mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-06 11:02:36 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
169fce294f | ||
|
|
526728ab85 | ||
|
|
1cdc065c93 | ||
|
|
24d16c2e94 | ||
|
|
97f6319e22 | ||
|
|
a27cadfc93 | ||
|
|
7343eb4a74 | ||
|
|
d904233d2f | ||
|
|
cf14cb3e29 | ||
|
|
ec76f03168 | ||
|
|
4bc9df9459 | ||
|
|
b0fd1cc45a | ||
|
|
c9878baa87 | ||
|
|
ad25b1afb9 | ||
|
|
69877ac4f2 | ||
|
|
251143f8fb | ||
|
|
0c2d71edba | ||
|
|
8a05c21e32 | ||
|
|
eacb14a10a | ||
|
|
59ba104e4a | ||
|
|
6a85aea5b1 | ||
|
|
dab4fe5bcd | ||
|
|
0743eba0c4 | ||
|
|
ba8008c870 | ||
|
|
ea8bb82fc7 | ||
|
|
9df78a94f1 | ||
|
|
00519187a6 | ||
|
|
d1c510baec | ||
|
|
e4f1e64c30 | ||
|
|
14fbb43f3e | ||
|
|
7ebde3da45 | ||
|
|
170dffac83 | ||
|
|
c16d5a4fda | ||
|
|
65487da1f5 | ||
|
|
48669be618 | ||
|
|
91e2c151d2 | ||
|
|
cf160b98e1 | ||
|
|
974458891c | ||
|
|
e3183eae77 | ||
|
|
8d2bbdd04f | ||
|
|
4fba83b4c2 | ||
|
|
ee79a28963 | ||
|
|
cbf38af705 | ||
|
|
3feee6db17 | ||
|
|
a9f8f1fe38 | ||
|
|
0288bdbc53 | ||
|
|
108e6b6354 | ||
|
|
21218316da | ||
|
|
bf6795aea0 | ||
|
|
87983d442c | ||
|
|
e5311a8ea4 | ||
|
|
78ee8564ad | ||
|
|
4a09d632c4 | ||
|
|
0a9a05ae12 | ||
|
|
c696f27432 | ||
|
|
95013df278 | ||
|
|
19210d5715 | ||
|
|
8944a3bf27 | ||
|
|
36963dc2ca | ||
|
|
c6ff4c0b70 | ||
|
|
4ee991b1e6 | ||
|
|
9425acacce | ||
|
|
f9a30e0a5a | ||
|
|
12f1137355 | ||
|
|
1d226018af | ||
|
|
431e8afba7 | ||
|
|
19076c95aa | ||
|
|
12a8be1d44 | ||
|
|
e18a4df62a | ||
|
|
d5f5d6579a | ||
|
|
1a6438cff5 | ||
|
|
2d37830e44 | ||
|
|
b0c43e7081 | ||
|
|
cdd8b09b9b | ||
|
|
e44948295e | ||
|
|
928dea0e32 | ||
|
|
4aa1a19db8 | ||
|
|
4db58bcfb2 | ||
|
|
5b748b9e68 | ||
|
|
acc9679cda | ||
|
|
ffe4906192 | ||
|
|
d76a8eeef7 | ||
|
|
1001bc01c9 | ||
|
|
2fb6d9337f | ||
|
|
ac956f2bea | ||
|
|
7189ea8fb7 | ||
|
|
3e6ee9f82e | ||
|
|
0426d4a4ee | ||
|
|
8e7b068ecc | ||
|
|
77b4bfe511 | ||
|
|
fdbebdf484 | ||
|
|
e4bdf9e0cb | ||
|
|
edfcce39da | ||
|
|
0a9f78d2c8 | ||
|
|
eccc47e81c | ||
|
|
a3066ee75c | ||
|
|
4926b33742 | ||
|
|
8ed680bdb0 | ||
|
|
b2e30bdb67 | ||
|
|
c22e619f7e | ||
|
|
48c0843e69 | ||
|
|
cc2a180d00 | ||
|
|
8f7b6c8339 | ||
|
|
6e0f62f2b6 | ||
|
|
5792b73fdc | ||
|
|
e628f59e87 | ||
|
|
c1a65a4de4 | ||
|
|
58660bf21a | ||
|
|
225abffd8f | ||
|
|
159ea4702c | ||
|
|
b8c01ed38a | ||
|
|
0bad2b4308 | ||
|
|
61e324422e | ||
|
|
bb0f781da0 | ||
|
|
81367a4616 | ||
|
|
30cd38c687 | ||
|
|
edb0b1fb7f | ||
|
|
fd2db79fa4 | ||
|
|
01298c8ff7 | ||
|
|
d7738666b0 | ||
|
|
736c6dc59f | ||
|
|
44ebc24dca | ||
|
|
601585bca4 | ||
|
|
55e99688cc | ||
|
|
30a5ed9c53 | ||
|
|
bdb7e544bd | ||
|
|
bd2645bc34 | ||
|
|
a727efca99 | ||
|
|
02418194d7 | ||
|
|
daab7603f6 | ||
|
|
f4db3e4119 | ||
|
|
81592d9ffa | ||
|
|
41ff125a8a | ||
|
|
1022090981 | ||
|
|
9057d0a079 | ||
|
|
fbac1b3f80 | ||
|
|
4d897e51df | ||
|
|
861b0d1a49 | ||
|
|
fd0d35d390 |
No files matched your search
+113
-32
@@ -62,6 +62,14 @@ commands:
|
||||
path: /tmp/test-results
|
||||
- store_artifacts: # store LOG for debugging if there's any
|
||||
path: LOG
|
||||
- run: # on fail, compress Test Logs for diagnosing the issue
|
||||
name: Compress Test Logs
|
||||
command: tar -cvzf t.tar.gz t
|
||||
when: on_fail
|
||||
- store_artifacts: # on fail, store Test Logs for diagnosing the issue
|
||||
path: t.tar.gz
|
||||
destination: test_logs
|
||||
when: on_fail
|
||||
|
||||
install-clang-10:
|
||||
steps:
|
||||
@@ -95,6 +103,13 @@ commands:
|
||||
git clone --single-branch --branch master --depth 1 https://github.com/google/gtest-parallel.git ~/gtest-parallel
|
||||
echo 'export PATH=$HOME/gtest-parallel:$PATH' >> $BASH_ENV
|
||||
|
||||
install-compression-libs:
|
||||
steps:
|
||||
- run:
|
||||
name: Install compression libs
|
||||
command: |
|
||||
sudo apt-get update -y && sudo apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev
|
||||
|
||||
executors:
|
||||
windows-2xlarge:
|
||||
machine:
|
||||
@@ -169,13 +184,13 @@ jobs:
|
||||
build-linux-release:
|
||||
machine:
|
||||
image: ubuntu-1604:202007-01
|
||||
resource_class: 2xlarge
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: make V=1 -j32 release | .circleci/cat_ignore_eagain
|
||||
- run: make V=1 -j8 release | .circleci/cat_ignore_eagain
|
||||
- run: if ./db_stress --version; then false; else true; fi # ensure without gflags
|
||||
- install-gflags
|
||||
- run: make V=1 -j32 release | .circleci/cat_ignore_eagain
|
||||
- run: make V=1 -j8 release | .circleci/cat_ignore_eagain
|
||||
- run: ./db_stress --version # ensure with gflags
|
||||
- post-steps
|
||||
|
||||
@@ -186,11 +201,11 @@ jobs:
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: make clean
|
||||
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j16 static_lib tools db_bench | .circleci/cat_ignore_eagain
|
||||
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j8 static_lib tools db_bench | .circleci/cat_ignore_eagain
|
||||
- run: if ./db_stress --version; then false; else true; fi # ensure without gflags
|
||||
- run: sudo apt-get update -y && sudo apt-get install -y libgflags-dev
|
||||
- run: make clean
|
||||
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j16 static_lib tools db_bench | .circleci/cat_ignore_eagain
|
||||
- run: USE_RTTI=1 DEBUG_LEVEL=0 make V=1 -j8 static_lib tools db_bench | .circleci/cat_ignore_eagain
|
||||
- run: ./db_stress --version # ensure with gflags
|
||||
|
||||
build-linux-lite:
|
||||
@@ -209,21 +224,21 @@ jobs:
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: LITE=1 make V=1 -j32 release | .circleci/cat_ignore_eagain
|
||||
- run: LITE=1 make V=1 -j8 release | .circleci/cat_ignore_eagain
|
||||
- run: if ./db_stress --version; then false; else true; fi # ensure without gflags
|
||||
- install-gflags
|
||||
- run: LITE=1 make V=1 -j32 release | .circleci/cat_ignore_eagain
|
||||
- run: LITE=1 make V=1 -j8 release | .circleci/cat_ignore_eagain
|
||||
- run: ./db_stress --version # ensure with gflags
|
||||
- post-steps
|
||||
|
||||
build-linux-clang-no-test:
|
||||
build-linux-clang-no_test_run:
|
||||
machine:
|
||||
image: ubuntu-1604:202007-01
|
||||
resource_class: 2xlarge
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: sudo apt-get update -y && sudo apt-get install -y clang libgflags-dev
|
||||
- run: CC=clang CXX=clang++ USE_CLANG=1 PORTABLE=1 make V=1 -j32 all | .circleci/cat_ignore_eagain
|
||||
- run: CC=clang CXX=clang++ USE_CLANG=1 PORTABLE=1 make V=1 -j16 all | .circleci/cat_ignore_eagain
|
||||
- post-steps
|
||||
|
||||
build-linux-clang10-asan:
|
||||
@@ -271,33 +286,63 @@ jobs:
|
||||
- run: CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 CLANG_ANALYZER="/usr/bin/clang++-10" CLANG_SCAN_BUILD=scan-build-10 USE_CLANG=1 make V=1 -j32 analyze | .circleci/cat_ignore_eagain # aligned new doesn't work for reason we haven't figured out. For unknown, reason passing "clang++-10" as CLANG_ANALYZER doesn't work, and we need a full path.
|
||||
- post-steps
|
||||
|
||||
build-linux-cmake:
|
||||
build-linux-cmake-no_test_run:
|
||||
machine:
|
||||
image: ubuntu-1604:202007-01
|
||||
resource_class: 2xlarge
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: (mkdir build && cd build && cmake -DWITH_GFLAGS=0 .. && make V=1 -j32) | .circleci/cat_ignore_eagain
|
||||
- run: (mkdir build && cd build && cmake -DWITH_GFLAGS=0 .. && make V=1 -j8) | .circleci/cat_ignore_eagain
|
||||
- post-steps
|
||||
|
||||
build-linux-unity:
|
||||
docker: # executor type
|
||||
- image: gcc:latest
|
||||
resource_class: xlarge
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: apt-get update -y && apt-get install -y libgflags-dev
|
||||
- run: TEST_TMPDIR=/dev/shm && make V=1 -j16 unity_test | .circleci/cat_ignore_eagain
|
||||
- run: TEST_TMPDIR=/dev/shm && make V=1 -j8 unity_test | .circleci/cat_ignore_eagain
|
||||
- post-steps
|
||||
|
||||
build-linux-gcc-4-8:
|
||||
build-linux-gcc-4_8-no_test_run:
|
||||
machine:
|
||||
image: ubuntu-1604:202007-01
|
||||
resource_class: large
|
||||
steps:
|
||||
- pre-steps
|
||||
- run: sudo apt-get update -y && sudo apt-get install gcc-4.8 g++-4.8 libgflags-dev
|
||||
- run: CC=gcc-4.8 CXX=g++-4.8 V=1 SKIP_LINK=1 make -j4 all | .circleci/cat_ignore_eagain # Linking broken because libgflags compiled with newer ABI
|
||||
- run: CC=gcc-4.8 CXX=g++-4.8 V=1 SKIP_LINK=1 make -j8 all | .circleci/cat_ignore_eagain # Linking broken because libgflags compiled with newer ABI
|
||||
- post-steps
|
||||
|
||||
build-linux-gcc-8-no_test_run:
|
||||
machine:
|
||||
image: ubuntu-2004:202010-01
|
||||
resource_class: large
|
||||
steps:
|
||||
- pre-steps
|
||||
- run: sudo apt-get update -y && sudo apt-get install gcc-8 g++-8 libgflags-dev
|
||||
- run: CC=gcc-8 CXX=g++-8 V=1 SKIP_LINK=1 make -j8 all | .circleci/cat_ignore_eagain # Linking broken because libgflags compiled with newer ABI
|
||||
- post-steps
|
||||
|
||||
build-linux-gcc-9-no_test_run:
|
||||
machine:
|
||||
image: ubuntu-2004:202010-01
|
||||
resource_class: large
|
||||
steps:
|
||||
- pre-steps
|
||||
- run: sudo apt-get update -y && sudo apt-get install gcc-9 g++-9 libgflags-dev
|
||||
- run: CC=gcc-9 CXX=g++-9 V=1 SKIP_LINK=1 make -j8 all | .circleci/cat_ignore_eagain # Linking broken because libgflags compiled with newer ABI
|
||||
- post-steps
|
||||
|
||||
build-linux-gcc-10-cxx20-no_test_run:
|
||||
machine:
|
||||
image: ubuntu-2004:202010-01
|
||||
resource_class: xlarge
|
||||
steps:
|
||||
- pre-steps
|
||||
- run: sudo apt-get update -y && sudo apt-get install gcc-10 g++-10 libgflags-dev
|
||||
- run: CC=gcc-10 CXX=g++-10 V=1 SKIP_LINK=1 ROCKSDB_CXX_STANDARD=c++20 make -j16 all | .circleci/cat_ignore_eagain # Linking broken because libgflags compiled with newer ABI
|
||||
- post-steps
|
||||
|
||||
build-windows:
|
||||
@@ -326,9 +371,13 @@ jobs:
|
||||
- run:
|
||||
name: "Setup VS"
|
||||
command: |
|
||||
if [[ "${VS_YEAR}" == "2017" ]]; then
|
||||
if [[ "${VS_YEAR}" == "2019" ]]; then
|
||||
echo "VS2019 already present."
|
||||
elif [[ "${VS_YEAR}" == "2017" ]]; then
|
||||
echo "Installing VS2017..."
|
||||
powershell .circleci/vs2017_install.ps1
|
||||
elif [[ "${VS_YEAR}" == "2015" ]]; then
|
||||
echo "Installing VS2015..."
|
||||
powershell .circleci/vs2015_install.ps1
|
||||
fi
|
||||
- run:
|
||||
@@ -354,6 +403,7 @@ jobs:
|
||||
cd build
|
||||
${CMAKE_BIN} -G "${CMAKE_GENERATOR}" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE=1 -DSNAPPY=1 -DJNI=1 << parameters.extra_cmake_opt >> ..
|
||||
cd ..
|
||||
echo "Building with VS version: ${CMAKE_GENERATOR}"
|
||||
msbuild.exe build/rocksdb.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
|
||||
- run:
|
||||
name: "Test RocksDB"
|
||||
@@ -522,7 +572,25 @@ jobs:
|
||||
gtest-parallel $(</tmp/test_list) --output_dir=/tmp | cat # pipe to cat to continuously output status on circleci UI. Otherwise, no status will be printed while the job is running.
|
||||
- post-steps
|
||||
|
||||
build-format-compatible:
|
||||
machine:
|
||||
image: ubuntu-1604:202007-01
|
||||
resource_class: 2xlarge
|
||||
steps:
|
||||
- pre-steps
|
||||
- install-gflags
|
||||
- install-compression-libs
|
||||
- run:
|
||||
name: "test"
|
||||
command: |
|
||||
export TEST_TMPDIR=/dev/shm/rocksdb
|
||||
rm -rf /dev/shm/rocksdb
|
||||
mkdir /dev/shm/rocksdb
|
||||
tools/check_format_compatible.sh
|
||||
- post-steps
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-linux:
|
||||
jobs:
|
||||
- build-linux
|
||||
@@ -547,9 +615,6 @@ workflows:
|
||||
build-linux-lite-release:
|
||||
jobs:
|
||||
- build-linux-lite-release
|
||||
build-linux-clang-no-test:
|
||||
jobs:
|
||||
- build-linux-clang-no-test
|
||||
build-linux-clang10-asan:
|
||||
jobs:
|
||||
- build-linux-clang10-asan
|
||||
@@ -562,29 +627,30 @@ workflows:
|
||||
build-linux-clang10-clang-analyze:
|
||||
jobs:
|
||||
- build-linux-clang10-clang-analyze
|
||||
build-linux-cmake:
|
||||
jobs:
|
||||
- build-linux-cmake
|
||||
build-linux-unity:
|
||||
jobs:
|
||||
- build-linux-unity
|
||||
build-windows:
|
||||
build-windows-vs2019:
|
||||
jobs:
|
||||
- build-windows
|
||||
- build-windows:
|
||||
name: "build-windows-vs2019"
|
||||
build-windows-vs2019-cxx20:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2019-cxx20"
|
||||
extra_cmake_opt: -DCMAKE_CXX_STANDARD=20
|
||||
build-windows-vs2017:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2017"
|
||||
vs_year: "2017"
|
||||
cmake_generator: "Visual Studio 15 Win64"
|
||||
build-windows-vs2015:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2015"
|
||||
vs_year: "2015"
|
||||
cmake_generator: "Visual Studio 14 Win64"
|
||||
build-windows-cxx20:
|
||||
jobs:
|
||||
- build-windows:
|
||||
extra_cmake_opt: -DCMAKE_CXX_STANDARD=20
|
||||
build-java:
|
||||
jobs:
|
||||
- build-linux-java
|
||||
@@ -608,9 +674,14 @@ workflows:
|
||||
- build-linux-non-shm:
|
||||
start_test: "statistics_test" # make sure unique in src.mk
|
||||
end_test: ""
|
||||
build-linux-gcc-4-8:
|
||||
build-linux-compilers-no_test_run:
|
||||
jobs:
|
||||
- build-linux-gcc-4-8
|
||||
- build-linux-clang-no_test_run
|
||||
- build-linux-cmake-no_test_run
|
||||
- build-linux-gcc-4_8-no_test_run
|
||||
- build-linux-gcc-8-no_test_run
|
||||
- build-linux-gcc-9-no_test_run
|
||||
- build-linux-gcc-10-cxx20-no_test_run
|
||||
build-macos:
|
||||
jobs:
|
||||
- build-macos
|
||||
@@ -620,3 +691,13 @@ workflows:
|
||||
build-cmake-mingw:
|
||||
jobs:
|
||||
- build-cmake-mingw
|
||||
nightly:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
jobs:
|
||||
- build-format-compatible
|
||||
@@ -21,3 +21,4 @@ if (($exitCode -ne 0) -and ($exitCode -ne 3010)) {
|
||||
Copy-Item -Path "C:\Users\circleci\AppData\Local\Temp\vslogs.zip" -Destination "C:\w\build-results\"
|
||||
exit 1
|
||||
}
|
||||
echo "VS 2015 installed."
|
||||
@@ -32,3 +32,4 @@ if (($exitCode -ne 0) -and ($exitCode -ne 3010)) {
|
||||
Copy-Item -Path "C:\Users\circleci\AppData\Local\Temp\vslogs.zip" -Destination "C:\w\build-results\"
|
||||
exit 1
|
||||
}
|
||||
echo "VS 2017 installed."
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Download clang-format-diff.py
|
||||
uses: wei/wget@v1
|
||||
with:
|
||||
args: https://raw.githubusercontent.com/llvm/llvm-project/master/clang/tools/clang-format/clang-format-diff.py
|
||||
args: https://raw.githubusercontent.com/llvm/llvm-project/main/clang/tools/clang-format/clang-format-diff.py
|
||||
|
||||
- name: Check format
|
||||
run: VERBOSE_CHECK=1 make check-format
|
||||
|
||||
@@ -93,3 +93,5 @@ clang-format-diff.py
|
||||
|
||||
fuzz/proto/gen/
|
||||
fuzz/crash-*
|
||||
|
||||
cmake-build-*
|
||||
+12
-92
@@ -2,20 +2,18 @@ dist: xenial
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
osx_image: xcode9.4
|
||||
cache:
|
||||
- ccache
|
||||
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
@@ -26,15 +24,6 @@ addons:
|
||||
- liblzma-dev # xv
|
||||
- libzstd-dev
|
||||
- zlib1g-dev
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- ccache
|
||||
- gflags
|
||||
- lz4
|
||||
- snappy
|
||||
- xz
|
||||
- zstd
|
||||
|
||||
env:
|
||||
- TEST_GROUP=platform_dependent # 16-18 minutes
|
||||
@@ -58,20 +47,6 @@ env:
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc9
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc9-c++20
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os: osx
|
||||
env: JOB_NAME=make-gcc4.8
|
||||
- os: osx
|
||||
arch: ppc64le
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=cmake-mingw
|
||||
@@ -86,36 +61,6 @@ matrix:
|
||||
env: JOB_NAME=make-gcc4.8
|
||||
- os: linux
|
||||
compiler: clang
|
||||
# Exclude all but most unique cmake variants for pull requests, but build all in branches
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: amd64
|
||||
env: JOB_NAME=cmake
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: amd64
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: amd64
|
||||
env: JOB_NAME=cmake-gcc9
|
||||
# Exclude most osx, arm64 and ppc64le tests for pull requests, but build in branches
|
||||
# Temporarily disable ppc64le cmake test while snapd is broken
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake
|
||||
# Exclude all osx since it should be covered by CircleCI
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=platform_dependent
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: JOB_NAME=cmake
|
||||
# NB: the cmake build is a partial java test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=1
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -124,9 +69,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=1
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=2
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -135,9 +77,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=2
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=3
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -146,9 +85,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=3
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=4
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -157,9 +93,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=4
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/ AND commit_message !~ /java/
|
||||
os : osx
|
||||
env: JOB_NAME=java_test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/ AND commit_message !~ /java/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -168,9 +101,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=java_test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : osx
|
||||
env: JOB_NAME=lite_build
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -179,9 +109,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=lite_build
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : osx
|
||||
env: JOB_NAME=examples
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -214,9 +141,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-gcc9-c++20
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : osx
|
||||
env: JOB_NAME=status_checked
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -227,9 +151,6 @@ matrix:
|
||||
env: JOB_NAME=status_checked
|
||||
|
||||
install:
|
||||
- if [ "${TRAVIS_OS_NAME}" == osx ]; then
|
||||
PATH=$PATH:/usr/local/opt/ccache/libexec;
|
||||
fi
|
||||
- if [ "${JOB_NAME}" == cmake-gcc8 ]; then
|
||||
sudo apt-get install -y g++-8 || exit $?;
|
||||
CC=gcc-8 && CXX=g++-8;
|
||||
@@ -245,22 +166,21 @@ install:
|
||||
sudo apt-get install -y g++-4.8 || exit $?;
|
||||
CC=gcc-4.8 && CXX=g++-4.8;
|
||||
fi
|
||||
- if [[ "${JOB_NAME}" == cmake* ]] && [ "${TRAVIS_OS_NAME}" == linux ]; then
|
||||
sudo apt-get install snapd && sudo snap install cmake --beta --classic || exit $?;
|
||||
export PATH=/snap/bin:$PATH;
|
||||
- |
|
||||
if [[ "${JOB_NAME}" == cmake* ]]; then
|
||||
sudo apt-get remove -y cmake cmake-data
|
||||
export CMAKE_DEB="cmake-3.14.5-Linux-$(uname -m).deb"
|
||||
export CMAKE_DEB_URL="https://rocksdb-deps.s3-us-west-2.amazonaws.com/cmake/${CMAKE_DEB}"
|
||||
curl --silent --fail --show-error --location --output "${CMAKE_DEB}" "${CMAKE_DEB_URL}" || exit $?
|
||||
sudo dpkg -i "${CMAKE_DEB}" || exit $?
|
||||
which cmake && cmake --version
|
||||
fi
|
||||
- |
|
||||
if [[ "${JOB_NAME}" == java_test || "${JOB_NAME}" == cmake* ]]; then
|
||||
# Ensure JDK 8
|
||||
if [ "${TRAVIS_OS_NAME}" == osx ]; then
|
||||
brew tap AdoptOpenJDK/openjdk || exit $?
|
||||
brew cask install adoptopenjdk8 || exit $?
|
||||
export JAVA_HOME=$(/usr/libexec/java_home)
|
||||
else
|
||||
sudo apt-get install -y openjdk-8-jdk || exit $?
|
||||
export PATH=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)/bin:$PATH
|
||||
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)
|
||||
fi
|
||||
sudo apt-get install -y openjdk-8-jdk || exit $?
|
||||
export PATH=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)/bin:$PATH
|
||||
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
|
||||
+24
-25
@@ -170,23 +170,25 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(TIMESTAMP TS "%Y/%m/%d %H:%M:%S" UTC)
|
||||
set(GIT_DATE_TIME "${TS}" CACHE STRING "the time we first built rocksdb")
|
||||
string(TIMESTAMP TS "%Y-%m-%d %H:%M:%S" UTC)
|
||||
set(BUILD_DATE "${TS}" CACHE STRING "the time we first built rocksdb")
|
||||
|
||||
find_package(Git)
|
||||
|
||||
if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git")
|
||||
if(WIN32)
|
||||
execute_process(COMMAND $ENV{COMSPEC} /C ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} rev-parse HEAD OUTPUT_VARIABLE GIT_SHA)
|
||||
else()
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_CURRENT_SOURCE_DIR} rev-parse HEAD OUTPUT_VARIABLE GIT_SHA)
|
||||
execute_process(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE GIT_SHA COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD )
|
||||
execute_process(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE GIT_MOD COMMAND "${GIT_EXECUTABLE}" diff-index HEAD --quiet)
|
||||
execute_process(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE GIT_DATE COMMAND "${GIT_EXECUTABLE}" log -1 --date=format:"%Y-%m-%d %T" --format="%ad")
|
||||
execute_process(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE GIT_TAG RESULT_VARIABLE rv COMMAND "${GIT_EXECUTABLE}" symbolic-ref -q --short HEAD OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (rv AND NOT rv EQUAL 0)
|
||||
execute_process(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE GIT_TAG COMMAND "${GIT_EXECUTABLE}" describe --tags --exact-match OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
else()
|
||||
set(GIT_SHA 0)
|
||||
set(GIT_MOD 1)
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE "[^0-9a-f]+" "" GIT_SHA "${GIT_SHA}")
|
||||
|
||||
string(REGEX REPLACE "[^0-9a-fA-F]+" "" GIT_SHA "${GIT_SHA}")
|
||||
string(REGEX REPLACE "[^0-9: /-]+" "" GIT_DATE "${GIT_DATE}")
|
||||
|
||||
option(WITH_MD_LIBRARY "build with MD" ON)
|
||||
if(WIN32 AND MSVC)
|
||||
@@ -199,9 +201,7 @@ endif()
|
||||
|
||||
set(BUILD_VERSION_CC ${CMAKE_BINARY_DIR}/build_version.cc)
|
||||
configure_file(util/build_version.cc.in ${BUILD_VERSION_CC} @ONLY)
|
||||
add_library(build_version OBJECT ${BUILD_VERSION_CC})
|
||||
target_include_directories(build_version PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util)
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /EHsc /GS /Gd /GR /GF /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W4 /wd4127 /wd4800 /wd4996 /wd4351 /wd4100 /wd4204 /wd4324")
|
||||
@@ -243,14 +243,14 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
endif(HAS_ALTIVEC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64|AARCH64")
|
||||
CHECK_C_COMPILER_FLAG("-march=armv8-a+crc+crypto" HAS_ARMV8_CRC)
|
||||
if(HAS_ARMV8_CRC)
|
||||
message(STATUS " HAS_ARMV8_CRC yes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a+crc+crypto -Wno-unused-function")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a+crc+crypto -Wno-unused-function")
|
||||
endif(HAS_ARMV8_CRC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64|AARCH64")
|
||||
|
||||
option(PORTABLE "build a portable binary" OFF)
|
||||
option(FORCE_SSE42 "force building with SSE4.2, even when PORTABLE=ON" OFF)
|
||||
@@ -466,11 +466,6 @@ if(CMAKE_SYSTEM_NAME MATCHES "Cygwin")
|
||||
add_definitions(-fno-builtin-memcmp -DCYGWIN)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
add_definitions(-DOS_MACOSX)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES arm)
|
||||
add_definitions(-DIOS_CROSS_COMPILE -DROCKSDB_LITE)
|
||||
# no debug info for IOS, that will make our library big
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_definitions(-DOS_LINUX)
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "SunOS")
|
||||
@@ -814,6 +809,8 @@ set(SOURCES
|
||||
utilities/transactions/lock/lock_manager.cc
|
||||
utilities/transactions/lock/point/point_lock_tracker.cc
|
||||
utilities/transactions/lock/point/point_lock_manager.cc
|
||||
utilities/transactions/lock/range/range_tree/range_tree_lock_manager.cc
|
||||
utilities/transactions/lock/range/range_tree/range_tree_lock_tracker.cc
|
||||
utilities/transactions/optimistic_transaction_db_impl.cc
|
||||
utilities/transactions/optimistic_transaction.cc
|
||||
utilities/transactions/pessimistic_transaction.cc
|
||||
@@ -828,10 +825,9 @@ set(SOURCES
|
||||
utilities/transactions/write_unprepared_txn_db.cc
|
||||
utilities/ttl/db_ttl_impl.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index_internal.cc
|
||||
$<TARGET_OBJECTS:build_version>)
|
||||
utilities/write_batch_with_index/write_batch_with_index_internal.cc)
|
||||
|
||||
list(APPEND SOURCE
|
||||
list(APPEND SOURCES
|
||||
utilities/transactions/lock/range/range_tree/lib/locktree/concurrent_tree.cc
|
||||
utilities/transactions/lock/range/range_tree/lib/locktree/keyrange.cc
|
||||
utilities/transactions/lock/range/range_tree/lib/locktree/lock_request.cc
|
||||
@@ -920,12 +916,12 @@ else()
|
||||
set(SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
add_library(${ROCKSDB_STATIC_LIB} STATIC ${SOURCES})
|
||||
add_library(${ROCKSDB_STATIC_LIB} STATIC ${SOURCES} ${BUILD_VERSION_CC})
|
||||
target_link_libraries(${ROCKSDB_STATIC_LIB} PRIVATE
|
||||
${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
|
||||
if(ROCKSDB_BUILD_SHARED)
|
||||
add_library(${ROCKSDB_SHARED_LIB} SHARED ${SOURCES})
|
||||
add_library(${ROCKSDB_SHARED_LIB} SHARED ${SOURCES} ${BUILD_VERSION_CC})
|
||||
target_link_libraries(${ROCKSDB_SHARED_LIB} PRIVATE
|
||||
${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
|
||||
@@ -943,7 +939,7 @@ if(ROCKSDB_BUILD_SHARED)
|
||||
LINKER_LANGUAGE CXX
|
||||
VERSION ${rocksdb_VERSION}
|
||||
SOVERSION ${rocksdb_VERSION_MAJOR}
|
||||
OUTPUT_NAME "rocksdb")
|
||||
OUTPUT_NAME "rocksdb${ARTIFACT_SUFFIX}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1086,6 +1082,7 @@ if(WITH_TESTS)
|
||||
db/db_iter_test.cc
|
||||
db/db_iter_stress_test.cc
|
||||
db/db_iterator_test.cc
|
||||
db/db_kv_checksum_test.cc
|
||||
db/db_log_iter_test.cc
|
||||
db/db_memtable_test.cc
|
||||
db/db_merge_operator_test.cc
|
||||
@@ -1174,6 +1171,7 @@ if(WITH_TESTS)
|
||||
table/table_test.cc
|
||||
table/block_fetcher_test.cc
|
||||
test_util/testutil_test.cc
|
||||
trace_replay/block_cache_tracer_test.cc
|
||||
trace_replay/io_tracer_test.cc
|
||||
tools/block_cache_analyzer/block_cache_trace_analyzer_test.cc
|
||||
tools/io_tracer_parser_test.cc
|
||||
@@ -1224,6 +1222,7 @@ if(WITH_TESTS)
|
||||
utilities/transactions/lock/point/point_lock_manager_test.cc
|
||||
utilities/transactions/write_prepared_transaction_test.cc
|
||||
utilities/transactions/write_unprepared_transaction_test.cc
|
||||
utilities/transactions/lock/range/range_locking_test.cc
|
||||
utilities/ttl/ttl_test.cc
|
||||
utilities/write_batch_with_index/write_batch_with_index_test.cc
|
||||
)
|
||||
|
||||
+44
-1
@@ -1,4 +1,42 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
|
||||
## 6.18.0 (02/19/2021)
|
||||
### Behavior Changes
|
||||
* When retryable IO error occurs during compaction, it is mapped to soft error and set the BG error. However, auto resume is not called to clean the soft error since compaction will reschedule by itself. In this change, When retryable IO error occurs during compaction, BG error is not set. User will be informed the error via EventHelper.
|
||||
* Introduce a new trace file format for query tracing and replay and trace file version is bump up to 0.2. A payload map is added as the first portion of the payload. We will not have backward compatible issues when adding new entries to trace records. Added the iterator_upper_bound and iterator_lower_bound in Seek and SeekForPrev tracing function. Added them as the new payload member for iterator tracing.
|
||||
|
||||
### New Features
|
||||
* Add support for key-value integrity protection in live updates from the user buffers provided to `WriteBatch` through the write to RocksDB's in-memory update buffer (memtable). This is intended to detect some cases of in-memory data corruption, due to either software or hardware errors. Users can enable protection by constructing their `WriteBatch` with `protection_bytes_per_key == 8`.
|
||||
* Add support for updating `full_history_ts_low` option in manual compaction, which is for old timestamp data GC.
|
||||
* Add a mechanism for using Makefile to build external plugin code into the RocksDB libraries/binaries. This intends to simplify compatibility and distribution for plugins (e.g., special-purpose `FileSystem`s) whose source code resides outside the RocksDB repo. See "plugin/README.md" for developer details, and "PLUGINS.md" for a listing of available plugins.
|
||||
* Added memory pre-fetching for experimental Ribbon filter, which especially optimizes performance with batched MultiGet.
|
||||
* A new, experimental version of BlobDB (key-value separation) is now available. The new implementation is integrated into the RocksDB core, i.e. it is accessible via the usual `rocksdb::DB` API, as opposed to the separate `rocksdb::blob_db::BlobDB` interface used by the earlier version, and can be configured on a per-column family basis using the configuration options `enable_blob_files`, `min_blob_size`, `blob_file_size`, `blob_compression_type`, `enable_blob_garbage_collection`, and `blob_garbage_collection_age_cutoff`. It extends RocksDB's consistency guarantees to blobs, and offers more features and better performance. Note that some features, most notably `Merge`, compaction filters, and backup/restore are not yet supported, and there is no support for migrating a database created by the old implementation.
|
||||
|
||||
### Bug Fixes
|
||||
* Since 6.15.0, `TransactionDB` returns error `Status`es from calls to `DeleteRange()` and calls to `Write()` where the `WriteBatch` contains a range deletion. Previously such operations may have succeeded while not providing the expected transactional guarantees. There are certain cases where range deletion can still be used on such DBs; see the API doc on `TransactionDB::DeleteRange()` for details.
|
||||
* `OptimisticTransactionDB` now returns error `Status`es from calls to `DeleteRange()` and calls to `Write()` where the `WriteBatch` contains a range deletion. Previously such operations may have succeeded while not providing the expected transactional guarantees.
|
||||
* Fix `WRITE_PREPARED`, `WRITE_UNPREPARED` TransactionDB `MultiGet()` may return uncommitted data with snapshot.
|
||||
* In DB::OpenForReadOnly, if any error happens while checking Manifest file path, it was overridden by Status::NotFound. It has been fixed and now actual error is returned.
|
||||
|
||||
### Public API Change
|
||||
* Added a "only_mutable_options" flag to the ConfigOptions. When this flag is "true", the Configurable functions and convenience methods (such as GetDBOptionsFromString) will only deal with options that are marked as mutable. When this flag is true, only options marked as mutable can be configured (a Status::InvalidArgument will be returned) and options not marked as mutable will not be returned or compared. The default is "false", meaning to compare all options.
|
||||
* Add new Append and PositionedAppend APIs to FileSystem to bring the data verification information (data checksum information) from upper layer (e.g., WritableFileWriter) to the storage layer. In this way, the customized FileSystem is able to verify the correctness of data being written to the storage on time. Add checksum_handoff_file_types to DBOptions. User can use this option to control which file types (Currently supported file tyes: kWALFile, kTableFile, kDescriptorFile.) should use the new Append and PositionedAppend APIs to handoff the verification information. Currently, RocksDB only use crc32c to calculate the checksum for write handoff.
|
||||
* Add an option, `CompressionOptions::max_dict_buffer_bytes`, to limit the in-memory buffering for selecting samples for generating/training a dictionary. The limit is currently loosely adhered to.
|
||||
|
||||
## 6.17.0 (01/15/2021)
|
||||
### Behavior Changes
|
||||
* When verifying full file checksum with `DB::VerifyFileChecksums()`, we now fail with `Status::InvalidArgument` if the name of the checksum generator used for verification does not match the name of the checksum generator used for protecting the file when it was created.
|
||||
* Since RocksDB does not continue write the same file if a file write fails for any reason, the file scope write IO error is treated the same as retryable IO error. More information about error handling of file scope IO error is included in `ErrorHandler::SetBGError`.
|
||||
|
||||
### Bug Fixes
|
||||
* Version older than 6.15 cannot decode VersionEdits `WalAddition` and `WalDeletion`, fixed this by changing the encoded format of them to be ignorable by older versions.
|
||||
* Fix a race condition between DB startups and shutdowns in managing the periodic background worker threads. One effect of this race condition could be the process being terminated.
|
||||
|
||||
### Public API Change
|
||||
* Add a public API WriteBufferManager::dummy_entries_in_cache_usage() which reports the size of dummy entries stored in cache (passed to WriteBufferManager). Dummy entries are used to account for DataBlocks.
|
||||
* Add a public API GetRocksBuildProperties and GetRocksBuildInfoAsString to get properties about the current build. These properties may include settings related to the GIT settings (branch, timestamp). This change also sets the "build date" based on the GIT properties, rather than the actual build time, thereby enabling more reproducible builds.
|
||||
|
||||
## 6.16.0 (12/18/2020)
|
||||
### Behavior Changes
|
||||
* Attempting to write a merge operand without explicitly configuring `merge_operator` now fails immediately, causing the DB to enter read-only mode. Previously, failure was deferred until the `merge_operator` was needed by a user read or a background operation.
|
||||
@@ -10,6 +48,8 @@
|
||||
* Fixed the logic of populating native data structure for `read_amp_bytes_per_bit` during OPTIONS file parsing on big-endian architecture. Without this fix, original code introduced in PR7659, when running on big-endian machine, can mistakenly store read_amp_bytes_per_bit (an uint32) in little endian format. Future access to `read_amp_bytes_per_bit` will give wrong values. Little endian architecture is not affected.
|
||||
* Fixed prefix extractor with timestamp issues.
|
||||
* Fixed a bug in atomic flush: in two-phase commit mode, the minimum WAL log number to keep is incorrect.
|
||||
* Fixed a bug related to checkpoint in PR7789: if there are multiple column families, and the checkpoint is not opened as read only, then in rare cases, data loss may happen in the checkpoint. Since backup engine relies on checkpoint, it may also be affected.
|
||||
* When ldb --try_load_options is used with the --column_family option, the ColumnFamilyOptions for the specified column family was not loaded from the OPTIONS file. Fix it so its loaded from OPTIONS and then overridden with command line overrides.
|
||||
|
||||
### New Features
|
||||
* User defined timestamp feature supports `CompactRange` and `GetApproximateSizes`.
|
||||
@@ -18,6 +58,10 @@
|
||||
|
||||
### Public API Change
|
||||
* Deprecated public but rarely-used FilterBitsBuilder::CalculateNumEntry, which is replaced with ApproximateNumEntries taking a size_t parameter and returning size_t.
|
||||
* To improve portability the functions `Env::GetChildren` and `Env::GetChildrenFileAttributes` will no longer return entries for the special directories `.` or `..`.
|
||||
* Added a new option `track_and_verify_wals_in_manifest`. If `true`, the log numbers and sizes of the synced WALs are tracked in MANIFEST, then during DB recovery, if a synced WAL is missing from disk, or the WAL's size does not match the recorded size in MANIFEST, an error will be reported and the recovery will be aborted. Note that this option does not work with secondary instance.
|
||||
* `rocksdb_approximate_sizes` and `rocksdb_approximate_sizes_cf` in the C API now requires an error pointer (`char** errptr`) for receiving any error.
|
||||
* All overloads of DB::GetApproximateSizes now return Status, so that any failure to obtain the sizes is indicated to the caller.
|
||||
|
||||
## 6.15.0 (11/13/2020)
|
||||
### Bug Fixes
|
||||
@@ -39,7 +83,6 @@
|
||||
### Public API Change
|
||||
* Deprecate `BlockBasedTableOptions::pin_l0_filter_and_index_blocks_in_cache` and `BlockBasedTableOptions::pin_top_level_index_and_filter`. These options still take effect until users migrate to the replacement APIs in `BlockBasedTableOptions::metadata_cache_options`. Migration guidance can be found in the API comments on the deprecated options.
|
||||
* Add new API `DB::VerifyFileChecksums` to verify SST file checksum with corresponding entries in the MANIFEST if present. Current implementation requires scanning and recomputing file checksums.
|
||||
* Added a new option `track_and_verify_wals_in_manifest`. If `true`, the log numbers and sizes of the synced WALs are tracked in MANIFEST, then during DB recovery, if a synced WAL is missing from disk, or the WAL's size does not match the recorded size in MANIFEST, an error will be reported and the recovery will be aborted. Note that this option does not work with secondary instance.
|
||||
|
||||
### Behavior Changes
|
||||
* The dictionary compression settings specified in `ColumnFamilyOptions::compression_opts` now additionally affect files generated by flush and compaction to non-bottommost level. Previously those settings at most affected files generated by compaction to bottommost level, depending on whether `ColumnFamilyOptions::bottommost_compression_opts` overrode them. Users who relied on dictionary compression settings in `ColumnFamilyOptions::compression_opts` affecting only the bottommost level can keep the behavior by moving their dictionary settings to `ColumnFamilyOptions::bottommost_compression_opts` and setting its `enabled` flag.
|
||||
|
||||
@@ -190,6 +190,11 @@ else
|
||||
endif
|
||||
|
||||
ifdef ASSERT_STATUS_CHECKED
|
||||
# For ASC, turn off constructor elision, preventing the case where a constructor returned
|
||||
# by a method may pass the ASC check if the status is checked in the inner method. Forcing
|
||||
# the copy constructor to be invoked disables the optimization and will cause the calling method
|
||||
# to check the status in order to prevent an error from being raised.
|
||||
PLATFORM_CXXFLAGS += -fno-elide-constructors
|
||||
ifeq ($(filter -DROCKSDB_ASSERT_STATUS_CHECKED,$(OPT)),)
|
||||
OPT += -DROCKSDB_ASSERT_STATUS_CHECKED
|
||||
endif
|
||||
@@ -264,6 +269,12 @@ dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; \
|
||||
# this file is generated by the previous line to set build flags and sources
|
||||
include make_config.mk
|
||||
|
||||
ROCKSDB_PLUGIN_MKS = $(foreach plugin, $(ROCKSDB_PLUGINS), plugin/$(plugin)/*.mk)
|
||||
include $(ROCKSDB_PLUGIN_MKS)
|
||||
ROCKSDB_PLUGIN_SOURCES = $(foreach plugin, $(ROCKSDB_PLUGINS), $(foreach source, $($(plugin)_SOURCES), plugin/$(plugin)/$(source)))
|
||||
ROCKSDB_PLUGIN_HEADERS = $(foreach plugin, $(ROCKSDB_PLUGINS), $(foreach header, $($(plugin)_HEADERS), plugin/$(plugin)/$(header)))
|
||||
PLATFORM_LDFLAGS += $(foreach plugin, $(ROCKSDB_PLUGINS), $($(plugin)_LDFLAGS))
|
||||
|
||||
export JAVAC_ARGS
|
||||
CLEAN_FILES += make_config.mk rocksdb.pc
|
||||
|
||||
@@ -474,33 +485,9 @@ CXXFLAGS += $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) -Woverl
|
||||
|
||||
LDFLAGS += $(PLATFORM_LDFLAGS)
|
||||
|
||||
# If NO_UPDATE_BUILD_VERSION is set we don't update util/build_version.cc, but
|
||||
# the file needs to already exist or else the build will fail
|
||||
ifndef NO_UPDATE_BUILD_VERSION
|
||||
date := $(shell date +%F)
|
||||
ifdef FORCE_GIT_SHA
|
||||
git_sha := $(FORCE_GIT_SHA)
|
||||
else
|
||||
git_sha := $(shell git rev-parse HEAD 2>/dev/null)
|
||||
endif
|
||||
gen_build_version = sed -e s/@@GIT_SHA@@/$(git_sha)/ -e s/@@GIT_DATE_TIME@@/$(date)/ util/build_version.cc.in
|
||||
|
||||
# Record the version of the source that we are compiling.
|
||||
# We keep a record of the git revision in this file. It is then built
|
||||
# as a regular source file as part of the compilation process.
|
||||
# One can run "strings executable_filename | grep _build_" to find
|
||||
# the version of the source that we used to build the executable file.
|
||||
FORCE:
|
||||
util/build_version.cc: FORCE
|
||||
$(AM_V_GEN)rm -f $@-t
|
||||
$(AM_V_at)$(gen_build_version) > $@-t
|
||||
$(AM_V_at)if test -f $@; then \
|
||||
cmp -s $@-t $@ && rm -f $@-t || mv -f $@-t $@; \
|
||||
else mv -f $@-t $@; fi
|
||||
endif
|
||||
|
||||
OBJ_DIR?=.
|
||||
LIB_OBJECTS = $(patsubst %.cc, $(OBJ_DIR)/%.o, $(LIB_SOURCES))
|
||||
LIB_OBJECTS += $(patsubst %.cc, $(OBJ_DIR)/%.o, $(ROCKSDB_PLUGIN_SOURCES))
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
LIB_OBJECTS += $(patsubst %.c, $(OBJ_DIR)/%.o, $(LIB_SOURCES_C))
|
||||
LIB_OBJECTS += $(patsubst %.S, $(OBJ_DIR)/%.o, $(LIB_SOURCES_ASM))
|
||||
@@ -510,6 +497,12 @@ ifeq ($(USE_FOLLY_DISTRIBUTED_MUTEX),1)
|
||||
LIB_OBJECTS += $(patsubst %.cpp, $(OBJ_DIR)/%.o, $(FOLLY_SOURCES))
|
||||
endif
|
||||
|
||||
# range_tree is not compatible with non GNU libc on ppc64
|
||||
# see https://jira.percona.com/browse/PS-7559
|
||||
ifneq ($(PPC_LIBC_IS_GNU),0)
|
||||
LIB_OBJECTS += $(patsubst %.cc, $(OBJ_DIR)/%.o, $(RANGE_TREE_SOURCES))
|
||||
endif
|
||||
|
||||
GTEST = $(OBJ_DIR)/$(GTEST_DIR)/gtest/gtest-all.o
|
||||
TESTUTIL = $(OBJ_DIR)/test_util/testutil.o
|
||||
TESTHARNESS = $(OBJ_DIR)/test_util/testharness.o $(TESTUTIL) $(GTEST)
|
||||
@@ -558,6 +551,7 @@ PARALLEL_TEST = \
|
||||
table_test \
|
||||
transaction_test \
|
||||
point_lock_manager_test \
|
||||
range_locking_test \
|
||||
write_prepared_transaction_test \
|
||||
write_unprepared_transaction_test \
|
||||
|
||||
@@ -586,6 +580,7 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
blob_file_reader_test \
|
||||
bloom_test \
|
||||
cassandra_format_test \
|
||||
cassandra_functional_test \
|
||||
cassandra_row_merge_test \
|
||||
cassandra_serialize_test \
|
||||
cleanable_test \
|
||||
@@ -594,11 +589,25 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
crc32c_test \
|
||||
dbformat_test \
|
||||
db_basic_test \
|
||||
compact_files_test \
|
||||
compaction_picker_test \
|
||||
comparator_db_test \
|
||||
db_encryption_test \
|
||||
db_iter_test \
|
||||
db_iter_stress_test \
|
||||
db_log_iter_test \
|
||||
db_bloom_filter_test \
|
||||
db_blob_basic_test \
|
||||
db_blob_index_test \
|
||||
db_block_cache_test \
|
||||
db_compaction_test \
|
||||
db_compaction_filter_test \
|
||||
db_dynamic_level_test \
|
||||
db_flush_test \
|
||||
db_inplace_update_test \
|
||||
db_io_failure_test \
|
||||
db_iterator_test \
|
||||
db_kv_checksum_test \
|
||||
db_logical_block_size_cache_test \
|
||||
db_memtable_test \
|
||||
db_merge_operand_test \
|
||||
@@ -606,10 +615,28 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
db_wal_test \
|
||||
db_with_timestamp_basic_test \
|
||||
db_with_timestamp_compaction_test \
|
||||
db_write_test \
|
||||
db_options_test \
|
||||
db_properties_test \
|
||||
db_range_del_test \
|
||||
db_secondary_test \
|
||||
deletefile_test \
|
||||
external_sst_file_test \
|
||||
options_file_test \
|
||||
db_sst_test \
|
||||
db_statistics_test \
|
||||
db_table_properties_test \
|
||||
db_tailing_iter_test \
|
||||
fault_injection_test \
|
||||
listener_test \
|
||||
log_test \
|
||||
manual_compaction_test \
|
||||
obsolete_files_test \
|
||||
perf_context_test \
|
||||
periodic_work_scheduler_test \
|
||||
perf_context_test \
|
||||
version_set_test \
|
||||
wal_manager_test \
|
||||
defer_test \
|
||||
filename_test \
|
||||
dynamic_bloom_test \
|
||||
@@ -621,6 +648,7 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
external_sst_file_basic_test \
|
||||
auto_roll_logger_test \
|
||||
file_indexer_test \
|
||||
delete_scheduler_test \
|
||||
flush_job_test \
|
||||
hash_table_test \
|
||||
hash_test \
|
||||
@@ -631,6 +659,7 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
iostats_context_test \
|
||||
ldb_cmd_test \
|
||||
memkind_kmem_allocator_test \
|
||||
merge_test \
|
||||
merger_test \
|
||||
mock_env_test \
|
||||
object_registry_test \
|
||||
@@ -643,6 +672,7 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
options_settable_test \
|
||||
options_test \
|
||||
point_lock_manager_test \
|
||||
random_access_file_reader_test \
|
||||
random_test \
|
||||
range_del_aggregator_test \
|
||||
sst_file_reader_test \
|
||||
@@ -651,9 +681,11 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
ribbon_test \
|
||||
skiplist_test \
|
||||
slice_test \
|
||||
slice_transform_test \
|
||||
sst_dump_test \
|
||||
statistics_test \
|
||||
stats_history_test \
|
||||
stringappend_test \
|
||||
thread_local_test \
|
||||
trace_analyzer_test \
|
||||
transaction_test \
|
||||
@@ -671,27 +703,43 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
version_builder_test \
|
||||
version_edit_test \
|
||||
work_queue_test \
|
||||
write_buffer_manager_test \
|
||||
write_controller_test \
|
||||
write_prepared_transaction_test \
|
||||
write_unprepared_transaction_test \
|
||||
compaction_iterator_test \
|
||||
compaction_job_test \
|
||||
compaction_job_stats_test \
|
||||
io_tracer_test \
|
||||
io_tracer_test \
|
||||
io_tracer_parser_test \
|
||||
prefetch_test \
|
||||
merge_helper_test \
|
||||
memtable_list_test \
|
||||
flush_job_test \
|
||||
block_based_filter_block_test \
|
||||
block_fetcher_test \
|
||||
block_test \
|
||||
data_block_hash_index_test \
|
||||
full_filter_block_test \
|
||||
partitioned_filter_block_test \
|
||||
column_family_test \
|
||||
file_reader_writer_test \
|
||||
rate_limiter_test \
|
||||
corruption_test \
|
||||
reduce_levels_test \
|
||||
thread_list_test \
|
||||
compact_on_deletion_collector_test \
|
||||
db_universal_compaction_test \
|
||||
import_column_family_test \
|
||||
option_change_migration_test \
|
||||
cuckoo_table_builder_test \
|
||||
cuckoo_table_db_test \
|
||||
cuckoo_table_reader_test \
|
||||
memory_test \
|
||||
table_test \
|
||||
backupable_db_test \
|
||||
blob_db_test \
|
||||
ttl_test \
|
||||
write_batch_test \
|
||||
write_batch_with_index_test \
|
||||
|
||||
@@ -804,6 +852,37 @@ ROCKSDB_MAJOR = $(shell egrep "ROCKSDB_MAJOR.[0-9]" include/rocksdb/version.h |
|
||||
ROCKSDB_MINOR = $(shell egrep "ROCKSDB_MINOR.[0-9]" include/rocksdb/version.h | cut -d ' ' -f 3)
|
||||
ROCKSDB_PATCH = $(shell egrep "ROCKSDB_PATCH.[0-9]" include/rocksdb/version.h | cut -d ' ' -f 3)
|
||||
|
||||
# If NO_UPDATE_BUILD_VERSION is set we don't update util/build_version.cc, but
|
||||
# the file needs to already exist or else the build will fail
|
||||
ifndef NO_UPDATE_BUILD_VERSION
|
||||
|
||||
# By default, use the current date-time as the date. If there are no changes,
|
||||
# we will use the last commit date instead.
|
||||
build_date := $(shell date "+%Y-%m-%d %T")
|
||||
|
||||
ifdef FORCE_GIT_SHA
|
||||
git_sha := $(FORCE_GIT_SHA)
|
||||
git_mod := 1
|
||||
git_date := $(build_date)
|
||||
else
|
||||
git_sha := $(shell git rev-parse HEAD 2>/dev/null)
|
||||
git_tag := $(shell git symbolic-ref -q --short HEAD 2> /dev/null || git describe --tags --exact-match 2>/dev/null)
|
||||
git_mod := $(shell git diff-index HEAD --quiet 2>/dev/null; echo $$?)
|
||||
git_date := $(shell git log -1 --date=format:"%Y-%m-%d %T" --format="%ad" 2>/dev/null)
|
||||
endif
|
||||
gen_build_version = sed -e s/@GIT_SHA@/$(git_sha)/ -e s:@GIT_TAG@:"$(git_tag)": -e s/@GIT_MOD@/"$(git_mod)"/ -e s/@BUILD_DATE@/"$(build_date)"/ -e s/@GIT_DATE@/"$(git_date)"/ util/build_version.cc.in
|
||||
|
||||
# Record the version of the source that we are compiling.
|
||||
# We keep a record of the git revision in this file. It is then built
|
||||
# as a regular source file as part of the compilation process.
|
||||
# One can run "strings executable_filename | grep _build_" to find
|
||||
# the version of the source that we used to build the executable file.
|
||||
util/build_version.cc: $(filter-out $(OBJ_DIR)/util/build_version.o, $(LIB_OBJECTS)) util/build_version.cc.in
|
||||
$(AM_V_GEN)rm -f $@-t
|
||||
$(AM_V_at)$(gen_build_version) > $@
|
||||
endif
|
||||
CLEAN_FILES += util/build_version.cc
|
||||
|
||||
default: all
|
||||
|
||||
#-----------------------------------------------
|
||||
@@ -1346,7 +1425,7 @@ $(STATIC_TEST_LIBRARY): $(TEST_OBJECTS)
|
||||
$(AM_V_AR)rm -f $@ $(SHARED_TEST_LIBRARY)
|
||||
$(AM_V_at)$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
$(STATIC_TOOLS_LIBRARY): $(BENCH_OBJECTS) $(TOOL_OBJECTS)
|
||||
$(STATIC_TOOLS_LIBRARY): $(TOOL_OBJECTS)
|
||||
$(AM_V_AR)rm -f $@ $(SHARED_TOOLS_LIBRARY)
|
||||
$(AM_V_at)$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
@@ -1543,6 +1622,9 @@ db_inplace_update_test: $(OBJ_DIR)/db/db_inplace_update_test.o $(TEST_LIBRARY) $
|
||||
db_iterator_test: $(OBJ_DIR)/db/db_iterator_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_kv_checksum_test: $(OBJ_DIR)/db/db_kv_checksum_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_memtable_test: $(OBJ_DIR)/db/db_memtable_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1926,6 +2008,9 @@ blob_db_test: $(OBJ_DIR)/utilities/blob_db/blob_db_test.o $(TEST_LIBRARY) $(LIBR
|
||||
repeatable_thread_test: $(OBJ_DIR)/util/repeatable_thread_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
range_locking_test: utilities/transactions/lock/range/range_locking_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
range_tombstone_fragmenter_test: $(OBJ_DIR)/db/range_tombstone_fragmenter_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -2004,6 +2089,10 @@ install-headers: gen-pc
|
||||
for header in `$(FIND) "include/rocksdb" -type f -name *.h`; do \
|
||||
install -C -m 644 $$header $(DESTDIR)/$(PREFIX)/$$header; \
|
||||
done
|
||||
for header in $(ROCKSDB_PLUGIN_HEADERS); do \
|
||||
install -d $(DESTDIR)/$(PREFIX)/include/rocksdb/`dirname $$header`; \
|
||||
install -C -m 644 $$header $(DESTDIR)/$(PREFIX)/include/rocksdb/$$header; \
|
||||
done
|
||||
install -C -m 644 rocksdb.pc $(INSTALL_LIBDIR)/pkgconfig/rocksdb.pc
|
||||
|
||||
install-static: install-headers $(LIBRARY)
|
||||
@@ -2087,11 +2176,11 @@ BZIP2_DOWNLOAD_BASE ?= https://sourceware.org/pub/bzip2
|
||||
SNAPPY_VER ?= 1.1.8
|
||||
SNAPPY_SHA256 ?= 16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f
|
||||
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/archive
|
||||
LZ4_VER ?= 1.9.2
|
||||
LZ4_SHA256 ?= 658ba6191fa44c92280d4aa2c271b0f4fbc0e34d249578dd05e50e76d0e5efcc
|
||||
LZ4_VER ?= 1.9.3
|
||||
LZ4_SHA256 ?= 030644df4611007ff7dc962d981f390361e6c97a34e5cbc393ddfbe019ffe2c1
|
||||
LZ4_DOWNLOAD_BASE ?= https://github.com/lz4/lz4/archive
|
||||
ZSTD_VER ?= 1.4.5
|
||||
ZSTD_SHA256 ?= 734d1f565c42f691f8420c8d06783ad818060fc390dee43ae0a89f86d0a4f8c2
|
||||
ZSTD_VER ?= 1.4.9
|
||||
ZSTD_SHA256 ?= acf714d98e3db7b876e5b540cbf6dee298f60eb3c0723104f6d3f065cd60d6a8
|
||||
ZSTD_DOWNLOAD_BASE ?= https://github.com/facebook/zstd/archive
|
||||
CURL_SSL_OPTS ?= --tlsv1
|
||||
|
||||
@@ -2206,9 +2295,10 @@ endif
|
||||
|
||||
JAVA_STATIC_FLAGS = -DZLIB -DBZIP2 -DSNAPPY -DLZ4 -DZSTD
|
||||
JAVA_STATIC_INCLUDES = -I./zlib-$(ZLIB_VER) -I./bzip2-$(BZIP2_VER) -I./snappy-$(SNAPPY_VER) -I./snappy-$(SNAPPY_VER)/build -I./lz4-$(LZ4_VER)/lib -I./zstd-$(ZSTD_VER)/lib -I./zstd-$(ZSTD_VER)/lib/dictBuilder
|
||||
ifneq ($(findstring rocksdbjavastatic, $(MAKECMDGOALS)),)
|
||||
|
||||
ifneq ($(findstring rocksdbjavastatic, $(filter-out rocksdbjavastatic_deps, $(MAKECMDGOALS))),)
|
||||
CXXFLAGS += $(JAVA_STATIC_FLAGS) $(JAVA_STATIC_INCLUDES)
|
||||
CFLAGS += $(JAVA_STATIC_FLAGS) $(JAVA_STATIC_INCLUDES)
|
||||
CFLAGS += $(JAVA_STATIC_FLAGS) $(JAVA_STATIC_INCLUDES)
|
||||
endif
|
||||
rocksdbjavastatic:
|
||||
ifeq ($(JAVA_HOME),)
|
||||
@@ -2216,8 +2306,11 @@ ifeq ($(JAVA_HOME),)
|
||||
endif
|
||||
$(MAKE) rocksdbjavastatic_deps
|
||||
$(MAKE) rocksdbjavastatic_libobjects
|
||||
cd java;$(MAKE) javalib;
|
||||
rm -f ./java/target/$(ROCKSDBJNILIB)
|
||||
$(MAKE) rocksdbjavastatic_javalib
|
||||
|
||||
rocksdbjavastatic_javalib:
|
||||
cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) javalib
|
||||
rm -f java/target/$(ROCKSDBJNILIB)
|
||||
$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC \
|
||||
-o ./java/target/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) \
|
||||
$(LIB_OBJECTS) $(COVERAGEFLAGS) \
|
||||
@@ -2310,7 +2403,7 @@ rocksdbjava: $(LIB_OBJECTS)
|
||||
ifeq ($(JAVA_HOME),)
|
||||
$(error JAVA_HOME is not set)
|
||||
endif
|
||||
$(AM_V_GEN)cd java;$(MAKE) javalib;
|
||||
$(AM_V_GEN)cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) javalib;
|
||||
$(AM_V_at)rm -f ./java/target/$(ROCKSDBJNILIB)
|
||||
$(AM_V_at)$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC -o ./java/target/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) $(LIB_OBJECTS) $(JAVA_LDFLAGS) $(COVERAGEFLAGS)
|
||||
$(AM_V_at)cd java;jar -cf target/$(ROCKSDB_JAR) HISTORY*.md
|
||||
@@ -2322,13 +2415,13 @@ jclean:
|
||||
cd java;$(MAKE) clean;
|
||||
|
||||
jtest_compile: rocksdbjava
|
||||
cd java;$(MAKE) java_test
|
||||
cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) java_test
|
||||
|
||||
jtest_run:
|
||||
cd java;$(MAKE) run_test
|
||||
|
||||
jtest: rocksdbjava
|
||||
cd java;$(MAKE) sample;$(MAKE) test;
|
||||
cd java;$(MAKE) sample; SHA256_CMD='$(SHA256_CMD)' $(MAKE) test;
|
||||
$(PYTHON) tools/check_all_python.py # TODO peterd: find a better place for this check in CI targets
|
||||
|
||||
jdb_bench:
|
||||
@@ -2438,8 +2531,12 @@ build_subset_tests: $(ROCKSDBTESTS_SUBSET)
|
||||
# working solution.
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(MAKECMDGOALS),format)
|
||||
ifneq ($(MAKECMDGOALS),check-format)
|
||||
ifneq ($(MAKECMDGOALS),check-buck-targets)
|
||||
ifneq ($(MAKECMDGOALS),jclean)
|
||||
ifneq ($(MAKECMDGOALS),jtest)
|
||||
ifneq ($(MAKECMDGOALS),rocksdbjavastatic)
|
||||
ifneq ($(MAKECMDGOALS),rocksdbjavastatic_deps)
|
||||
ifneq ($(MAKECMDGOALS),package)
|
||||
ifneq ($(MAKECMDGOALS),analyze)
|
||||
-include $(DEPFILES)
|
||||
@@ -2449,3 +2546,7 @@ endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,3 @@
|
||||
This is the list of all known third-party plugins for RocksDB. If something is missing, please open a pull request to add it.
|
||||
|
||||
* [Dedupfs](https://github.com/ajkr/dedupfs): an example for plugin developers to reference
|
||||
@@ -1,4 +1,5 @@
|
||||
# This file @generated by `python3 buckifier/buckify_rocksdb.py`
|
||||
# This file @generated by:
|
||||
#$ python3 buckifier/buckify_rocksdb.py
|
||||
# --> DO NOT EDIT MANUALLY <--
|
||||
# This file is a Facebook-specific integration for buck builds, so can
|
||||
# only be validated by Facebook employees.
|
||||
@@ -24,7 +25,7 @@ ROCKSDB_EXTERNAL_DEPS = [
|
||||
("zlib", None, "z"),
|
||||
("gflags", None, "gflags"),
|
||||
("lz4", None, "lz4"),
|
||||
("zstd", None),
|
||||
("zstd", None, "zstd"),
|
||||
]
|
||||
|
||||
ROCKSDB_OS_DEPS = [
|
||||
@@ -400,6 +401,8 @@ cpp_library(
|
||||
"utilities/transactions/lock/range/range_tree/lib/standalone_port.cc",
|
||||
"utilities/transactions/lock/range/range_tree/lib/util/dbt.cc",
|
||||
"utilities/transactions/lock/range/range_tree/lib/util/memarena.cc",
|
||||
"utilities/transactions/lock/range/range_tree/range_tree_lock_manager.cc",
|
||||
"utilities/transactions/lock/range/range_tree/range_tree_lock_tracker.cc",
|
||||
"utilities/transactions/optimistic_transaction.cc",
|
||||
"utilities/transactions/optimistic_transaction_db_impl.cc",
|
||||
"utilities/transactions/pessimistic_transaction.cc",
|
||||
@@ -702,6 +705,8 @@ cpp_library(
|
||||
"utilities/transactions/lock/range/range_tree/lib/standalone_port.cc",
|
||||
"utilities/transactions/lock/range/range_tree/lib/util/dbt.cc",
|
||||
"utilities/transactions/lock/range/range_tree/lib/util/memarena.cc",
|
||||
"utilities/transactions/lock/range/range_tree/range_tree_lock_manager.cc",
|
||||
"utilities/transactions/lock/range/range_tree/range_tree_lock_tracker.cc",
|
||||
"utilities/transactions/optimistic_transaction.cc",
|
||||
"utilities/transactions/optimistic_transaction_db_impl.cc",
|
||||
"utilities/transactions/pessimistic_transaction.cc",
|
||||
@@ -1233,6 +1238,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_kv_checksum_test",
|
||||
"db/db_kv_checksum_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_log_iter_test",
|
||||
"db/db_log_iter_test.cc",
|
||||
@@ -1800,6 +1812,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"range_locking_test",
|
||||
"utilities/transactions/lock/range/range_locking_test.cc",
|
||||
"parallel",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"range_tombstone_fragmenter_test",
|
||||
"db/range_tombstone_fragmenter_test.cc",
|
||||
|
||||
@@ -26,6 +26,9 @@ Learn more about those use cases in a Tech Talk by Ankit Gupta and Naveen Somasu
|
||||
## Yahoo
|
||||
Yahoo is using RocksDB as a storage engine for their biggest distributed data store Sherpa. Learn more about it here: http://yahooeng.tumblr.com/post/120730204806/sherpa-scales-new-heights
|
||||
|
||||
## Baidu
|
||||
[Apache Doris](http://doris.apache.org/master/en/) is a MPP analytical database engine released by Baidu. It [uses RocksDB](http://doris.apache.org/master/en/administrator-guide/operation/tablet-meta-tool.html) to manage its tablet's metadata.
|
||||
|
||||
## CockroachDB
|
||||
CockroachDB is an open-source geo-replicated transactional database. They are using RocksDB as their storage engine. Check out their github: https://github.com/cockroachdb/cockroach
|
||||
|
||||
@@ -67,7 +70,7 @@ Pinterest's Object Retrieval System uses RocksDB for storage: https://www.youtub
|
||||
[VWO's](https://vwo.com/) Smart Code checker and URL helper uses RocksDB to store all the URLs where VWO's Smart Code is installed.
|
||||
|
||||
## quasardb
|
||||
[quasardb](https://www.quasardb.net) is a high-performance, distributed, transactional key-value database that integrates well with in-memory analytics engines such as Apache Spark.
|
||||
[quasardb](https://www.quasardb.net) is a high-performance, distributed, transactional key-value database that integrates well with in-memory analytics engines such as Apache Spark.
|
||||
quasardb uses a heavily tuned RocksDB as its persistence layer.
|
||||
|
||||
## Netflix
|
||||
@@ -96,10 +99,10 @@ LzLabs is using RocksDB as a storage engine in their multi-database distributed
|
||||
|
||||
## IOTA Foundation
|
||||
[IOTA Foundation](https://www.iota.org/) is using RocksDB in the [IOTA Reference Implementation (IRI)](https://github.com/iotaledger/iri) to store the local state of the Tangle. The Tangle is the first open-source distributed ledger powering the future of the Internet of Things.
|
||||
|
||||
|
||||
## Avrio Project
|
||||
[Avrio Project](http://avrio-project.github.io/avrio.network/) is using RocksDB in [Avrio ](https://github.com/avrio-project/avrio) to store blocks, account balances and data and other blockchain-releated data. Avrio is a multiblockchain decentralized cryptocurrency empowering monetary transactions.
|
||||
|
||||
|
||||
## Crux
|
||||
[Crux](https://github.com/juxt/crux) is a document database that uses RocksDB for local [EAV](https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model) index storage to enable point-in-time bitemporal Datalog queries. The "unbundled" architecture uses Kafka to provide horizontal scalability.
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ from util import ColorString
|
||||
# (This generates a TARGET file without user-specified dependency for unit
|
||||
# tests.)
|
||||
# $python3 buckifier/buckify_rocksdb.py \
|
||||
# '{"fake": { \
|
||||
# "extra_deps": [":test_dep", "//fakes/module:mock1"], \
|
||||
# "extra_compiler_flags": ["-DROCKSDB_LITE", "-Os"], \
|
||||
# } \
|
||||
# '{"fake": {
|
||||
# "extra_deps": [":test_dep", "//fakes/module:mock1"],
|
||||
# "extra_compiler_flags": ["-DROCKSDB_LITE", "-Os"]
|
||||
# }
|
||||
# }'
|
||||
# (Generated TARGETS file has test_dep and mock1 as dependencies for RocksDB
|
||||
# unit tests, and will use the extra_compiler_flags to compile the unit test
|
||||
@@ -129,17 +129,27 @@ def generate_targets(repo_path, deps_map):
|
||||
if src_mk is None or cc_files is None or parallel_tests is None:
|
||||
return False
|
||||
|
||||
TARGETS = TARGETSBuilder("%s/TARGETS" % repo_path)
|
||||
extra_argv = ""
|
||||
if len(sys.argv) >= 2:
|
||||
# Heuristically quote and canonicalize whitespace for inclusion
|
||||
# in how the file was generated.
|
||||
extra_argv = " '{0}'".format(" ".join(sys.argv[1].split()))
|
||||
|
||||
TARGETS = TARGETSBuilder("%s/TARGETS" % repo_path, extra_argv)
|
||||
|
||||
# rocksdb_lib
|
||||
TARGETS.add_library(
|
||||
"rocksdb_lib",
|
||||
src_mk["LIB_SOURCES"] +
|
||||
# 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"])
|
||||
# rocksdb_whole_archive_lib
|
||||
TARGETS.add_library(
|
||||
"rocksdb_whole_archive_lib",
|
||||
src_mk["LIB_SOURCES"] +
|
||||
# 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=None,
|
||||
headers=None,
|
||||
|
||||
@@ -25,10 +25,11 @@ def pretty_list(lst, indent=8):
|
||||
|
||||
|
||||
class TARGETSBuilder(object):
|
||||
def __init__(self, path):
|
||||
def __init__(self, path, extra_argv):
|
||||
self.path = path
|
||||
self.targets_file = open(path, 'wb')
|
||||
header = targets_cfg.rocksdb_target_header_template
|
||||
header = targets_cfg.rocksdb_target_header_template.format(
|
||||
extra_argv=extra_argv)
|
||||
self.targets_file.write(header.encode("utf-8"))
|
||||
self.total_lib = 0
|
||||
self.total_bin = 0
|
||||
|
||||
@@ -5,7 +5,8 @@ from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
rocksdb_target_header_template = \
|
||||
"""# This file \100generated by `python3 buckifier/buckify_rocksdb.py`
|
||||
"""# This file \100generated by:
|
||||
#$ python3 buckifier/buckify_rocksdb.py{extra_argv}
|
||||
# --> DO NOT EDIT MANUALLY <--
|
||||
# This file is a Facebook-specific integration for buck builds, so can
|
||||
# only be validated by Facebook employees.
|
||||
@@ -31,7 +32,7 @@ ROCKSDB_EXTERNAL_DEPS = [
|
||||
("zlib", None, "z"),
|
||||
("gflags", None, "gflags"),
|
||||
("lz4", None, "lz4"),
|
||||
("zstd", None),
|
||||
("zstd", None, "zstd"),
|
||||
]
|
||||
|
||||
ROCKSDB_OS_DEPS = [
|
||||
@@ -99,11 +100,11 @@ ROCKSDB_PREPROCESSOR_FLAGS = [
|
||||
"-I" + REPO_PATH,
|
||||
]
|
||||
|
||||
ROCKSDB_ARCH_PREPROCESSOR_FLAGS = {
|
||||
ROCKSDB_ARCH_PREPROCESSOR_FLAGS = {{
|
||||
"x86_64": [
|
||||
"-DHAVE_PCLMUL",
|
||||
],
|
||||
}
|
||||
}}
|
||||
|
||||
build_mode = read_config("fbcode", "build_mode")
|
||||
|
||||
|
||||
@@ -45,8 +45,13 @@ if test -z "$OUTPUT"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# we depend on C++11
|
||||
PLATFORM_CXXFLAGS="-std=c++11"
|
||||
# we depend on C++11, but should be compatible with newer standards
|
||||
if [ "$ROCKSDB_CXX_STANDARD" ]; then
|
||||
PLATFORM_CXXFLAGS="-std=$ROCKSDB_CXX_STANDARD"
|
||||
else
|
||||
PLATFORM_CXXFLAGS="-std=c++11"
|
||||
fi
|
||||
|
||||
# we currently depend on POSIX platform
|
||||
COMMON_FLAGS="-DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX"
|
||||
|
||||
@@ -663,6 +668,23 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "`echo $TARGET_ARCHITECTURE | grep ^ppc64`"; then
|
||||
# check for GNU libc on ppc64
|
||||
$CXX -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <gnu/libc-version.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("GNU libc version: %s\n", gnu_get_libc_version());
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" != 0 ]; then
|
||||
PPC_LIBC_IS_GNU=0
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$TRY_SSE_ETC"; then
|
||||
# The USE_SSE flag now means "attempt to compile with widely-available
|
||||
# Intel architecture extensions utilized by specific optimizations in the
|
||||
@@ -856,3 +878,6 @@ echo "LUA_PATH=$LUA_PATH" >> "$OUTPUT"
|
||||
if test -n "$USE_FOLLY_DISTRIBUTED_MUTEX"; then
|
||||
echo "USE_FOLLY_DISTRIBUTED_MUTEX=$USE_FOLLY_DISTRIBUTED_MUTEX" >> "$OUTPUT"
|
||||
fi
|
||||
if test -n "$PPC_LIBC_IS_GNU"; then
|
||||
echo "PPC_LIBC_IS_GNU=$PPC_LIBC_IS_GNU" >> "$OUTPUT"
|
||||
fi
|
||||
@@ -52,7 +52,8 @@ else
|
||||
else
|
||||
echo "You didn't have clang-format-diff.py and/or clang-format available in your computer!"
|
||||
echo "You can download clang-format-diff.py by running: "
|
||||
echo " curl --location https://tinyurl.com/y2kvokof -o ${REPO_ROOT}/clang-format-diff.py"
|
||||
echo " curl --location https://raw.githubusercontent.com/llvm/llvm-project/main/clang/tools/clang-format/clang-format-diff.py -o ${REPO_ROOT}/clang-format-diff.py"
|
||||
echo "You should make sure the downloaded script is not compromised."
|
||||
echo "You can download clang-format by running:"
|
||||
echo " brew install clang-format"
|
||||
echo " Or"
|
||||
@@ -82,7 +83,8 @@ else
|
||||
echo "You have clang-format-diff.py for Python 2 but are using a Python 3"
|
||||
echo "interpreter (${PYTHON:-python3})."
|
||||
echo "You can download clang-format-diff.py for Python 3 by running: "
|
||||
echo " curl --location https://tinyurl.com/y2kvokof -o ${REPO_ROOT}/clang-format-diff.py"
|
||||
echo " curl --location https://raw.githubusercontent.com/llvm/llvm-project/main/clang/tools/clang-format/clang-format-diff.py -o ${REPO_ROOT}/clang-format-diff.py"
|
||||
echo "You should make sure the downloaded script is not compromised."
|
||||
exit 130
|
||||
fi
|
||||
CLANG_FORMAT_DIFF="${PYTHON:-python3} $CFD_PATH"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# to determine next steps to run
|
||||
|
||||
# Usage:
|
||||
# EMAIL=<email> ONCALL=<email> TRIGGER=<trigger> SUBSCRIBER=<email> rocks_ci.py <test-name>
|
||||
# EMAIL=<email> ONCALL=<email> TRIGGER=<trigger> SUBSCRIBER=<email> WORKINGDIR=<working_dir> rocksdb-lego-determinator <test-name>
|
||||
#
|
||||
# Input Value
|
||||
# -------------------------------------------------------------------------
|
||||
@@ -11,7 +11,7 @@
|
||||
# ONCALL Email address to raise a task on failure
|
||||
# TRIGGER Trigger conditions for email. Valid values are fail, warn, all
|
||||
# SUBSCRIBER Email addresss to add as subscriber for task
|
||||
#
|
||||
# WORKINGDIR Working directory
|
||||
|
||||
#
|
||||
# Report configuration
|
||||
@@ -53,13 +53,19 @@ if [[ ! -z $REPORT_EMAIL || ! -z $CREATE_TASK ]]; then
|
||||
]"
|
||||
fi
|
||||
|
||||
# Working directory for the following command, default to current directory
|
||||
WORKING_DIR=.
|
||||
if [ ! -z $WORKINGDIR ]; then
|
||||
WORKING_DIR=$WORKINGDIR
|
||||
fi
|
||||
|
||||
#
|
||||
# Helper variables
|
||||
#
|
||||
CLEANUP_ENV="
|
||||
{
|
||||
'name':'Cleanup environment',
|
||||
'shell':'rm -rf /dev/shm/rocksdb && mkdir /dev/shm/rocksdb && (chmod +t /dev/shm || true) && make clean',
|
||||
'shell':'cd $WORKING_DIR; rm -rf /dev/shm/rocksdb && mkdir /dev/shm/rocksdb && (chmod +t /dev/shm || true) && make clean',
|
||||
'user':'root'
|
||||
}"
|
||||
|
||||
@@ -112,6 +118,7 @@ SETUP_JAVA_ENV="export $HTTP_PROXY; export JAVA_HOME=/usr/local/jdk-8u60-64/; ex
|
||||
PARSER="'parser':'python build_tools/error_filter.py $1'"
|
||||
|
||||
CONTRUN_NAME="ROCKSDB_CONTRUN_NAME"
|
||||
SKIP_FORMAT_CHECKS="SKIP_FORMAT_BUCK_CHECKS=1"
|
||||
|
||||
# This code is getting called under various scenarios. What we care about is to
|
||||
# understand when it's called from nightly contruns because in that case we'll
|
||||
@@ -153,7 +160,7 @@ UNIT_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and test RocksDB debug version',
|
||||
'shell':'$SHM $DEBUG make $PARALLELISM check || $CONTRUN_NAME=check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -176,7 +183,7 @@ UNIT_TEST_NON_SHM_COMMANDS="[
|
||||
{
|
||||
'name':'Build and test RocksDB debug version',
|
||||
'timeout': 86400,
|
||||
'shell':'$NON_SHM $DEBUG make $PARALLELISM check || $CONTRUN_NAME=non_shm_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $NON_SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=non_shm_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -197,7 +204,7 @@ RELEASE_BUILD_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build RocksDB release',
|
||||
'shell':'make $PARALLEL_j release || $CONTRUN_NAME=release $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; make $PARALLEL_j release || $CONTRUN_NAME=release $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -218,7 +225,7 @@ UNIT_TEST_COMMANDS_481="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and test RocksDB debug version',
|
||||
'shell':'$SHM $GCC_481 $DEBUG make $PARALLELISM check || $CONTRUN_NAME=unit_gcc_481_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $GCC_481 $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=unit_gcc_481_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -239,7 +246,7 @@ RELEASE_BUILD_COMMANDS_481="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build RocksDB release on GCC 4.8.1',
|
||||
'shell':'$GCC_481 make $PARALLEL_j release || $CONTRUN_NAME=release_gcc481 $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $GCC_481 make $PARALLEL_j release || $CONTRUN_NAME=release_gcc481 $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -260,7 +267,7 @@ CLANG_UNIT_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and test RocksDB debug',
|
||||
'shell':'$CLANG $SHM $DEBUG make $PARALLELISM check || $CONTRUN_NAME=clang_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $CLANG $SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=clang_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -281,7 +288,7 @@ CLANG_RELEASE_BUILD_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build RocksDB release',
|
||||
'shell':'$CLANG make $PARALLEL_j release|| $CONTRUN_NAME=clang_release $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $CLANG make $PARALLEL_j release|| $CONTRUN_NAME=clang_release $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -302,7 +309,7 @@ CLANG_ANALYZE_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'RocksDB build and analyze',
|
||||
'shell':'$CLANG $SHM $DEBUG make $PARALLEL_j analyze || $CONTRUN_NAME=clang_analyze $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $CLANG $SHM $DEBUG make $PARALLEL_j analyze || $CONTRUN_NAME=clang_analyze $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -323,7 +330,7 @@ CODE_COV_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build, test and collect code coverage info',
|
||||
'shell':'$SHM $DEBUG make $PARALLELISM coverage || $CONTRUN_NAME=coverage $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM coverage || $CONTRUN_NAME=coverage $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -344,7 +351,7 @@ UNITY_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build, test unity test',
|
||||
'shell':'$SHM $DEBUG V=1 make J=1 unity_test || $CONTRUN_NAME=unity_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG V=1 make J=1 unity_test || $CONTRUN_NAME=unity_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -365,7 +372,7 @@ LITE_BUILD_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build RocksDB debug version',
|
||||
'shell':'make J=1 LITE=1 all check || $CONTRUN_NAME=lite $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SKIP_FORMAT_CHECKS make J=1 LITE=1 all check || $CONTRUN_NAME=lite $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -385,7 +392,7 @@ REPORT_LITE_BINARY_SIZE_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Report RocksDB Lite binary size to scuba',
|
||||
'shell':'tools/report_lite_binary_size.sh',
|
||||
'shell':'cd $WORKING_DIR; tools/report_lite_binary_size.sh',
|
||||
'user':'root',
|
||||
},
|
||||
],
|
||||
@@ -404,14 +411,14 @@ STRESS_CRASH_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB debug stress tests',
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
{
|
||||
'name':'Build and run RocksDB debug crash tests',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test || $CONTRUN_NAME=crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test || $CONTRUN_NAME=crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -434,14 +441,14 @@ BLACKBOX_STRESS_CRASH_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB debug stress tests',
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
{
|
||||
'name':'Build and run RocksDB debug blackbox crash tests',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 blackbox_crash_test || $CONTRUN_NAME=blackbox_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 blackbox_crash_test || $CONTRUN_NAME=blackbox_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -464,14 +471,14 @@ WHITEBOX_STRESS_CRASH_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB debug stress tests',
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
{
|
||||
'name':'Build and run RocksDB debug whitebox crash tests',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 whitebox_crash_test || $CONTRUN_NAME=whitebox_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 whitebox_crash_test || $CONTRUN_NAME=whitebox_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -494,14 +501,14 @@ STRESS_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB debug stress tests',
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
{
|
||||
'name':'Build and run RocksDB debug crash tests with atomic flush',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test_with_atomic_flush || $CONTRUN_NAME=crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test_with_atomic_flush || $CONTRUN_NAME=crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -524,14 +531,14 @@ STRESS_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB debug stress tests',
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 db_stress || $CONTRUN_NAME=db_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
{
|
||||
'name':'Build and run RocksDB debug crash tests with txn',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test_with_txn || $CONTRUN_NAME=crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test_with_txn || $CONTRUN_NAME=crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -553,7 +560,7 @@ WRITE_STRESS_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB write stress tests',
|
||||
'shell':'make write_stress && python tools/write_stress_runner.py --runtime_sec=3600 --db=/tmp/rocksdb_write_stress || $CONTRUN_NAME=write_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; make write_stress && python tools/write_stress_runner.py --runtime_sec=3600 --db=/tmp/rocksdb_write_stress || $CONTRUN_NAME=write_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
@@ -576,7 +583,7 @@ ASAN_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Test RocksDB debug under ASAN',
|
||||
'shell':'set -o pipefail && ($SHM $ASAN $DEBUG make $PARALLELISM asan_check || $CONTRUN_NAME=asan_check $TASK_CREATION_TOOL) |& /usr/facebook/ops/scripts/asan_symbolize.py -d',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && ($SHM $ASAN $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM asan_check || $CONTRUN_NAME=asan_check $TASK_CREATION_TOOL) |& /usr/facebook/ops/scripts/asan_symbolize.py -d',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
@@ -599,7 +606,7 @@ ASAN_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug asan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 asan_crash_test || $CONTRUN_NAME=asan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $SKIP_FORMAT_CHECKS make J=1 asan_crash_test || $CONTRUN_NAME=asan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -623,7 +630,7 @@ ASAN_BLACKBOX_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug blackbox asan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 blackbox_asan_crash_test || $CONTRUN_NAME=blackbox_asan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $SKIP_FORMAT_CHECKS make J=1 blackbox_asan_crash_test || $CONTRUN_NAME=blackbox_asan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -647,7 +654,7 @@ ASAN_WHITEBOX_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug whitebox asan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 whitebox_asan_crash_test || $CONTRUN_NAME=whitebox_asan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $SKIP_FORMAT_CHECKS make J=1 whitebox_asan_crash_test || $CONTRUN_NAME=whitebox_asan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -671,7 +678,7 @@ ASAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug asan_crash_test_with_atomic_flush',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 asan_crash_test_with_atomic_flush || $CONTRUN_NAME=asan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $SKIP_FORMAT_CHECKS make J=1 asan_crash_test_with_atomic_flush || $CONTRUN_NAME=asan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -695,7 +702,7 @@ ASAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug asan_crash_test_with_txn',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 asan_crash_test_with_txn || $CONTRUN_NAME=asan_crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $SKIP_FORMAT_CHECKS make J=1 asan_crash_test_with_txn || $CONTRUN_NAME=asan_crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -717,7 +724,7 @@ UBSAN_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Test RocksDB debug under UBSAN',
|
||||
'shell':'set -o pipefail && $SHM $UBSAN $CLANG $DEBUG make $PARALLELISM ubsan_check || $CONTRUN_NAME=ubsan_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $UBSAN $CLANG $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM ubsan_check || $CONTRUN_NAME=ubsan_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
@@ -740,7 +747,7 @@ UBSAN_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug ubsan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH $CLANG make J=1 ubsan_crash_test || $CONTRUN_NAME=ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $CLANG $SKIP_FORMAT_CHECKS make J=1 ubsan_crash_test || $CONTRUN_NAME=ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -764,7 +771,7 @@ UBSAN_BLACKBOX_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug blackbox ubsan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH $CLANG make J=1 blackbox_ubsan_crash_test || $CONTRUN_NAME=blackbox_ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $CLANG $SKIP_FORMAT_CHECKS make J=1 blackbox_ubsan_crash_test || $CONTRUN_NAME=blackbox_ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -788,7 +795,7 @@ UBSAN_WHITEBOX_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug whitebox ubsan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH $CLANG make J=1 whitebox_ubsan_crash_test || $CONTRUN_NAME=whitebox_ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $CLANG $SKIP_FORMAT_CHECKS make J=1 whitebox_ubsan_crash_test || $CONTRUN_NAME=whitebox_ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -812,7 +819,7 @@ UBSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug ubsan_crash_test_with_atomic_flush',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH $CLANG make J=1 ubsan_crash_test_with_atomic_flush || $CONTRUN_NAME=ubsan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $CLANG $SKIP_FORMAT_CHECKS make J=1 ubsan_crash_test_with_atomic_flush || $CONTRUN_NAME=ubsan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -836,7 +843,7 @@ UBSAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug ubsan_crash_test_with_txn',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH $CLANG make J=1 ubsan_crash_test_with_txn || $CONTRUN_NAME=ubsan_crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $NON_TSAN_CRASH $CLANG $SKIP_FORMAT_CHECKS make J=1 ubsan_crash_test_with_txn || $CONTRUN_NAME=ubsan_crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -860,7 +867,7 @@ VALGRIND_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Run RocksDB debug unit tests',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG make $PARALLELISM valgrind_test || $CONTRUN_NAME=valgrind_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG make $PARALLELISM valgrind_test || $CONTRUN_NAME=valgrind_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -883,7 +890,7 @@ TSAN_UNIT_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Run RocksDB debug unit test',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN make $PARALLELISM check || $CONTRUN_NAME=tsan_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=tsan_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -906,7 +913,7 @@ TSAN_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Compile and run',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 crash_test || $CONTRUN_NAME=tsan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 crash_test || $CONTRUN_NAME=tsan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -930,7 +937,7 @@ TSAN_BLACKBOX_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Compile and run',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 blackbox_crash_test || $CONTRUN_NAME=tsan_blackbox_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 blackbox_crash_test || $CONTRUN_NAME=tsan_blackbox_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -954,7 +961,7 @@ TSAN_WHITEBOX_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Compile and run',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 whitebox_crash_test || $CONTRUN_NAME=tsan_whitebox_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 whitebox_crash_test || $CONTRUN_NAME=tsan_whitebox_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -978,7 +985,7 @@ TSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
{
|
||||
'name':'Compile and run',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 crash_test_with_atomic_flush || $CONTRUN_NAME=tsan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 crash_test_with_atomic_flush || $CONTRUN_NAME=tsan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1002,7 +1009,7 @@ TSAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Compile and run',
|
||||
'timeout': 86400,
|
||||
'shell':'set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 crash_test_with_txn || $CONTRUN_NAME=tsan_crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $TSAN_CRASH CRASH_TEST_KILL_ODD=1887 make J=1 crash_test_with_txn || $CONTRUN_NAME=tsan_crash_test_with_txn $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1036,7 +1043,7 @@ FORMAT_COMPATIBLE_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Run RocksDB debug unit test',
|
||||
'shell':'build_tools/rocksdb-lego-determinator run_format_compatible || $CONTRUN_NAME=run_format_compatible $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; build_tools/rocksdb-lego-determinator run_format_compatible || $CONTRUN_NAME=run_format_compatible $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1058,6 +1065,7 @@ run_no_compression()
|
||||
mv .tmp.fbcode_config.sh build_tools/fbcode_config.sh
|
||||
cat Makefile | grep -v tools/ldb_test.py > .tmp.Makefile
|
||||
mv .tmp.Makefile Makefile
|
||||
export $SKIP_FORMAT_CHECKS
|
||||
make $DEBUG J=1 check
|
||||
}
|
||||
|
||||
@@ -1070,7 +1078,7 @@ NO_COMPRESSION_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Run RocksDB debug unit test',
|
||||
'shell':'build_tools/rocksdb-lego-determinator run_no_compression || $CONTRUN_NAME=run_no_compression $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; build_tools/rocksdb-lego-determinator run_no_compression || $CONTRUN_NAME=run_no_compression $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1129,7 +1137,7 @@ REGRESSION_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Make and run script',
|
||||
'shell':'build_tools/rocksdb-lego-determinator run_regression || $CONTRUN_NAME=run_regression $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; build_tools/rocksdb-lego-determinator run_regression || $CONTRUN_NAME=run_regression $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1150,7 +1158,7 @@ JAVA_BUILD_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build RocksDB for Java',
|
||||
'shell':'$SETUP_JAVA_ENV; $SHM make rocksdbjava || $CONTRUN_NAME=rocksdbjava $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; $SETUP_JAVA_ENV; $SHM make rocksdbjava || $CONTRUN_NAME=rocksdbjava $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
#include "file/writable_file_writer.h"
|
||||
#include "logging/logging.h"
|
||||
#include "options/cf_options.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "trace_replay/io_tracer.h"
|
||||
#include "util/compression.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -31,12 +33,13 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
int job_id, uint32_t column_family_id,
|
||||
const std::string& column_family_name, Env::IOPriority io_priority,
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions)
|
||||
: BlobFileBuilder([versions]() { return versions->NewFileNumber(); }, env,
|
||||
fs, immutable_cf_options, mutable_cf_options,
|
||||
file_options, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
column_family_name, io_priority, write_hint, io_tracer,
|
||||
blob_file_paths, blob_file_additions) {}
|
||||
|
||||
BlobFileBuilder::BlobFileBuilder(
|
||||
@@ -46,6 +49,7 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
int job_id, uint32_t column_family_id,
|
||||
const std::string& column_family_name, Env::IOPriority io_priority,
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions)
|
||||
: file_number_generator_(std::move(file_number_generator)),
|
||||
@@ -61,6 +65,7 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
column_family_name_(column_family_name),
|
||||
io_priority_(io_priority),
|
||||
write_hint_(write_hint),
|
||||
io_tracer_(io_tracer),
|
||||
blob_file_paths_(blob_file_paths),
|
||||
blob_file_additions_(blob_file_additions),
|
||||
blob_count_(0),
|
||||
@@ -157,11 +162,12 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
|
||||
std::unique_ptr<FSWritableFile> file;
|
||||
|
||||
{
|
||||
TEST_SYNC_POINT("BlobFileBuilder::OpenBlobFileIfNeeded:NewWritableFile");
|
||||
|
||||
assert(file_options_);
|
||||
const Status s =
|
||||
NewWritableFile(fs_, blob_file_path, &file, *file_options_);
|
||||
Status s = NewWritableFile(fs_, blob_file_path, &file, *file_options_);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"BlobFileBuilder::OpenBlobFileIfNeeded:NewWritableFile", &s);
|
||||
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -176,17 +182,19 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
|
||||
assert(file);
|
||||
file->SetIOPriority(io_priority_);
|
||||
file->SetWriteLifeTimeHint(write_hint_);
|
||||
|
||||
FileTypeSet tmp_set = immutable_cf_options_->checksum_handoff_file_types;
|
||||
Statistics* const statistics = immutable_cf_options_->statistics;
|
||||
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(file), blob_file_paths_->back(), *file_options_, env_,
|
||||
nullptr /*IOTracer*/, statistics, immutable_cf_options_->listeners,
|
||||
immutable_cf_options_->file_checksum_gen_factory));
|
||||
io_tracer_, statistics, immutable_cf_options_->listeners,
|
||||
immutable_cf_options_->file_checksum_gen_factory,
|
||||
tmp_set.Contains(FileType::kBlobFile)));
|
||||
|
||||
std::unique_ptr<BlobLogWriter> blob_log_writer(
|
||||
new BlobLogWriter(std::move(file_writer), env_, statistics,
|
||||
blob_file_number, immutable_cf_options_->use_fsync));
|
||||
constexpr bool do_flush = false;
|
||||
|
||||
std::unique_ptr<BlobLogWriter> blob_log_writer(new BlobLogWriter(
|
||||
std::move(file_writer), env_, statistics, blob_file_number,
|
||||
immutable_cf_options_->use_fsync, do_flush));
|
||||
|
||||
constexpr bool has_ttl = false;
|
||||
constexpr ExpirationRange expiration_range;
|
||||
@@ -195,9 +203,11 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
|
||||
expiration_range);
|
||||
|
||||
{
|
||||
TEST_SYNC_POINT("BlobFileBuilder::OpenBlobFileIfNeeded:WriteHeader");
|
||||
Status s = blob_log_writer->WriteHeader(header);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"BlobFileBuilder::OpenBlobFileIfNeeded:WriteHeader", &s);
|
||||
|
||||
const Status s = blob_log_writer->WriteHeader(header);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -247,9 +257,10 @@ Status BlobFileBuilder::WriteBlobToFile(const Slice& key, const Slice& blob,
|
||||
|
||||
uint64_t key_offset = 0;
|
||||
|
||||
TEST_SYNC_POINT("BlobFileBuilder::WriteBlobToFile:AddRecord");
|
||||
Status s = writer_->AddRecord(key, blob, &key_offset, blob_offset);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("BlobFileBuilder::WriteBlobToFile:AddRecord", &s);
|
||||
|
||||
const Status s = writer_->AddRecord(key, blob, &key_offset, blob_offset);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -271,10 +282,10 @@ Status BlobFileBuilder::CloseBlobFile() {
|
||||
std::string checksum_method;
|
||||
std::string checksum_value;
|
||||
|
||||
TEST_SYNC_POINT("BlobFileBuilder::WriteBlobToFile:AppendFooter");
|
||||
Status s = writer_->AppendFooter(footer, &checksum_method, &checksum_value);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("BlobFileBuilder::WriteBlobToFile:AppendFooter", &s);
|
||||
|
||||
const Status s =
|
||||
writer_->AppendFooter(footer, &checksum_method, &checksum_value);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class BlobFileAddition;
|
||||
class Status;
|
||||
class Slice;
|
||||
class BlobLogWriter;
|
||||
class IOTracer;
|
||||
|
||||
class BlobFileBuilder {
|
||||
public:
|
||||
@@ -36,6 +37,7 @@ class BlobFileBuilder {
|
||||
const std::string& column_family_name,
|
||||
Env::IOPriority io_priority,
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions);
|
||||
|
||||
@@ -48,6 +50,7 @@ class BlobFileBuilder {
|
||||
const std::string& column_family_name,
|
||||
Env::IOPriority io_priority,
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions);
|
||||
|
||||
@@ -81,6 +84,7 @@ class BlobFileBuilder {
|
||||
std::string column_family_name_;
|
||||
Env::IOPriority io_priority_;
|
||||
Env::WriteLifeTimeHint write_hint_;
|
||||
std::shared_ptr<IOTracer> io_tracer_;
|
||||
std::vector<std::string>* blob_file_paths_;
|
||||
std::vector<BlobFileAddition>* blob_file_additions_;
|
||||
std::unique_ptr<BlobLogWriter> writer_;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "db/blob/blob_index.h"
|
||||
#include "db/blob/blob_log_format.h"
|
||||
#include "db/blob/blob_log_sequential_reader.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "env/mock_env.h"
|
||||
#include "file/filename.h"
|
||||
#include "file/random_access_file_reader.h"
|
||||
@@ -40,7 +39,8 @@ class TestFileNumberGenerator {
|
||||
|
||||
class BlobFileBuilderTest : public testing::Test {
|
||||
protected:
|
||||
BlobFileBuilderTest() : mock_env_(Env::Default()), fs_(&mock_env_) {}
|
||||
BlobFileBuilderTest()
|
||||
: mock_env_(Env::Default()), fs_(mock_env_.GetFileSystem().get()) {}
|
||||
|
||||
void VerifyBlobFile(uint64_t blob_file_number,
|
||||
const std::string& blob_file_path,
|
||||
@@ -54,7 +54,7 @@ class BlobFileBuilderTest : public testing::Test {
|
||||
std::unique_ptr<FSRandomAccessFile> file;
|
||||
constexpr IODebugContext* dbg = nullptr;
|
||||
ASSERT_OK(
|
||||
fs_.NewRandomAccessFile(blob_file_path, file_options_, &file, dbg));
|
||||
fs_->NewRandomAccessFile(blob_file_path, file_options_, &file, dbg));
|
||||
|
||||
std::unique_ptr<RandomAccessFileReader> file_reader(
|
||||
new RandomAccessFileReader(std::move(file), blob_file_path,
|
||||
@@ -108,7 +108,7 @@ class BlobFileBuilderTest : public testing::Test {
|
||||
}
|
||||
|
||||
MockEnv mock_env_;
|
||||
LegacyFileSystemWrapper fs_;
|
||||
FileSystem* fs_;
|
||||
FileOptions file_options_;
|
||||
};
|
||||
|
||||
@@ -138,11 +138,11 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> expected_key_value_pairs(
|
||||
number_of_blobs);
|
||||
@@ -221,11 +221,11 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckMultipleFiles) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> expected_key_value_pairs(
|
||||
number_of_blobs);
|
||||
@@ -306,11 +306,11 @@ TEST_F(BlobFileBuilderTest, InlinedValues) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
for (size_t i = 0; i < number_of_blobs; ++i) {
|
||||
const std::string key = std::to_string(i);
|
||||
@@ -358,11 +358,11 @@ TEST_F(BlobFileBuilderTest, Compression) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
const std::string key("1");
|
||||
const std::string uncompressed_value(value_size, 'x');
|
||||
@@ -440,11 +440,11 @@ TEST_F(BlobFileBuilderTest, CompressionError) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack("CompressData:TamperWithReturnValue",
|
||||
[](void* arg) {
|
||||
@@ -517,11 +517,11 @@ TEST_F(BlobFileBuilderTest, Checksum) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
const std::string key("1");
|
||||
const std::string value("deadbeef");
|
||||
@@ -570,13 +570,11 @@ class BlobFileBuilderIOErrorTest
|
||||
protected:
|
||||
BlobFileBuilderIOErrorTest()
|
||||
: mock_env_(Env::Default()),
|
||||
fault_injection_env_(&mock_env_),
|
||||
fs_(&fault_injection_env_),
|
||||
fs_(mock_env_.GetFileSystem().get()),
|
||||
sync_point_(GetParam()) {}
|
||||
|
||||
MockEnv mock_env_;
|
||||
FaultInjectionTestEnv fault_injection_env_;
|
||||
LegacyFileSystemWrapper fs_;
|
||||
FileSystem* fs_;
|
||||
FileOptions file_options_;
|
||||
std::string sync_point_;
|
||||
};
|
||||
@@ -597,11 +595,11 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) {
|
||||
|
||||
Options options;
|
||||
options.cf_paths.emplace_back(
|
||||
test::PerThreadDBPath(&fault_injection_env_,
|
||||
"BlobFileBuilderIOErrorTest_IOError"),
|
||||
test::PerThreadDBPath(&mock_env_, "BlobFileBuilderIOErrorTest_IOError"),
|
||||
0);
|
||||
options.enable_blob_files = true;
|
||||
options.blob_file_size = value_size;
|
||||
options.env = &mock_env_;
|
||||
|
||||
ImmutableCFOptions immutable_cf_options(options);
|
||||
MutableCFOptions mutable_cf_options(options);
|
||||
@@ -615,15 +613,17 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &fault_injection_env_,
|
||||
&fs_, &immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
BlobFileBuilder builder(
|
||||
TestFileNumberGenerator(), &mock_env_, fs_, &immutable_cf_options,
|
||||
&mutable_cf_options, &file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint, nullptr /*IOTracer*/,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* /* arg */) {
|
||||
fault_injection_env_.SetFilesystemActive(false,
|
||||
Status::IOError(sync_point_));
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* arg) {
|
||||
Status* const s = static_cast<Status*>(arg);
|
||||
assert(s);
|
||||
|
||||
(*s) = Status::IOError(sync_point_);
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "trace_replay/io_tracer.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -21,13 +22,15 @@ BlobFileCache::BlobFileCache(Cache* cache,
|
||||
const ImmutableCFOptions* immutable_cf_options,
|
||||
const FileOptions* file_options,
|
||||
uint32_t column_family_id,
|
||||
HistogramImpl* blob_file_read_hist)
|
||||
HistogramImpl* blob_file_read_hist,
|
||||
const std::shared_ptr<IOTracer>& io_tracer)
|
||||
: cache_(cache),
|
||||
mutex_(kNumberOfMutexStripes, GetSliceNPHash64),
|
||||
mutex_(kNumberOfMutexStripes, kGetSliceNPHash64UnseededFnPtr),
|
||||
immutable_cf_options_(immutable_cf_options),
|
||||
file_options_(file_options),
|
||||
column_family_id_(column_family_id),
|
||||
blob_file_read_hist_(blob_file_read_hist) {
|
||||
blob_file_read_hist_(blob_file_read_hist),
|
||||
io_tracer_(io_tracer) {
|
||||
assert(cache_);
|
||||
assert(immutable_cf_options_);
|
||||
assert(file_options_);
|
||||
@@ -71,7 +74,7 @@ Status BlobFileCache::GetBlobFileReader(
|
||||
assert(file_options_);
|
||||
const Status s = BlobFileReader::Create(
|
||||
*immutable_cf_options_, *file_options_, column_family_id_,
|
||||
blob_file_read_hist_, blob_file_number, &reader);
|
||||
blob_file_read_hist_, blob_file_number, io_tracer_, &reader);
|
||||
if (!s.ok()) {
|
||||
RecordTick(statistics, NO_FILE_ERRORS);
|
||||
return s;
|
||||
|
||||
@@ -20,12 +20,14 @@ class HistogramImpl;
|
||||
class Status;
|
||||
class BlobFileReader;
|
||||
class Slice;
|
||||
class IOTracer;
|
||||
|
||||
class BlobFileCache {
|
||||
public:
|
||||
BlobFileCache(Cache* cache, const ImmutableCFOptions* immutable_cf_options,
|
||||
const FileOptions* file_options, uint32_t column_family_id,
|
||||
HistogramImpl* blob_file_read_hist);
|
||||
HistogramImpl* blob_file_read_hist,
|
||||
const std::shared_ptr<IOTracer>& io_tracer);
|
||||
|
||||
BlobFileCache(const BlobFileCache&) = delete;
|
||||
BlobFileCache& operator=(const BlobFileCache&) = delete;
|
||||
@@ -42,6 +44,7 @@ class BlobFileCache {
|
||||
const FileOptions* file_options_;
|
||||
uint32_t column_family_id_;
|
||||
HistogramImpl* blob_file_read_hist_;
|
||||
std::shared_ptr<IOTracer> io_tracer_;
|
||||
|
||||
static constexpr size_t kNumberOfMutexStripes = 1 << 7;
|
||||
};
|
||||
|
||||
@@ -46,10 +46,11 @@ void WriteBlobFile(uint32_t column_family_id,
|
||||
|
||||
constexpr Statistics* statistics = nullptr;
|
||||
constexpr bool use_fsync = false;
|
||||
constexpr bool do_flush = false;
|
||||
|
||||
BlobLogWriter blob_log_writer(std::move(file_writer),
|
||||
immutable_cf_options.env, statistics,
|
||||
blob_file_number, use_fsync);
|
||||
blob_file_number, use_fsync, do_flush);
|
||||
|
||||
constexpr bool has_ttl = false;
|
||||
constexpr ExpirationRange expiration_range;
|
||||
@@ -113,7 +114,7 @@ TEST_F(BlobFileCacheTest, GetBlobFileReader) {
|
||||
|
||||
BlobFileCache blob_file_cache(backing_cache.get(), &immutable_cf_options,
|
||||
&file_options, column_family_id,
|
||||
blob_file_read_hist);
|
||||
blob_file_read_hist, nullptr /*IOTracer*/);
|
||||
|
||||
// First try: reader should be opened and put in cache
|
||||
CacheHandleGuard<BlobFileReader> first;
|
||||
@@ -158,7 +159,7 @@ TEST_F(BlobFileCacheTest, GetBlobFileReader_Race) {
|
||||
|
||||
BlobFileCache blob_file_cache(backing_cache.get(), &immutable_cf_options,
|
||||
&file_options, column_family_id,
|
||||
blob_file_read_hist);
|
||||
blob_file_read_hist, nullptr /*IOTracer*/);
|
||||
|
||||
CacheHandleGuard<BlobFileReader> first;
|
||||
CacheHandleGuard<BlobFileReader> second;
|
||||
@@ -206,7 +207,7 @@ TEST_F(BlobFileCacheTest, GetBlobFileReader_IOError) {
|
||||
|
||||
BlobFileCache blob_file_cache(backing_cache.get(), &immutable_cf_options,
|
||||
&file_options, column_family_id,
|
||||
blob_file_read_hist);
|
||||
blob_file_read_hist, nullptr /*IOTracer*/);
|
||||
|
||||
// Note: there is no blob file with the below number
|
||||
constexpr uint64_t blob_file_number = 123;
|
||||
@@ -247,7 +248,7 @@ TEST_F(BlobFileCacheTest, GetBlobFileReader_CacheFull) {
|
||||
|
||||
BlobFileCache blob_file_cache(backing_cache.get(), &immutable_cf_options,
|
||||
&file_options, column_family_id,
|
||||
blob_file_read_hist);
|
||||
blob_file_read_hist, nullptr /*IOTracer*/);
|
||||
|
||||
// Insert into cache should fail since it has zero capacity and
|
||||
// strict_capacity_limit is set
|
||||
|
||||
@@ -24,6 +24,7 @@ Status BlobFileReader::Create(
|
||||
const ImmutableCFOptions& immutable_cf_options,
|
||||
const FileOptions& file_options, uint32_t column_family_id,
|
||||
HistogramImpl* blob_file_read_hist, uint64_t blob_file_number,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
std::unique_ptr<BlobFileReader>* blob_file_reader) {
|
||||
assert(blob_file_reader);
|
||||
assert(!*blob_file_reader);
|
||||
@@ -34,7 +35,7 @@ Status BlobFileReader::Create(
|
||||
{
|
||||
const Status s =
|
||||
OpenFile(immutable_cf_options, file_options, blob_file_read_hist,
|
||||
blob_file_number, &file_size, &file_reader);
|
||||
blob_file_number, io_tracer, &file_size, &file_reader);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -68,8 +69,8 @@ Status BlobFileReader::Create(
|
||||
Status BlobFileReader::OpenFile(
|
||||
const ImmutableCFOptions& immutable_cf_options,
|
||||
const FileOptions& file_opts, HistogramImpl* blob_file_read_hist,
|
||||
uint64_t blob_file_number, uint64_t* file_size,
|
||||
std::unique_ptr<RandomAccessFileReader>* file_reader) {
|
||||
uint64_t blob_file_number, const std::shared_ptr<IOTracer>& io_tracer,
|
||||
uint64_t* file_size, std::unique_ptr<RandomAccessFileReader>* file_reader) {
|
||||
assert(file_size);
|
||||
assert(file_reader);
|
||||
|
||||
@@ -117,10 +118,11 @@ Status BlobFileReader::OpenFile(
|
||||
}
|
||||
|
||||
file_reader->reset(new RandomAccessFileReader(
|
||||
std::move(file), blob_file_path, immutable_cf_options.env,
|
||||
std::shared_ptr<IOTracer>(), immutable_cf_options.statistics,
|
||||
BLOB_DB_BLOB_FILE_READ_MICROS, blob_file_read_hist,
|
||||
immutable_cf_options.rate_limiter, immutable_cf_options.listeners));
|
||||
std::move(file), blob_file_path,
|
||||
immutable_cf_options.env, io_tracer,
|
||||
immutable_cf_options.statistics, BLOB_DB_BLOB_FILE_READ_MICROS,
|
||||
blob_file_read_hist, immutable_cf_options.rate_limiter,
|
||||
immutable_cf_options.listeners));
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class BlobFileReader {
|
||||
uint32_t column_family_id,
|
||||
HistogramImpl* blob_file_read_hist,
|
||||
uint64_t blob_file_number,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
std::unique_ptr<BlobFileReader>* reader);
|
||||
|
||||
BlobFileReader(const BlobFileReader&) = delete;
|
||||
@@ -47,7 +48,9 @@ class BlobFileReader {
|
||||
static Status OpenFile(const ImmutableCFOptions& immutable_cf_options,
|
||||
const FileOptions& file_opts,
|
||||
HistogramImpl* blob_file_read_hist,
|
||||
uint64_t blob_file_number, uint64_t* file_size,
|
||||
uint64_t blob_file_number,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
uint64_t* file_size,
|
||||
std::unique_ptr<RandomAccessFileReader>* file_reader);
|
||||
|
||||
static Status ReadHeader(const RandomAccessFileReader* file_reader,
|
||||
|
||||
@@ -54,10 +54,11 @@ void WriteBlobFile(const ImmutableCFOptions& immutable_cf_options,
|
||||
|
||||
constexpr Statistics* statistics = nullptr;
|
||||
constexpr bool use_fsync = false;
|
||||
constexpr bool do_flush = false;
|
||||
|
||||
BlobLogWriter blob_log_writer(std::move(file_writer),
|
||||
immutable_cf_options.env, statistics,
|
||||
blob_file_number, use_fsync);
|
||||
blob_file_number, use_fsync, do_flush);
|
||||
|
||||
BlobLogHeader header(column_family_id, compression_type, has_ttl,
|
||||
expiration_range_header);
|
||||
@@ -141,9 +142,9 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
|
||||
std::unique_ptr<BlobFileReader> reader;
|
||||
|
||||
ASSERT_OK(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader));
|
||||
ASSERT_OK(BlobFileReader::Create(
|
||||
immutable_cf_options, FileOptions(), column_family_id,
|
||||
blob_file_read_hist, blob_file_number, nullptr /*IOTracer*/, &reader));
|
||||
|
||||
// Make sure the blob can be retrieved with and without checksum verification
|
||||
ReadOptions read_options;
|
||||
@@ -263,10 +264,11 @@ TEST_F(BlobFileReaderTest, Malformed) {
|
||||
|
||||
constexpr Statistics* statistics = nullptr;
|
||||
constexpr bool use_fsync = false;
|
||||
constexpr bool do_flush = false;
|
||||
|
||||
BlobLogWriter blob_log_writer(std::move(file_writer),
|
||||
immutable_cf_options.env, statistics,
|
||||
blob_file_number, use_fsync);
|
||||
blob_file_number, use_fsync, do_flush);
|
||||
|
||||
BlobLogHeader header(column_family_id, kNoCompression, has_ttl,
|
||||
expiration_range);
|
||||
@@ -280,7 +282,8 @@ TEST_F(BlobFileReaderTest, Malformed) {
|
||||
|
||||
ASSERT_TRUE(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader)
|
||||
blob_file_number, nullptr /*IOTracer*/,
|
||||
&reader)
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
@@ -313,7 +316,8 @@ TEST_F(BlobFileReaderTest, TTL) {
|
||||
|
||||
ASSERT_TRUE(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader)
|
||||
blob_file_number, nullptr /*IOTracer*/,
|
||||
&reader)
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
@@ -351,7 +355,8 @@ TEST_F(BlobFileReaderTest, ExpirationRangeInHeader) {
|
||||
|
||||
ASSERT_TRUE(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader)
|
||||
blob_file_number, nullptr /*IOTracer*/,
|
||||
&reader)
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
@@ -389,7 +394,8 @@ TEST_F(BlobFileReaderTest, ExpirationRangeInFooter) {
|
||||
|
||||
ASSERT_TRUE(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader)
|
||||
blob_file_number, nullptr /*IOTracer*/,
|
||||
&reader)
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
@@ -427,7 +433,7 @@ TEST_F(BlobFileReaderTest, IncorrectColumnFamily) {
|
||||
ASSERT_TRUE(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
incorrect_column_family_id,
|
||||
blob_file_read_hist, blob_file_number,
|
||||
&reader)
|
||||
nullptr /*IOTracer*/, &reader)
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
@@ -458,9 +464,9 @@ TEST_F(BlobFileReaderTest, BlobCRCError) {
|
||||
|
||||
std::unique_ptr<BlobFileReader> reader;
|
||||
|
||||
ASSERT_OK(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader));
|
||||
ASSERT_OK(BlobFileReader::Create(
|
||||
immutable_cf_options, FileOptions(), column_family_id,
|
||||
blob_file_read_hist, blob_file_number, nullptr /*IOTracer*/, &reader));
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BlobFileReader::VerifyBlob:CheckBlobCRC", [](void* arg) {
|
||||
@@ -514,9 +520,9 @@ TEST_F(BlobFileReaderTest, Compression) {
|
||||
|
||||
std::unique_ptr<BlobFileReader> reader;
|
||||
|
||||
ASSERT_OK(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader));
|
||||
ASSERT_OK(BlobFileReader::Create(
|
||||
immutable_cf_options, FileOptions(), column_family_id,
|
||||
blob_file_read_hist, blob_file_number, nullptr /*IOTracer*/, &reader));
|
||||
|
||||
// Make sure the blob can be retrieved with and without checksum verification
|
||||
ReadOptions read_options;
|
||||
@@ -574,9 +580,9 @@ TEST_F(BlobFileReaderTest, UncompressionError) {
|
||||
|
||||
std::unique_ptr<BlobFileReader> reader;
|
||||
|
||||
ASSERT_OK(BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader));
|
||||
ASSERT_OK(BlobFileReader::Create(
|
||||
immutable_cf_options, FileOptions(), column_family_id,
|
||||
blob_file_read_hist, blob_file_number, nullptr /*IOTracer*/, &reader));
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BlobFileReader::UncompressBlobIfNeeded:TamperWithResult", [](void* arg) {
|
||||
@@ -659,9 +665,9 @@ TEST_P(BlobFileReaderIOErrorTest, IOError) {
|
||||
|
||||
std::unique_ptr<BlobFileReader> reader;
|
||||
|
||||
const Status s = BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader);
|
||||
const Status s = BlobFileReader::Create(
|
||||
immutable_cf_options, FileOptions(), column_family_id,
|
||||
blob_file_read_hist, blob_file_number, nullptr /*IOTracer*/, &reader);
|
||||
|
||||
const bool fail_during_create =
|
||||
(sync_point_ != "BlobFileReader::GetBlob:ReadFromFile");
|
||||
@@ -739,9 +745,9 @@ TEST_P(BlobFileReaderDecodingErrorTest, DecodingError) {
|
||||
|
||||
std::unique_ptr<BlobFileReader> reader;
|
||||
|
||||
const Status s = BlobFileReader::Create(immutable_cf_options, FileOptions(),
|
||||
column_family_id, blob_file_read_hist,
|
||||
blob_file_number, &reader);
|
||||
const Status s = BlobFileReader::Create(
|
||||
immutable_cf_options, FileOptions(), column_family_id,
|
||||
blob_file_read_hist, blob_file_number, nullptr /*IOTracer*/, &reader);
|
||||
|
||||
const bool fail_during_create =
|
||||
sync_point_ != "BlobFileReader::GetBlob:TamperWithResult";
|
||||
|
||||
@@ -20,13 +20,15 @@ namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
BlobLogWriter::BlobLogWriter(std::unique_ptr<WritableFileWriter>&& dest,
|
||||
Env* env, Statistics* statistics,
|
||||
uint64_t log_number, bool use_fs, uint64_t boffset)
|
||||
uint64_t log_number, bool use_fs, bool do_flush,
|
||||
uint64_t boffset)
|
||||
: dest_(std::move(dest)),
|
||||
env_(env),
|
||||
statistics_(statistics),
|
||||
log_number_(log_number),
|
||||
block_offset_(boffset),
|
||||
use_fsync_(use_fs),
|
||||
do_flush_(do_flush),
|
||||
last_elem_type_(kEtNone) {}
|
||||
|
||||
BlobLogWriter::~BlobLogWriter() = default;
|
||||
@@ -49,7 +51,9 @@ Status BlobLogWriter::WriteHeader(BlobLogHeader& header) {
|
||||
Status s = dest_->Append(Slice(str));
|
||||
if (s.ok()) {
|
||||
block_offset_ += str.size();
|
||||
s = dest_->Flush();
|
||||
if (do_flush_) {
|
||||
s = dest_->Flush();
|
||||
}
|
||||
}
|
||||
last_elem_type_ = kEtFileHdr;
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_WRITTEN,
|
||||
@@ -152,7 +156,7 @@ Status BlobLogWriter::EmitPhysicalRecord(const std::string& headerbuf,
|
||||
if (s.ok()) {
|
||||
s = dest_->Append(val);
|
||||
}
|
||||
if (s.ok()) {
|
||||
if (do_flush_ && s.ok()) {
|
||||
s = dest_->Flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class BlobLogWriter {
|
||||
// "*dest" must remain live while this BlobLogWriter is in use.
|
||||
BlobLogWriter(std::unique_ptr<WritableFileWriter>&& dest, Env* env,
|
||||
Statistics* statistics, uint64_t log_number, bool use_fsync,
|
||||
uint64_t boffset = 0);
|
||||
bool do_flush, uint64_t boffset = 0);
|
||||
// No copying allowed
|
||||
BlobLogWriter(const BlobLogWriter&) = delete;
|
||||
BlobLogWriter& operator=(const BlobLogWriter&) = delete;
|
||||
@@ -74,6 +74,7 @@ class BlobLogWriter {
|
||||
uint64_t log_number_;
|
||||
uint64_t block_offset_; // Current offset in block
|
||||
bool use_fsync_;
|
||||
bool do_flush_;
|
||||
|
||||
public:
|
||||
enum ElemType { kEtNone, kEtFileHdr, kEtRecord, kEtFileFooter };
|
||||
|
||||
@@ -210,6 +210,63 @@ TEST_F(DBBlobBasicTest, GetBlob_IndexWithInvalidFileNumber) {
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBBlobBasicTest, GenerateIOTracing) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
std::string trace_file = dbname_ + "/io_trace_file";
|
||||
|
||||
Reopen(options);
|
||||
{
|
||||
// Create IO trace file
|
||||
std::unique_ptr<TraceWriter> trace_writer;
|
||||
ASSERT_OK(
|
||||
NewFileTraceWriter(env_, EnvOptions(), trace_file, &trace_writer));
|
||||
ASSERT_OK(db_->StartIOTrace(env_, TraceOptions(), std::move(trace_writer)));
|
||||
|
||||
constexpr char key[] = "key";
|
||||
constexpr char blob_value[] = "blob_value";
|
||||
|
||||
ASSERT_OK(Put(key, blob_value));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(Get(key), blob_value);
|
||||
|
||||
ASSERT_OK(db_->EndIOTrace());
|
||||
ASSERT_OK(env_->FileExists(trace_file));
|
||||
}
|
||||
{
|
||||
// Parse trace file to check file opertions related to blob files are
|
||||
// recorded.
|
||||
std::unique_ptr<TraceReader> trace_reader;
|
||||
ASSERT_OK(
|
||||
NewFileTraceReader(env_, EnvOptions(), trace_file, &trace_reader));
|
||||
IOTraceReader reader(std::move(trace_reader));
|
||||
|
||||
IOTraceHeader header;
|
||||
ASSERT_OK(reader.ReadHeader(&header));
|
||||
ASSERT_EQ(kMajorVersion, static_cast<int>(header.rocksdb_major_version));
|
||||
ASSERT_EQ(kMinorVersion, static_cast<int>(header.rocksdb_minor_version));
|
||||
|
||||
// Read records.
|
||||
int blob_files_op_count = 0;
|
||||
Status status;
|
||||
while (true) {
|
||||
IOTraceRecord record;
|
||||
status = reader.ReadIOOp(&record);
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
if (record.file_name.find("blob") != std::string::npos) {
|
||||
blob_files_op_count++;
|
||||
}
|
||||
}
|
||||
// Assuming blob files will have Append, Close and then Read operations.
|
||||
ASSERT_GT(blob_files_op_count, 2);
|
||||
}
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
class DBBlobBasicIOErrorTest : public DBBlobBasicTest,
|
||||
public testing::WithParamInterface<std::string> {
|
||||
protected:
|
||||
|
||||
+6
-4
@@ -28,6 +28,7 @@
|
||||
#include "file/writable_file_writer.h"
|
||||
#include "monitoring/iostats_context_imp.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
@@ -147,13 +148,14 @@ Status BuildTable(
|
||||
file_checksum, file_checksum_func_name);
|
||||
return s;
|
||||
}
|
||||
FileTypeSet tmp_set = ioptions.checksum_handoff_file_types;
|
||||
file->SetIOPriority(io_priority);
|
||||
file->SetWriteLifeTimeHint(write_hint);
|
||||
|
||||
file_writer.reset(new WritableFileWriter(
|
||||
std::move(file), fname, file_options, env, io_tracer,
|
||||
ioptions.statistics, ioptions.listeners,
|
||||
ioptions.file_checksum_gen_factory));
|
||||
ioptions.file_checksum_gen_factory,
|
||||
tmp_set.Contains(FileType::kTableFile)));
|
||||
|
||||
builder = NewTableBuilder(
|
||||
ioptions, mutable_cf_options, internal_comparator,
|
||||
@@ -175,8 +177,8 @@ Status BuildTable(
|
||||
? new BlobFileBuilder(versions, env, fs, &ioptions,
|
||||
&mutable_cf_options, &file_options, job_id,
|
||||
column_family_id, column_family_name,
|
||||
io_priority, write_hint, &blob_file_paths,
|
||||
blob_file_additions)
|
||||
io_priority, write_hint, io_tracer,
|
||||
&blob_file_paths, blob_file_additions)
|
||||
: nullptr);
|
||||
|
||||
CompactionIterator c_iter(
|
||||
|
||||
@@ -1388,34 +1388,39 @@ char* rocksdb_property_value_cf(
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_approximate_sizes(
|
||||
rocksdb_t* db,
|
||||
int num_ranges,
|
||||
const char* const* range_start_key, const size_t* range_start_key_len,
|
||||
const char* const* range_limit_key, const size_t* range_limit_key_len,
|
||||
uint64_t* sizes) {
|
||||
void rocksdb_approximate_sizes(rocksdb_t* db, int num_ranges,
|
||||
const char* const* range_start_key,
|
||||
const size_t* range_start_key_len,
|
||||
const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len,
|
||||
uint64_t* sizes, char** errptr) {
|
||||
Range* ranges = new Range[num_ranges];
|
||||
for (int i = 0; i < num_ranges; i++) {
|
||||
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);
|
||||
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);
|
||||
}
|
||||
db->rep->GetApproximateSizes(ranges, num_ranges, sizes);
|
||||
Status s = db->rep->GetApproximateSizes(ranges, num_ranges, sizes);
|
||||
if (!s.ok()) {
|
||||
SaveError(errptr, s);
|
||||
}
|
||||
delete[] ranges;
|
||||
}
|
||||
|
||||
void rocksdb_approximate_sizes_cf(
|
||||
rocksdb_t* db,
|
||||
rocksdb_column_family_handle_t* column_family,
|
||||
int num_ranges,
|
||||
const char* const* range_start_key, const size_t* range_start_key_len,
|
||||
const char* const* range_limit_key, const size_t* range_limit_key_len,
|
||||
uint64_t* sizes) {
|
||||
rocksdb_t* db, rocksdb_column_family_handle_t* column_family,
|
||||
int num_ranges, const char* const* range_start_key,
|
||||
const size_t* range_start_key_len, const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len, uint64_t* sizes, char** errptr) {
|
||||
Range* ranges = new Range[num_ranges];
|
||||
for (int i = 0; i < num_ranges; i++) {
|
||||
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);
|
||||
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);
|
||||
}
|
||||
db->rep->GetApproximateSizes(column_family->rep, ranges, num_ranges, sizes);
|
||||
Status s = db->rep->GetApproximateSizes(column_family->rep, ranges,
|
||||
num_ranges, sizes);
|
||||
if (!s.ok()) {
|
||||
SaveError(errptr, s);
|
||||
}
|
||||
delete[] ranges;
|
||||
}
|
||||
|
||||
@@ -2769,6 +2774,14 @@ void rocksdb_options_set_bottommost_compression_options_zstd_max_train_bytes(
|
||||
opt->rep.bottommost_compression_opts.enabled = enabled;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_bottommost_compression_options_max_dict_buffer_bytes(
|
||||
rocksdb_options_t* opt, uint64_t max_dict_buffer_bytes,
|
||||
unsigned char enabled) {
|
||||
opt->rep.bottommost_compression_opts.max_dict_buffer_bytes =
|
||||
max_dict_buffer_bytes;
|
||||
opt->rep.bottommost_compression_opts.enabled = enabled;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_compression_options(rocksdb_options_t* opt, int w_bits,
|
||||
int level, int strategy,
|
||||
int max_dict_bytes) {
|
||||
@@ -2783,6 +2796,11 @@ void rocksdb_options_set_compression_options_zstd_max_train_bytes(
|
||||
opt->rep.compression_opts.zstd_max_train_bytes = zstd_max_train_bytes;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_prefix_extractor(
|
||||
rocksdb_options_t* opt, rocksdb_slicetransform_t* prefix_extractor) {
|
||||
opt->rep.prefix_extractor.reset(prefix_extractor);
|
||||
@@ -3931,6 +3949,25 @@ unsigned char rocksdb_readoptions_get_ignore_range_deletions(
|
||||
return opt->rep.ignore_range_deletions;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
extern ROCKSDB_LIBRARY_API uint64_t
|
||||
rocksdb_readoptions_get_io_timeout(rocksdb_readoptions_t* opt) {
|
||||
return opt->rep.io_timeout.count();
|
||||
}
|
||||
|
||||
rocksdb_writeoptions_t* rocksdb_writeoptions_create() {
|
||||
return new rocksdb_writeoptions_t;
|
||||
}
|
||||
|
||||
+9
-1
@@ -988,7 +988,9 @@ int main(int argc, char** argv) {
|
||||
&err);
|
||||
CheckNoError(err);
|
||||
}
|
||||
rocksdb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);
|
||||
rocksdb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes,
|
||||
&err);
|
||||
CheckNoError(err);
|
||||
CheckCondition(sizes[0] > 0);
|
||||
CheckCondition(sizes[1] > 0);
|
||||
}
|
||||
@@ -2279,6 +2281,12 @@ int main(int argc, char** argv) {
|
||||
rocksdb_readoptions_set_ignore_range_deletions(ro, 1);
|
||||
CheckCondition(1 == rocksdb_readoptions_get_ignore_range_deletions(ro));
|
||||
|
||||
rocksdb_readoptions_set_deadline(ro, 300);
|
||||
CheckCondition(300 == rocksdb_readoptions_get_deadline(ro));
|
||||
|
||||
rocksdb_readoptions_set_io_timeout(ro, 400);
|
||||
CheckCondition(400 == rocksdb_readoptions_get_io_timeout(ro));
|
||||
|
||||
rocksdb_readoptions_destroy(ro);
|
||||
}
|
||||
|
||||
|
||||
+14
-11
@@ -33,6 +33,7 @@
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "table/merging_iterator.h"
|
||||
#include "util/autovector.h"
|
||||
@@ -335,7 +336,9 @@ ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
// was not used)
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(db_options.sst_file_manager.get());
|
||||
for (size_t i = 0; i < result.cf_paths.size(); i++) {
|
||||
DeleteScheduler::CleanupDirectory(db_options.env, sfm, result.cf_paths[i].path);
|
||||
DeleteScheduler::CleanupDirectory(db_options.env, sfm,
|
||||
result.cf_paths[i].path)
|
||||
.PermitUncheckedError();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -560,7 +563,7 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
block_cache_tracer, io_tracer));
|
||||
blob_file_cache_.reset(
|
||||
new BlobFileCache(_table_cache, ioptions(), soptions(), id_,
|
||||
internal_stats_->GetBlobFileReadHist()));
|
||||
internal_stats_->GetBlobFileReadHist(), io_tracer));
|
||||
|
||||
if (ioptions_.compaction_style == kCompactionStyleLevel) {
|
||||
compaction_picker_.reset(
|
||||
@@ -1353,19 +1356,19 @@ Status ColumnFamilyData::ValidateOptions(
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
Status ColumnFamilyData::SetOptions(
|
||||
const DBOptions& db_options,
|
||||
const DBOptions& db_opts,
|
||||
const std::unordered_map<std::string, std::string>& options_map) {
|
||||
MutableCFOptions new_mutable_cf_options;
|
||||
Status s =
|
||||
GetMutableOptionsFromStrings(mutable_cf_options_, options_map,
|
||||
ioptions_.info_log, &new_mutable_cf_options);
|
||||
ColumnFamilyOptions cf_opts =
|
||||
BuildColumnFamilyOptions(initial_cf_options_, mutable_cf_options_);
|
||||
ConfigOptions config_opts;
|
||||
config_opts.mutable_options_only = true;
|
||||
Status s = GetColumnFamilyOptionsFromMap(config_opts, cf_opts, options_map,
|
||||
&cf_opts);
|
||||
if (s.ok()) {
|
||||
ColumnFamilyOptions cf_options =
|
||||
BuildColumnFamilyOptions(initial_cf_options_, new_mutable_cf_options);
|
||||
s = ValidateOptions(db_options, cf_options);
|
||||
s = ValidateOptions(db_opts, cf_opts);
|
||||
}
|
||||
if (s.ok()) {
|
||||
mutable_cf_options_ = new_mutable_cf_options;
|
||||
mutable_cf_options_ = MutableCFOptions(cf_opts);
|
||||
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
||||
}
|
||||
return s;
|
||||
|
||||
+29
-35
@@ -73,7 +73,7 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
db_options_.create_if_missing = true;
|
||||
db_options_.fail_if_options_file_error = true;
|
||||
db_options_.env = env_;
|
||||
DestroyDB(dbname_, Options(db_options_, column_family_options_));
|
||||
EXPECT_OK(DestroyDB(dbname_, Options(db_options_, column_family_options_)));
|
||||
}
|
||||
|
||||
~ColumnFamilyTestBase() override {
|
||||
@@ -187,8 +187,8 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
names_.clear();
|
||||
for (size_t i = 0; i < cf.size(); ++i) {
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]));
|
||||
column_families.emplace_back(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]);
|
||||
names_.push_back(cf[i]);
|
||||
}
|
||||
return DB::Open(db_options_, dbname_, column_families, &handles_, &db_);
|
||||
@@ -199,8 +199,8 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
names_.clear();
|
||||
for (size_t i = 0; i < cf.size(); ++i) {
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]));
|
||||
column_families.emplace_back(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]);
|
||||
names_.push_back(cf[i]);
|
||||
}
|
||||
return DB::OpenForReadOnly(db_options_, dbname_, column_families, &handles_,
|
||||
@@ -653,8 +653,8 @@ TEST_P(FlushEmptyCFTestWithParam, FlushEmptyCFTest) {
|
||||
// after flushing file B is deleted. At the same time, the min log number of
|
||||
// default CF is not written to manifest. Log file A still remains.
|
||||
// Flushed to SST file Y.
|
||||
Flush(1);
|
||||
Flush(0);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Flush(0));
|
||||
ASSERT_OK(Put(1, "bar", "v3")); // seqID 4
|
||||
ASSERT_OK(Put(1, "foo", "v4")); // seqID 5
|
||||
ASSERT_OK(db_->FlushWAL(/*sync=*/false));
|
||||
@@ -708,15 +708,15 @@ TEST_P(FlushEmptyCFTestWithParam, FlushEmptyCFTest2) {
|
||||
// and is set to current. Both CFs' min log number is set to file C so after
|
||||
// flushing file B is deleted. Log file A still remains.
|
||||
// Flushed to SST file Y.
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(0, "bar", "v2")); // seqID 4
|
||||
ASSERT_OK(Put(2, "bar", "v2")); // seqID 5
|
||||
ASSERT_OK(Put(1, "bar", "v3")); // seqID 6
|
||||
// Flushing all column families. This forces all CFs' min log to current. This
|
||||
// is written to the manifest file. Log file C is cleared.
|
||||
Flush(0);
|
||||
Flush(1);
|
||||
Flush(2);
|
||||
ASSERT_OK(Flush(0));
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Flush(2));
|
||||
// Write to log file D
|
||||
ASSERT_OK(Put(1, "bar", "v4")); // seqID 7
|
||||
ASSERT_OK(Put(1, "bar", "v5")); // seqID 8
|
||||
@@ -898,9 +898,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> old_files;
|
||||
ASSERT_OK(env_->GetChildren(backup_logs, &old_files));
|
||||
for (auto& file : old_files) {
|
||||
if (file != "." && file != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
|
||||
column_family_options_.merge_operator =
|
||||
@@ -929,9 +927,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> logs;
|
||||
ASSERT_OK(env_->GetChildren(db_options_.wal_dir, &logs));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(db_options_.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
CopyFile(db_options_.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
|
||||
// recover the DB
|
||||
@@ -956,9 +952,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
|
||||
if (iter == 0) {
|
||||
// copy the logs from backup back to wal dir
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, db_options_.wal_dir + "/" + log);
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, db_options_.wal_dir + "/" + log);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -985,7 +979,7 @@ TEST_P(ColumnFamilyTest, FlushTest) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
uint64_t max_total_in_memory_state =
|
||||
MaxTotalInMemoryState();
|
||||
Flush(i);
|
||||
ASSERT_OK(Flush(i));
|
||||
AssertMaxTotalInMemoryState(max_total_in_memory_state);
|
||||
}
|
||||
ASSERT_OK(Put(1, "foofoo", "bar"));
|
||||
@@ -1093,7 +1087,7 @@ TEST_P(ColumnFamilyTest, CrashAfterFlush) {
|
||||
ASSERT_OK(batch.Put(handles_[0], Slice("foo"), Slice("bar")));
|
||||
ASSERT_OK(batch.Put(handles_[1], Slice("foo"), Slice("bar")));
|
||||
ASSERT_OK(db_->Write(WriteOptions(), &batch));
|
||||
Flush(0);
|
||||
ASSERT_OK(Flush(0));
|
||||
fault_env->SetFilesystemActive(false);
|
||||
|
||||
std::vector<std::string> names;
|
||||
@@ -1103,7 +1097,7 @@ TEST_P(ColumnFamilyTest, CrashAfterFlush) {
|
||||
}
|
||||
}
|
||||
Close();
|
||||
fault_env->DropUnsyncedFileData();
|
||||
ASSERT_OK(fault_env->DropUnsyncedFileData());
|
||||
fault_env->ResetState();
|
||||
Open(names, {});
|
||||
|
||||
@@ -2236,7 +2230,7 @@ TEST_P(ColumnFamilyTest, FlushStaleColumnFamilies) {
|
||||
// files for column family [one], because it's empty
|
||||
AssertCountLiveFiles(4);
|
||||
|
||||
Flush(0);
|
||||
ASSERT_OK(Flush(0));
|
||||
ASSERT_EQ(0, dbfull()->TEST_total_log_size());
|
||||
Close();
|
||||
}
|
||||
@@ -3040,7 +3034,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile1) {
|
||||
Iterator* it = db_->NewIterator(ReadOptions(), handles_[1]);
|
||||
ASSERT_OK(it->status());
|
||||
// A flush will make `it` hold the last reference of its super version.
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(0, "fodor", "mirko"));
|
||||
@@ -3093,7 +3087,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
|
||||
Iterator* it = db_->NewIterator(ro, handles_[1]);
|
||||
ASSERT_OK(it->status());
|
||||
// A flush will make `it` hold the last reference of its super version.
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(0, "fodor", "mirko"));
|
||||
@@ -3147,7 +3141,7 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
|
||||
CreateColumnFamilies({"one"});
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(1, "fodar2", "mirko"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
// Create an iterator holding the current super version, as well as
|
||||
// the SST file just flushed.
|
||||
@@ -3159,7 +3153,7 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
|
||||
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(1, "fodar2", "mirko"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
WaitForCompaction();
|
||||
|
||||
@@ -3232,9 +3226,9 @@ TEST_P(ColumnFamilyTest, LogSyncConflictFlush) {
|
||||
ROCKSDB_NAMESPACE::port::Thread thread([&] { ASSERT_OK(db_->SyncWAL()); });
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::LogSyncConflictFlush:1");
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::LogSyncConflictFlush:2");
|
||||
|
||||
@@ -3256,7 +3250,7 @@ TEST_P(ColumnFamilyTest, DISABLED_LogTruncationTest) {
|
||||
Build(0, 100);
|
||||
|
||||
// Flush the 0th column family to force a roll of the wal log
|
||||
Flush(0);
|
||||
ASSERT_OK(Flush(0));
|
||||
|
||||
// Add some more entries
|
||||
Build(100, 100);
|
||||
@@ -3332,14 +3326,14 @@ TEST_P(ColumnFamilyTest, DefaultCfPathsTest) {
|
||||
|
||||
// Fill Column family 1.
|
||||
PutRandomData(1, 100, 100);
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
ASSERT_EQ(1, GetSstFileCount(cf_opt1.cf_paths[0].path));
|
||||
ASSERT_EQ(0, GetSstFileCount(dbname_));
|
||||
|
||||
// Fill column family 2
|
||||
PutRandomData(2, 100, 100);
|
||||
Flush(2);
|
||||
ASSERT_OK(Flush(2));
|
||||
|
||||
// SST from Column family 2 should be generated in
|
||||
// db_paths which is dbname_ in this case.
|
||||
@@ -3358,14 +3352,14 @@ TEST_P(ColumnFamilyTest, MultipleCFPathsTest) {
|
||||
Reopen({ColumnFamilyOptions(), cf_opt1, cf_opt2});
|
||||
|
||||
PutRandomData(1, 100, 100, true /* save */);
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
// Check that files are generated in appropriate paths.
|
||||
ASSERT_EQ(1, GetSstFileCount(cf_opt1.cf_paths[0].path));
|
||||
ASSERT_EQ(0, GetSstFileCount(dbname_));
|
||||
|
||||
PutRandomData(2, 100, 100, true /* save */);
|
||||
Flush(2);
|
||||
ASSERT_OK(Flush(2));
|
||||
|
||||
ASSERT_EQ(1, GetSstFileCount(cf_opt2.cf_paths[0].path));
|
||||
ASSERT_EQ(0, GetSstFileCount(dbname_));
|
||||
|
||||
+28
-25
@@ -91,9 +91,9 @@ TEST_F(CompactFilesTest, L0ConflictsFiles) {
|
||||
// create couple files
|
||||
// Background compaction starts and waits in BackgroundCallCompaction:0
|
||||
for (int i = 0; i < kLevel0Trigger * 4; ++i) {
|
||||
db->Put(WriteOptions(), ToString(i), "");
|
||||
db->Put(WriteOptions(), ToString(100 - i), "");
|
||||
db->Flush(FlushOptions());
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i), ""));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(100 - i), ""));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
ROCKSDB_NAMESPACE::ColumnFamilyMetaData meta;
|
||||
@@ -138,18 +138,18 @@ TEST_F(CompactFilesTest, ObsoleteFiles) {
|
||||
DB* db = nullptr;
|
||||
DestroyDB(db_name_, options);
|
||||
Status s = DB::Open(options, db_name_, &db);
|
||||
assert(s.ok());
|
||||
assert(db);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_NE(db, nullptr);
|
||||
|
||||
// create couple files
|
||||
for (int i = 1000; i < 2000; ++i) {
|
||||
db->Put(WriteOptions(), ToString(i),
|
||||
std::string(kWriteBufferSize / 10, 'a' + (i % 26)));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(kWriteBufferSize / 10, 'a' + (i % 26))));
|
||||
}
|
||||
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
ASSERT_OK(db->CompactFiles(CompactionOptions(), l0_files, 1));
|
||||
static_cast_with_check<DBImpl>(db)->TEST_WaitForCompact();
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForCompact());
|
||||
|
||||
// verify all compaction input files are deleted
|
||||
for (auto fname : l0_files) {
|
||||
@@ -182,15 +182,17 @@ TEST_F(CompactFilesTest, NotCutOutputOnLevel0) {
|
||||
|
||||
// create couple files
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
db->Put(WriteOptions(), ToString(i), std::string(1000, 'a' + (i % 26)));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(1000, 'a' + (i % 26))));
|
||||
}
|
||||
static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable());
|
||||
auto l0_files_1 = collector->GetFlushedFiles();
|
||||
collector->ClearFlushedFiles();
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
db->Put(WriteOptions(), ToString(i), std::string(1000, 'a' + (i % 26)));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(1000, 'a' + (i % 26))));
|
||||
}
|
||||
static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable());
|
||||
auto l0_files_2 = collector->GetFlushedFiles();
|
||||
ASSERT_OK(db->CompactFiles(CompactionOptions(), l0_files_1, 0));
|
||||
ASSERT_OK(db->CompactFiles(CompactionOptions(), l0_files_2, 0));
|
||||
@@ -213,13 +215,13 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
DB* db = nullptr;
|
||||
DestroyDB(db_name_, options);
|
||||
Status s = DB::Open(options, db_name_, &db);
|
||||
assert(s.ok());
|
||||
ASSERT_OK(s);
|
||||
assert(db);
|
||||
|
||||
// Create 5 files.
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
db->Put(WriteOptions(), "key" + ToString(i), "value");
|
||||
db->Flush(FlushOptions());
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key" + ToString(i), "value"));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
@@ -237,8 +239,8 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
|
||||
// In the meantime flush another file.
|
||||
TEST_SYNC_POINT("CompactFilesTest.CapturingPendingFiles:0");
|
||||
db->Put(WriteOptions(), "key5", "value");
|
||||
db->Flush(FlushOptions());
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key5", "value"));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
TEST_SYNC_POINT("CompactFilesTest.CapturingPendingFiles:1");
|
||||
|
||||
compaction_thread.join();
|
||||
@@ -249,7 +251,7 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
|
||||
// Make sure we can reopen the DB.
|
||||
s = DB::Open(options, db_name_, &db);
|
||||
ASSERT_TRUE(s.ok());
|
||||
ASSERT_OK(s);
|
||||
assert(db);
|
||||
delete db;
|
||||
}
|
||||
@@ -293,8 +295,8 @@ TEST_F(CompactFilesTest, CompactionFilterWithGetSv) {
|
||||
cf->SetDB(db);
|
||||
|
||||
// Write one L0 file
|
||||
db->Put(WriteOptions(), "K1", "V1");
|
||||
db->Flush(FlushOptions());
|
||||
ASSERT_OK(db->Put(WriteOptions(), "K1", "V1"));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
// Compact all L0 files using CompactFiles
|
||||
ROCKSDB_NAMESPACE::ColumnFamilyMetaData meta;
|
||||
@@ -337,8 +339,8 @@ TEST_F(CompactFilesTest, SentinelCompressionType) {
|
||||
DB* db = nullptr;
|
||||
ASSERT_OK(DB::Open(options, db_name_, &db));
|
||||
|
||||
db->Put(WriteOptions(), "key", "val");
|
||||
db->Flush(FlushOptions());
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key", "val"));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
ASSERT_EQ(1, l0_files.size());
|
||||
@@ -377,14 +379,15 @@ TEST_F(CompactFilesTest, GetCompactionJobInfo) {
|
||||
DB* db = nullptr;
|
||||
DestroyDB(db_name_, options);
|
||||
Status s = DB::Open(options, db_name_, &db);
|
||||
assert(s.ok());
|
||||
ASSERT_OK(s);
|
||||
assert(db);
|
||||
|
||||
// create couple files
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
db->Put(WriteOptions(), ToString(i), std::string(1000, 'a' + (i % 26)));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(1000, 'a' + (i % 26))));
|
||||
}
|
||||
static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable());
|
||||
auto l0_files_1 = collector->GetFlushedFiles();
|
||||
CompactionOptions co;
|
||||
co.compression = CompressionType::kLZ4Compression;
|
||||
|
||||
@@ -82,6 +82,11 @@ class CompactedDBImpl : public DBImpl {
|
||||
ColumnFamilyHandle* /*column_family*/) override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
|
||||
virtual Status SyncWAL() override {
|
||||
return Status::NotSupported("Not supported in compacted db mode.");
|
||||
}
|
||||
|
||||
using DB::IngestExternalFile;
|
||||
virtual Status IngestExternalFile(
|
||||
ColumnFamilyHandle* /*column_family*/,
|
||||
|
||||
@@ -422,8 +422,8 @@ void CompactionIterator::NextFromInput() {
|
||||
// In the previous iteration we encountered a single delete that we could
|
||||
// not compact out. We will keep this Put, but can drop it's data.
|
||||
// (See Optimization 3, below.)
|
||||
assert(ikey_.type == kTypeValue);
|
||||
if (ikey_.type != kTypeValue) {
|
||||
assert(ikey_.type == kTypeValue || ikey_.type == kTypeBlobIndex);
|
||||
if (ikey_.type != kTypeValue && ikey_.type != kTypeBlobIndex) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"Unexpected key type %d for compaction output",
|
||||
ikey_.type);
|
||||
@@ -436,6 +436,11 @@ void CompactionIterator::NextFromInput() {
|
||||
current_user_key_snapshot_, last_snapshot);
|
||||
}
|
||||
|
||||
if (ikey_.type == kTypeBlobIndex) {
|
||||
ikey_.type = kTypeValue;
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
}
|
||||
|
||||
value_.clear();
|
||||
valid_ = true;
|
||||
clear_and_output_next_key_ = false;
|
||||
|
||||
@@ -970,6 +970,21 @@ TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
2 /*earliest_write_conflict_snapshot*/);
|
||||
}
|
||||
|
||||
// Same as above but with a blob index. In addition to the value getting
|
||||
// trimmed, the type of the KV is changed to kTypeValue.
|
||||
TEST_F(CompactionIteratorWithSnapshotCheckerTest,
|
||||
KeepSingleDeletionForWriteConflictChecking_BlobIndex) {
|
||||
AddSnapshot(2, 0);
|
||||
RunTest({test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeBlobIndex)},
|
||||
{"", "fake_blob_index"},
|
||||
{test::KeyStr("a", 2, kTypeSingleDeletion),
|
||||
test::KeyStr("a", 1, kTypeValue)},
|
||||
{"", ""}, 2 /*last_committed_seq*/, nullptr /*merge_operator*/,
|
||||
nullptr /*compaction_filter*/, false /*bottommost_level*/,
|
||||
2 /*earliest_write_conflict_snapshot*/);
|
||||
}
|
||||
|
||||
// Compaction filter should keep uncommitted key as-is, and
|
||||
// * Convert the latest velue to deletion, and/or
|
||||
// * if latest value is a merge, apply filter to all suequent merges.
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "monitoring/iostats_context_imp.h"
|
||||
#include "monitoring/perf_context_imp.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
@@ -976,7 +977,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
sub_compact->compaction->immutable_cf_options(),
|
||||
mutable_cf_options, &file_options_, job_id_, cfd->GetID(),
|
||||
cfd->GetName(), Env::IOPriority::IO_LOW, write_hint_,
|
||||
&blob_file_paths, &sub_compact->blob_file_additions)
|
||||
io_tracer_, &blob_file_paths, &sub_compact->blob_file_additions)
|
||||
: nullptr);
|
||||
|
||||
TEST_SYNC_POINT("CompactionJob::Run():Inprogress");
|
||||
@@ -1500,7 +1501,18 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
std::string fname =
|
||||
TableFileName(sub_compact->compaction->immutable_cf_options()->cf_paths,
|
||||
meta->fd.GetNumber(), meta->fd.GetPathId());
|
||||
env_->DeleteFile(fname);
|
||||
|
||||
// TODO(AR) it is not clear if there are any larger implications if
|
||||
// DeleteFile fails here
|
||||
Status ds = env_->DeleteFile(fname);
|
||||
if (!ds.ok()) {
|
||||
ROCKS_LOG_WARN(
|
||||
db_options_.info_log,
|
||||
"[%s] [JOB %d] Unable to remove SST file for table #%" PRIu64
|
||||
" at bottom level%s",
|
||||
cfd->GetName().c_str(), job_id_, output_number,
|
||||
meta->marked_for_compaction ? " (need compaction)" : "");
|
||||
}
|
||||
|
||||
// Also need to remove the file from outputs, or it will be added to the
|
||||
// VersionEdit.
|
||||
@@ -1722,6 +1734,7 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
|
||||
writable_file->SetIOPriority(Env::IOPriority::IO_LOW);
|
||||
writable_file->SetWriteLifeTimeHint(write_hint_);
|
||||
FileTypeSet tmp_set = db_options_.checksum_handoff_file_types;
|
||||
writable_file->SetPreallocationBlockSize(static_cast<size_t>(
|
||||
sub_compact->compaction->OutputFilePreallocationSize()));
|
||||
const auto& listeners =
|
||||
@@ -1729,7 +1742,8 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
sub_compact->outfile.reset(new WritableFileWriter(
|
||||
std::move(writable_file), fname, file_options_, env_, io_tracer_,
|
||||
db_options_.statistics.get(), listeners,
|
||||
db_options_.file_checksum_gen_factory.get()));
|
||||
db_options_.file_checksum_gen_factory.get(),
|
||||
tmp_set.Contains(FileType::kTableFile)));
|
||||
|
||||
// If the Column family flag is to only optimize filters for hits,
|
||||
// we can skip creating filters if this is the bottommost_level where
|
||||
|
||||
@@ -297,15 +297,14 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t Size(const Slice& start, const Slice& limit, int cf = 0) {
|
||||
Status Size(uint64_t* size, const Slice& start, const Slice& limit,
|
||||
int cf = 0) {
|
||||
Range r(start, limit);
|
||||
uint64_t size;
|
||||
if (cf == 0) {
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
return db_->GetApproximateSizes(&r, 1, size);
|
||||
} else {
|
||||
db_->GetApproximateSizes(handles_[1], &r, 1, &size);
|
||||
return db_->GetApproximateSizes(handles_[1], &r, 1, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void Compact(int cf, const Slice& start, const Slice& limit,
|
||||
|
||||
@@ -72,7 +72,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
CompactionJobTestBase(std::string dbname, const Comparator* ucmp,
|
||||
std::function<std::string(uint64_t)> encode_u64_ts)
|
||||
: env_(Env::Default()),
|
||||
fs_(std::make_shared<LegacyFileSystemWrapper>(env_)),
|
||||
fs_(env_->GetFileSystem()),
|
||||
dbname_(std::move(dbname)),
|
||||
ucmp_(ucmp),
|
||||
db_options_(),
|
||||
@@ -269,7 +269,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
&write_buffer_manager_, &write_controller_,
|
||||
/*block_cache_tracer=*/nullptr, /*io_tracer=*/nullptr));
|
||||
compaction_job_stats_.Reset();
|
||||
SetIdentityFile(env_, dbname_);
|
||||
ASSERT_OK(SetIdentityFile(env_, dbname_));
|
||||
|
||||
VersionEdit new_db;
|
||||
new_db.SetLogNumber(0);
|
||||
|
||||
@@ -141,7 +141,7 @@ class CompactionPickerTest : public testing::Test {
|
||||
if (temp_vstorage_) {
|
||||
VersionBuilder builder(FileOptions(), &ioptions_, nullptr,
|
||||
vstorage_.get(), nullptr);
|
||||
builder.SaveTo(temp_vstorage_.get());
|
||||
ASSERT_OK(builder.SaveTo(temp_vstorage_.get()));
|
||||
vstorage_ = std::move(temp_vstorage_);
|
||||
}
|
||||
vstorage_->CalculateBaseBytes(ioptions_, mutable_cf_options_);
|
||||
|
||||
@@ -579,7 +579,7 @@ TEST_F(CorruptionTest, FileSystemStateCorrupted) {
|
||||
|
||||
if (iter == 0) { // corrupt file size
|
||||
std::unique_ptr<WritableFile> file;
|
||||
env_->NewWritableFile(filename, &file, EnvOptions());
|
||||
ASSERT_OK(env_->NewWritableFile(filename, &file, EnvOptions()));
|
||||
ASSERT_OK(file->Append(Slice("corrupted sst")));
|
||||
file.reset();
|
||||
Status x = TryReopen(&options);
|
||||
@@ -616,7 +616,7 @@ TEST_F(CorruptionTest, ParanoidFileChecksOnFlush) {
|
||||
options.table_factory = mock;
|
||||
mock->SetCorruptionMode(mode);
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
Build(10);
|
||||
s = db_->Flush(FlushOptions());
|
||||
if (mode == mock::MockTableFactory::kCorruptNone) {
|
||||
@@ -642,7 +642,7 @@ TEST_F(CorruptionTest, ParanoidFileChecksOnCompact) {
|
||||
std::make_shared<mock::MockTableFactory>();
|
||||
options.table_factory = mock;
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
Build(100, 2);
|
||||
// ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
DBImpl* dbi = static_cast_with_check<DBImpl>(db_);
|
||||
@@ -669,7 +669,7 @@ TEST_F(CorruptionTest, ParanoidFileChecksWithDeleteRangeFirst) {
|
||||
ASSERT_OK(DestroyDB(dbname_, options));
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
std::string start, end;
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(3, &start), Key(7, &end)));
|
||||
auto snap = db_->GetSnapshot();
|
||||
@@ -701,7 +701,7 @@ TEST_F(CorruptionTest, ParanoidFileChecksWithDeleteRange) {
|
||||
db_ = nullptr;
|
||||
ASSERT_OK(DestroyDB(dbname_, options));
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
Build(10, 0, 0);
|
||||
std::string start, end;
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
@@ -737,7 +737,7 @@ TEST_F(CorruptionTest, ParanoidFileChecksWithDeleteRangeLast) {
|
||||
db_ = nullptr;
|
||||
ASSERT_OK(DestroyDB(dbname_, options));
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
std::string start, end;
|
||||
Build(10);
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
@@ -775,7 +775,7 @@ TEST_F(CorruptionTest, LogCorruptionErrorsInCompactionIterator) {
|
||||
options.table_factory = mock;
|
||||
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
Build(100, 2);
|
||||
|
||||
DBImpl* dbi = static_cast_with_check<DBImpl>(db_);
|
||||
@@ -798,7 +798,7 @@ TEST_F(CorruptionTest, CompactionKeyOrderCheck) {
|
||||
std::make_shared<mock::MockTableFactory>();
|
||||
options.table_factory = mock;
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db_));
|
||||
assert(db_ != nullptr);
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
mock->SetCorruptionMode(mock::MockTableFactory::kCorruptReorderKey);
|
||||
Build(100, 2);
|
||||
DBImpl* dbi = static_cast_with_check<DBImpl>(db_);
|
||||
@@ -884,7 +884,7 @@ TEST_F(CorruptionTest, VerifyWholeTableChecksum) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::VerifySstFileChecksum:mismatch", [&](void* arg) {
|
||||
auto* s = reinterpret_cast<Status*>(arg);
|
||||
assert(s);
|
||||
ASSERT_NE(s, nullptr);
|
||||
++count;
|
||||
ASSERT_NOK(*s);
|
||||
});
|
||||
|
||||
+20
-20
@@ -129,10 +129,10 @@ TEST_F(CuckooTableDBTest, Flush) {
|
||||
ASSERT_OK(Put("key1", "v1"));
|
||||
ASSERT_OK(Put("key2", "v2"));
|
||||
ASSERT_OK(Put("key3", "v3"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
TablePropertiesCollection ptc;
|
||||
reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
|
||||
ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
|
||||
ASSERT_EQ(1U, ptc.size());
|
||||
ASSERT_EQ(3U, ptc.begin()->second->num_entries);
|
||||
ASSERT_EQ("1", FilesPerLevel());
|
||||
@@ -146,9 +146,9 @@ TEST_F(CuckooTableDBTest, Flush) {
|
||||
ASSERT_OK(Put("key4", "v4"));
|
||||
ASSERT_OK(Put("key5", "v5"));
|
||||
ASSERT_OK(Put("key6", "v6"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
|
||||
ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
|
||||
ASSERT_EQ(2U, ptc.size());
|
||||
auto row = ptc.begin();
|
||||
ASSERT_EQ(3U, row->second->num_entries);
|
||||
@@ -164,8 +164,8 @@ TEST_F(CuckooTableDBTest, Flush) {
|
||||
ASSERT_OK(Delete("key6"));
|
||||
ASSERT_OK(Delete("key5"));
|
||||
ASSERT_OK(Delete("key4"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
|
||||
ASSERT_EQ(3U, ptc.size());
|
||||
row = ptc.begin();
|
||||
ASSERT_EQ(3U, row->second->num_entries);
|
||||
@@ -186,10 +186,10 @@ TEST_F(CuckooTableDBTest, FlushWithDuplicateKeys) {
|
||||
ASSERT_OK(Put("key1", "v1"));
|
||||
ASSERT_OK(Put("key2", "v2"));
|
||||
ASSERT_OK(Put("key1", "v3")); // Duplicate
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
TablePropertiesCollection ptc;
|
||||
reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
|
||||
ASSERT_OK(reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc));
|
||||
ASSERT_EQ(1U, ptc.size());
|
||||
ASSERT_EQ(2U, ptc.begin()->second->num_entries);
|
||||
ASSERT_EQ("1", FilesPerLevel());
|
||||
@@ -219,7 +219,7 @@ TEST_F(CuckooTableDBTest, Uint64Comparator) {
|
||||
ASSERT_OK(Put(Uint64Key(1), "v1"));
|
||||
ASSERT_OK(Put(Uint64Key(2), "v2"));
|
||||
ASSERT_OK(Put(Uint64Key(3), "v3"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
ASSERT_EQ("v1", Get(Uint64Key(1)));
|
||||
ASSERT_EQ("v2", Get(Uint64Key(2)));
|
||||
@@ -228,10 +228,10 @@ TEST_F(CuckooTableDBTest, Uint64Comparator) {
|
||||
|
||||
// Add more keys.
|
||||
ASSERT_OK(Delete(Uint64Key(2))); // Delete.
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
ASSERT_OK(Put(Uint64Key(3), "v0")); // Update.
|
||||
ASSERT_OK(Put(Uint64Key(4), "v4"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
ASSERT_EQ("v1", Get(Uint64Key(1)));
|
||||
ASSERT_EQ("NOT_FOUND", Get(Uint64Key(2)));
|
||||
ASSERT_EQ("v0", Get(Uint64Key(3)));
|
||||
@@ -251,11 +251,11 @@ TEST_F(CuckooTableDBTest, CompactionIntoMultipleFiles) {
|
||||
for (int idx = 0; idx < 28; ++idx) {
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + char(idx))));
|
||||
}
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ("1", FilesPerLevel());
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow trivial move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow trivial move */));
|
||||
ASSERT_EQ("0,2", FilesPerLevel());
|
||||
for (int idx = 0; idx < 28; ++idx) {
|
||||
ASSERT_EQ(std::string(10000, 'a' + char(idx)), Get(Key(idx)));
|
||||
@@ -274,15 +274,15 @@ TEST_F(CuckooTableDBTest, SameKeyInsertedInTwoDifferentFilesAndCompacted) {
|
||||
for (int idx = 0; idx < 11; ++idx) {
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a')));
|
||||
}
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ("1", FilesPerLevel());
|
||||
|
||||
// Generate one more file in level-0, and should trigger level-0 compaction
|
||||
for (int idx = 0; idx < 11; ++idx) {
|
||||
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + char(idx))));
|
||||
}
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr));
|
||||
|
||||
ASSERT_EQ("0,1", FilesPerLevel());
|
||||
for (int idx = 0; idx < 11; ++idx) {
|
||||
@@ -303,7 +303,7 @@ TEST_F(CuckooTableDBTest, AdaptiveTable) {
|
||||
ASSERT_OK(Put("key1", "v1"));
|
||||
ASSERT_OK(Put("key2", "v2"));
|
||||
ASSERT_OK(Put("key3", "v3"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
// Write some keys using plain table.
|
||||
std::shared_ptr<TableFactory> block_based_factory(
|
||||
@@ -319,7 +319,7 @@ TEST_F(CuckooTableDBTest, AdaptiveTable) {
|
||||
Reopen(&options);
|
||||
ASSERT_OK(Put("key4", "v4"));
|
||||
ASSERT_OK(Put("key1", "v5"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
// Write some keys using block based table.
|
||||
options.table_factory.reset(NewAdaptiveTableFactory(
|
||||
@@ -328,7 +328,7 @@ TEST_F(CuckooTableDBTest, AdaptiveTable) {
|
||||
Reopen(&options);
|
||||
ASSERT_OK(Put("key5", "v6"));
|
||||
ASSERT_OK(Put("key2", "v7"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
|
||||
ASSERT_EQ("v5", Get("key1"));
|
||||
ASSERT_EQ("v7", Get("key2"));
|
||||
|
||||
+75
-49
@@ -21,6 +21,7 @@
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "test_util/sync_point.h"
|
||||
#endif
|
||||
#include "util/file_checksum_helper.h"
|
||||
#include "util/random.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
@@ -146,7 +147,7 @@ TEST_F(DBBasicTest, ReadOnlyDB) {
|
||||
|
||||
// Reopen and flush memtable.
|
||||
Reopen(options);
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
// Now check keys in read only mode.
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
@@ -182,7 +183,7 @@ TEST_F(DBBasicTest, ReadOnlyDBWithWriteDBIdToManifestSet) {
|
||||
|
||||
// Reopen and flush memtable.
|
||||
Reopen(options);
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
// Now check keys in read only mode.
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
@@ -205,7 +206,7 @@ TEST_F(DBBasicTest, CompactedDB) {
|
||||
Reopen(options);
|
||||
// 1 L0 file, use CompactedDB if max_open_files = -1
|
||||
ASSERT_OK(Put("aaa", DummyString(kFileSize / 2, '1')));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
Status s = Put("new", "value");
|
||||
@@ -223,12 +224,12 @@ TEST_F(DBBasicTest, CompactedDB) {
|
||||
Reopen(options);
|
||||
// Add more L0 files
|
||||
ASSERT_OK(Put("bbb", DummyString(kFileSize / 2, '2')));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("aaa", DummyString(kFileSize / 2, 'a')));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("bbb", DummyString(kFileSize / 2, 'b')));
|
||||
ASSERT_OK(Put("eee", DummyString(kFileSize / 2, 'e')));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
@@ -1413,10 +1414,10 @@ TEST_F(DBBasicTest, MultiGetBatchedSortedMultiFile) {
|
||||
// mix with memtable
|
||||
ASSERT_OK(Put(1, "k1", "v1"));
|
||||
ASSERT_OK(Put(1, "k2", "v2"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "k3", "v3"));
|
||||
ASSERT_OK(Put(1, "k4", "v4"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Delete(1, "k4"));
|
||||
ASSERT_OK(Put(1, "k5", "v5"));
|
||||
ASSERT_OK(Delete(1, "no_key"));
|
||||
@@ -1459,19 +1460,19 @@ TEST_F(DBBasicTest, MultiGetBatchedDuplicateKeys) {
|
||||
// mix with memtable
|
||||
ASSERT_OK(Merge(1, "k1", "v1"));
|
||||
ASSERT_OK(Merge(1, "k2", "v2"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
MoveFilesToLevel(2, 1);
|
||||
ASSERT_OK(Merge(1, "k3", "v3"));
|
||||
ASSERT_OK(Merge(1, "k4", "v4"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
MoveFilesToLevel(2, 1);
|
||||
ASSERT_OK(Merge(1, "k4", "v4_2"));
|
||||
ASSERT_OK(Merge(1, "k6", "v6"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
MoveFilesToLevel(2, 1);
|
||||
ASSERT_OK(Merge(1, "k7", "v7"));
|
||||
ASSERT_OK(Merge(1, "k8", "v8"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
MoveFilesToLevel(2, 1);
|
||||
|
||||
get_perf_context()->Reset();
|
||||
@@ -1511,12 +1512,12 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) {
|
||||
ASSERT_OK(Put("key_" + std::to_string(i), "val_l2_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(2);
|
||||
@@ -1525,12 +1526,12 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) {
|
||||
ASSERT_OK(Put("key_" + std::to_string(i), "val_l1_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(1);
|
||||
@@ -1539,12 +1540,12 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) {
|
||||
ASSERT_OK(Put("key_" + std::to_string(i), "val_l0_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
ASSERT_EQ(0, num_keys);
|
||||
@@ -1590,12 +1591,12 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevelMerge) {
|
||||
ASSERT_OK(Put("key_" + std::to_string(i), "val_l2_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(2);
|
||||
@@ -1604,12 +1605,12 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevelMerge) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_l1_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(1);
|
||||
@@ -1618,12 +1619,12 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevelMerge) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_l0_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
ASSERT_EQ(0, num_keys);
|
||||
@@ -1705,7 +1706,7 @@ TEST_F(DBBasicTest, MultiGetBatchedValueSize) {
|
||||
ASSERT_OK(Put(1, "k7", "v7_"));
|
||||
ASSERT_OK(Put(1, "k3", "v3_"));
|
||||
ASSERT_OK(Put(1, "k4", "v4"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Delete(1, "k4"));
|
||||
ASSERT_OK(Put(1, "k11", "v11"));
|
||||
ASSERT_OK(Delete(1, "no_key"));
|
||||
@@ -1715,7 +1716,7 @@ TEST_F(DBBasicTest, MultiGetBatchedValueSize) {
|
||||
ASSERT_OK(Put(1, "k15", "v15"));
|
||||
ASSERT_OK(Put(1, "k16", "v16"));
|
||||
ASSERT_OK(Put(1, "k17", "v17"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
ASSERT_OK(Put(1, "k1", "v1_"));
|
||||
ASSERT_OK(Put(1, "k2", "v2_"));
|
||||
@@ -1785,12 +1786,12 @@ TEST_F(DBBasicTest, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
ASSERT_OK(Put("key_" + std::to_string(i), "val_l2_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(2);
|
||||
@@ -1799,12 +1800,12 @@ TEST_F(DBBasicTest, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_l1_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(1);
|
||||
@@ -1813,12 +1814,12 @@ TEST_F(DBBasicTest, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_l0_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
ASSERT_EQ(0, num_keys);
|
||||
@@ -1908,10 +1909,10 @@ TEST_F(DBBasicTest, MultiGetStats) {
|
||||
keys[i] = Slice(keys_str[i]);
|
||||
ASSERT_OK(Put(1, "k" + std::to_string(i), rnd.RandomString(1000)));
|
||||
if (i % 100 == 0) {
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
}
|
||||
}
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
MoveFilesToLevel(2, 1);
|
||||
|
||||
for (int i = 501; i < 1000; ++i) {
|
||||
@@ -1919,11 +1920,11 @@ TEST_F(DBBasicTest, MultiGetStats) {
|
||||
keys[i] = Slice(keys_str[i]);
|
||||
ASSERT_OK(Put(1, "k" + std::to_string(i), rnd.RandomString(1000)));
|
||||
if (i % 100 == 0) {
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
}
|
||||
}
|
||||
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
MoveFilesToLevel(2, 1);
|
||||
|
||||
for (int i = 1001; i < total_keys; ++i) {
|
||||
@@ -1931,10 +1932,10 @@ TEST_F(DBBasicTest, MultiGetStats) {
|
||||
keys[i] = Slice(keys_str[i]);
|
||||
ASSERT_OK(Put(1, "k" + std::to_string(i), rnd.RandomString(1000)));
|
||||
if (i % 100 == 0) {
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
}
|
||||
}
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
Close();
|
||||
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
@@ -1961,7 +1962,7 @@ TEST_F(DBBasicTest, MultiGetStats) {
|
||||
ASSERT_GT(hist_sst.max, 0);
|
||||
|
||||
// Minimun number of blocks read in a level.
|
||||
ASSERT_EQ(hist_data_blocks.min, 0);
|
||||
ASSERT_EQ(hist_data_blocks.min, 3);
|
||||
ASSERT_GT(hist_index_and_filter_blocks.min, 0);
|
||||
// Minimun number of sst files read in a level.
|
||||
ASSERT_GT(hist_sst.max, 0);
|
||||
@@ -2042,11 +2043,11 @@ TEST_P(DBMultiGetRowCacheTest, MultiGetBatched) {
|
||||
ASSERT_OK(Put(1, "k2", "v2"));
|
||||
ASSERT_OK(Put(1, "k3", "v3"));
|
||||
ASSERT_OK(Put(1, "k4", "v4"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "k5", "v5"));
|
||||
const Snapshot* snap1 = dbfull()->GetSnapshot();
|
||||
ASSERT_OK(Delete(1, "k4"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
const Snapshot* snap2 = dbfull()->GetSnapshot();
|
||||
|
||||
get_perf_context()->Reset();
|
||||
@@ -2185,7 +2186,7 @@ TEST_F(DBBasicTest, MultiGetIOBufferOverrun) {
|
||||
std::string value(rnd.RandomString(128) + zero_str);
|
||||
assert(Put(Key(i), value) == Status::OK());
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::vector<std::string> key_data(10);
|
||||
std::vector<Slice> keys;
|
||||
@@ -2579,7 +2580,7 @@ class DBBasicTestTrackWal : public DBTestBase,
|
||||
|
||||
int CountWalFiles() {
|
||||
VectorLogPtr log_files;
|
||||
dbfull()->GetSortedWalFiles(log_files);
|
||||
EXPECT_OK(dbfull()->GetSortedWalFiles(log_files));
|
||||
return static_cast<int>(log_files.size());
|
||||
};
|
||||
};
|
||||
@@ -2714,9 +2715,9 @@ class DBBasicTestMultiGet : public DBTestBase {
|
||||
: Put(cf, Key(i), values_[i])) == Status::OK());
|
||||
}
|
||||
if (num_cfs == 1) {
|
||||
Flush();
|
||||
EXPECT_OK(Flush());
|
||||
} else {
|
||||
dbfull()->Flush(FlushOptions(), handles_[cf]);
|
||||
EXPECT_OK(dbfull()->Flush(FlushOptions(), handles_[cf]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
@@ -2728,9 +2729,9 @@ class DBBasicTestMultiGet : public DBTestBase {
|
||||
Status::OK());
|
||||
}
|
||||
if (num_cfs == 1) {
|
||||
Flush();
|
||||
EXPECT_OK(Flush());
|
||||
} else {
|
||||
dbfull()->Flush(FlushOptions(), handles_[cf]);
|
||||
EXPECT_OK(dbfull()->Flush(FlushOptions(), handles_[cf]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3273,7 +3274,9 @@ class DeadlineFS : public FileSystemWrapper {
|
||||
|
||||
// Increment the IO counter and return a delay in microseconds
|
||||
IOStatus ShouldDelay(const IOOptions& opts) {
|
||||
if (!deadline_.count() && !io_timeout_.count()) {
|
||||
if (timedout_) {
|
||||
return IOStatus::TimedOut();
|
||||
} else if (!deadline_.count() && !io_timeout_.count()) {
|
||||
return IOStatus::OK();
|
||||
}
|
||||
if (!ignore_deadline_ && delay_trigger_ == io_count_++) {
|
||||
@@ -3580,6 +3583,29 @@ TEST_F(DBBasicTest, VerifyFileChecksums) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(db_->VerifyFileChecksums(ReadOptions()));
|
||||
|
||||
// Does the right thing but with the wrong name -- using it should lead to an
|
||||
// error.
|
||||
class MisnamedFileChecksumGenerator : public FileChecksumGenCrc32c {
|
||||
public:
|
||||
MisnamedFileChecksumGenerator(const FileChecksumGenContext& context)
|
||||
: FileChecksumGenCrc32c(context) {}
|
||||
|
||||
const char* Name() const override { return "sha1"; }
|
||||
};
|
||||
|
||||
class MisnamedFileChecksumGenFactory : public FileChecksumGenCrc32cFactory {
|
||||
public:
|
||||
std::unique_ptr<FileChecksumGenerator> CreateFileChecksumGenerator(
|
||||
const FileChecksumGenContext& context) override {
|
||||
return std::unique_ptr<FileChecksumGenerator>(
|
||||
new MisnamedFileChecksumGenerator(context));
|
||||
}
|
||||
};
|
||||
|
||||
options.file_checksum_gen_factory.reset(new MisnamedFileChecksumGenFactory());
|
||||
Reopen(options);
|
||||
ASSERT_TRUE(db_->VerifyFileChecksums(ReadOptions()).IsInvalidArgument());
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -3643,7 +3669,7 @@ TEST_P(DBBasicTestDeadline, PointLookupDeadline) {
|
||||
std::string key = "k" + ToString(i);
|
||||
ASSERT_OK(Put(key, rnd.RandomString(100)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
bool timedout = true;
|
||||
// A timeout will be forced when the IO counter reaches this value
|
||||
|
||||
+26
-25
@@ -128,8 +128,8 @@ TEST_P(DBBloomFilterTestDefFormatVersion, KeyMayExist) {
|
||||
ASSERT_EQ(cache_added, TestGetTickerCount(options, BLOCK_CACHE_ADD));
|
||||
|
||||
ASSERT_OK(Flush(1));
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1],
|
||||
true /* disallow trivial move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1],
|
||||
true /* disallow trivial move */));
|
||||
|
||||
numopen = TestGetTickerCount(options, NO_FILE_OPENS);
|
||||
cache_added = TestGetTickerCount(options, BLOCK_CACHE_ADD);
|
||||
@@ -178,7 +178,7 @@ TEST_F(DBBloomFilterTest, GetFilterByPrefixBloomCustomPrefixExtractor) {
|
||||
ASSERT_OK(dbfull()->Put(wo, "barbarbar2", "foo2"));
|
||||
ASSERT_OK(dbfull()->Put(wo, "foofoofoo", "bar"));
|
||||
|
||||
dbfull()->Flush(fo);
|
||||
ASSERT_OK(dbfull()->Flush(fo));
|
||||
|
||||
ASSERT_EQ("foo", Get("barbarbar"));
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 0);
|
||||
@@ -244,7 +244,7 @@ TEST_F(DBBloomFilterTest, GetFilterByPrefixBloom) {
|
||||
ASSERT_OK(dbfull()->Put(wo, "barbarbar2", "foo2"));
|
||||
ASSERT_OK(dbfull()->Put(wo, "foofoofoo", "bar"));
|
||||
|
||||
dbfull()->Flush(fo);
|
||||
ASSERT_OK(dbfull()->Flush(fo));
|
||||
|
||||
ASSERT_EQ("foo", Get("barbarbar"));
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_USEFUL), 0);
|
||||
@@ -297,7 +297,7 @@ TEST_F(DBBloomFilterTest, WholeKeyFilterProp) {
|
||||
// ranges.
|
||||
ASSERT_OK(dbfull()->Put(wo, "aaa", ""));
|
||||
ASSERT_OK(dbfull()->Put(wo, "zzz", ""));
|
||||
dbfull()->Flush(fo);
|
||||
ASSERT_OK(dbfull()->Flush(fo));
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("NOT_FOUND", Get("foo"));
|
||||
@@ -328,7 +328,7 @@ TEST_F(DBBloomFilterTest, WholeKeyFilterProp) {
|
||||
// ranges.
|
||||
ASSERT_OK(dbfull()->Put(wo, "aaa", ""));
|
||||
ASSERT_OK(dbfull()->Put(wo, "zzz", ""));
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
// Reopen with both of whole key off and prefix extractor enabled.
|
||||
// Still no bloom filter should be used.
|
||||
@@ -351,7 +351,7 @@ TEST_F(DBBloomFilterTest, WholeKeyFilterProp) {
|
||||
// ranges.
|
||||
ASSERT_OK(dbfull()->Put(wo, "aaa", ""));
|
||||
ASSERT_OK(dbfull()->Put(wo, "zzz", ""));
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
options.prefix_extractor.reset();
|
||||
bbto.whole_key_filtering = true;
|
||||
@@ -364,7 +364,7 @@ TEST_F(DBBloomFilterTest, WholeKeyFilterProp) {
|
||||
// not filtered out by key ranges.
|
||||
ASSERT_OK(dbfull()->Put(wo, "aaa", ""));
|
||||
ASSERT_OK(dbfull()->Put(wo, "zzz", ""));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// Now we have two files:
|
||||
// File 1: An older file with prefix bloom.
|
||||
@@ -467,7 +467,7 @@ TEST_P(DBBloomFilterTestWithParam, BloomFilter) {
|
||||
for (int i = 0; i < N; i += 100) {
|
||||
ASSERT_OK(Put(1, Key(i), Key(i)));
|
||||
}
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
// Prevent auto compactions triggered by seeks
|
||||
env_->delay_sstable_sync_.store(true, std::memory_order_release);
|
||||
@@ -880,7 +880,7 @@ TEST_F(DBBloomFilterTest, ContextCustomFilterPolicy) {
|
||||
|
||||
// Destroy
|
||||
ASSERT_OK(dbfull()->DropColumnFamily(handles_[1]));
|
||||
dbfull()->DestroyColumnFamilyHandle(handles_[1]);
|
||||
ASSERT_OK(dbfull()->DestroyColumnFamilyHandle(handles_[1]));
|
||||
handles_[1] = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1444,9 +1444,9 @@ void PrefixScanInit(DBBloomFilterTest* dbtest) {
|
||||
snprintf(buf, sizeof(buf), "%02d______:end", 10);
|
||||
keystr = std::string(buf);
|
||||
ASSERT_OK(dbtest->Put(keystr, keystr));
|
||||
dbtest->Flush();
|
||||
dbtest->dbfull()->CompactRange(CompactRangeOptions(), nullptr,
|
||||
nullptr); // move to level 1
|
||||
ASSERT_OK(dbtest->Flush());
|
||||
ASSERT_OK(dbtest->dbfull()->CompactRange(CompactRangeOptions(), nullptr,
|
||||
nullptr)); // move to level 1
|
||||
|
||||
// GROUP 1
|
||||
for (int i = 1; i <= small_range_sstfiles; i++) {
|
||||
@@ -1563,21 +1563,21 @@ TEST_F(DBBloomFilterTest, OptimizeFiltersForHits) {
|
||||
for (int key : keys) {
|
||||
ASSERT_OK(Put(1, Key(key), "val"));
|
||||
if (++num_inserted % 1000 == 0) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
}
|
||||
ASSERT_OK(Put(1, Key(0), "val"));
|
||||
ASSERT_OK(Put(1, Key(numkeys), "val"));
|
||||
ASSERT_OK(Flush(1));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
if (NumTableFilesAtLevel(0, 1) == 0) {
|
||||
// No Level 0 file. Create one.
|
||||
ASSERT_OK(Put(1, Key(0), "val"));
|
||||
ASSERT_OK(Put(1, Key(numkeys), "val"));
|
||||
ASSERT_OK(Flush(1));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
|
||||
for (int i = 1; i < numkeys; i += 2) {
|
||||
@@ -1682,7 +1682,8 @@ TEST_F(DBBloomFilterTest, OptimizeFiltersForHits) {
|
||||
BottommostLevelCompaction::kSkip;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = 7;
|
||||
db_->CompactRange(compact_options, handles_[1], nullptr, nullptr);
|
||||
ASSERT_TRUE(db_->CompactRange(compact_options, handles_[1], nullptr, nullptr)
|
||||
.IsNotSupported());
|
||||
|
||||
ASSERT_EQ(trivial_move, 1);
|
||||
ASSERT_EQ(non_trivial_move, 0);
|
||||
@@ -1714,10 +1715,10 @@ TEST_F(DBBloomFilterTest, OptimizeFiltersForHits) {
|
||||
|
||||
int CountIter(std::unique_ptr<Iterator>& iter, const Slice& key) {
|
||||
int count = 0;
|
||||
for (iter->Seek(key); iter->Valid() && iter->status() == Status::OK();
|
||||
iter->Next()) {
|
||||
for (iter->Seek(key); iter->Valid(); iter->Next()) {
|
||||
count++;
|
||||
}
|
||||
EXPECT_OK(iter->status());
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -1747,7 +1748,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
ASSERT_OK(Put("abcdxxx1", "val2"));
|
||||
ASSERT_OK(Put("abcdxxx2", "val3"));
|
||||
ASSERT_OK(Put("abcdxxx3", "val4"));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
{
|
||||
// prefix_extractor has not changed, BF will always be read
|
||||
Slice upper_bound("abce");
|
||||
@@ -1905,7 +1906,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
ASSERT_OK(Put("foo4", "bar4"));
|
||||
ASSERT_OK(Put("foq5", "bar5"));
|
||||
ASSERT_OK(Put("fpb", "1"));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
{
|
||||
// BF is cappped:3 now
|
||||
std::unique_ptr<Iterator> iter_tmp(db_->NewIterator(read_options));
|
||||
@@ -1929,7 +1930,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
ASSERT_OK(Put("foo7", "bar7"));
|
||||
ASSERT_OK(Put("foq8", "bar8"));
|
||||
ASSERT_OK(Put("fpc", "2"));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
{
|
||||
// BF is fixed:2 now
|
||||
std::unique_ptr<Iterator> iter_tmp(db_->NewIterator(read_options));
|
||||
@@ -2040,10 +2041,10 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterNewColumnFamily) {
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
}
|
||||
ASSERT_OK(dbfull()->DropColumnFamily(handles_[2]));
|
||||
dbfull()->DestroyColumnFamilyHandle(handles_[2]);
|
||||
ASSERT_OK(dbfull()->DestroyColumnFamilyHandle(handles_[2]));
|
||||
handles_[2] = nullptr;
|
||||
ASSERT_OK(dbfull()->DropColumnFamily(handles_[1]));
|
||||
dbfull()->DestroyColumnFamilyHandle(handles_[1]);
|
||||
ASSERT_OK(dbfull()->DestroyColumnFamilyHandle(handles_[1]));
|
||||
handles_[1] = nullptr;
|
||||
iteration++;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class DBTestCompactionFilterWithCompactParam
|
||||
option_config_ == kUniversalSubcompactions) {
|
||||
assert(options.max_subcompactions > 1);
|
||||
}
|
||||
TryReopen(options);
|
||||
Reopen(options);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -276,7 +276,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
@@ -284,10 +284,10 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
// the compaction is each level invokes the filter for
|
||||
// all the keys in that level.
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
@@ -321,6 +321,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
}
|
||||
iter->Next();
|
||||
}
|
||||
ASSERT_OK(iter->status());
|
||||
}
|
||||
ASSERT_EQ(total, 100000);
|
||||
ASSERT_EQ(count, 0);
|
||||
@@ -337,10 +338,10 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
// means that all keys should pass at least once
|
||||
// via the compaction filter
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1, 1), 0);
|
||||
@@ -369,10 +370,10 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
// verify that at the end of the compaction process,
|
||||
// nothing is left.
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1, 1), 0);
|
||||
@@ -387,6 +388,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
count++;
|
||||
iter->Next();
|
||||
}
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_EQ(count, 0);
|
||||
}
|
||||
|
||||
@@ -427,9 +429,9 @@ TEST_F(DBTestCompactionFilter, CompactionFilterDeletesAll) {
|
||||
// put some data
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
Put(ToString(table * 100 + i), "val");
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
// this will produce empty file (delete compaction filter)
|
||||
@@ -440,6 +442,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterDeletesAll) {
|
||||
|
||||
Iterator* itr = db_->NewIterator(ReadOptions());
|
||||
itr->SeekToFirst();
|
||||
ASSERT_OK(itr->status());
|
||||
// empty db
|
||||
ASSERT_TRUE(!itr->Valid());
|
||||
|
||||
@@ -463,25 +466,25 @@ TEST_P(DBTestCompactionFilterWithCompactParam,
|
||||
for (int i = 0; i < 100001; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
|
||||
// push all files to lower levels
|
||||
ASSERT_OK(Flush(1));
|
||||
if (option_config_ != kUniversalCompactionMultiLevel &&
|
||||
option_config_ != kUniversalSubcompactions) {
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
} else {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), handles_[1], nullptr,
|
||||
nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), handles_[1],
|
||||
nullptr, nullptr));
|
||||
}
|
||||
|
||||
// re-write all data again
|
||||
for (int i = 0; i < 100001; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
|
||||
// push all files to lower levels. This should
|
||||
@@ -489,11 +492,11 @@ TEST_P(DBTestCompactionFilterWithCompactParam,
|
||||
ASSERT_OK(Flush(1));
|
||||
if (option_config_ != kUniversalCompactionMultiLevel &&
|
||||
option_config_ != kUniversalSubcompactions) {
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
} else {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), handles_[1], nullptr,
|
||||
nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), handles_[1],
|
||||
nullptr, nullptr));
|
||||
}
|
||||
|
||||
// verify that all keys now have the new value that
|
||||
@@ -531,7 +534,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
ASSERT_OK(Flush());
|
||||
std::string newvalue = Get("foo");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("foo");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
|
||||
@@ -539,12 +542,12 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
// merge keys.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "bar", two));
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("bar");
|
||||
ASSERT_EQ("NOT_FOUND", newvalue);
|
||||
ASSERT_OK(db_->Merge(WriteOptions(), "bar", two));
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("bar");
|
||||
ASSERT_EQ(two, two);
|
||||
|
||||
@@ -555,7 +558,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
ASSERT_OK(Flush());
|
||||
newvalue = Get("foobar");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("foobar");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
|
||||
@@ -568,7 +571,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
ASSERT_OK(Flush());
|
||||
newvalue = Get("barfoo");
|
||||
ASSERT_EQ(newvalue, four);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("barfoo");
|
||||
ASSERT_EQ(newvalue, four);
|
||||
}
|
||||
@@ -590,21 +593,21 @@ TEST_F(DBTestCompactionFilter, CompactionFilterContextManual) {
|
||||
for (int i = 0; i < num_keys_per_file; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%02d", i, j);
|
||||
Put(key, value);
|
||||
ASSERT_OK(Put(key, value));
|
||||
}
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
// Make sure next file is much smaller so automatic compaction will not
|
||||
// be triggered.
|
||||
num_keys_per_file /= 2;
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
// Force a manual compaction
|
||||
cfilter_count = 0;
|
||||
filter->expect_manual_compaction_.store(true);
|
||||
filter->expect_full_compaction_.store(true);
|
||||
filter->expect_cf_id_.store(0);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(cfilter_count, 700);
|
||||
ASSERT_EQ(NumSortedRuns(0), 1);
|
||||
ASSERT_TRUE(filter->compaction_filter_created());
|
||||
@@ -654,14 +657,14 @@ TEST_F(DBTestCompactionFilter, CompactionFilterContextCfId) {
|
||||
for (int i = 0; i < num_keys_per_file; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%02d", i, j);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
// Make sure next file is much smaller so automatic compaction will not
|
||||
// be triggered.
|
||||
num_keys_per_file /= 2;
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_TRUE(filter->compaction_filter_created());
|
||||
}
|
||||
@@ -680,9 +683,9 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
const Snapshot* snapshot = nullptr;
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Put(ToString(table * 100 + i), "val");
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
if (table == 0) {
|
||||
snapshot = db_->GetSnapshot();
|
||||
@@ -702,6 +705,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
read_options.snapshot = snapshot;
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
iter->SeekToFirst();
|
||||
ASSERT_OK(iter->status());
|
||||
int count = 0;
|
||||
while (iter->Valid()) {
|
||||
count++;
|
||||
@@ -710,6 +714,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
ASSERT_EQ(count, 6);
|
||||
read_options.snapshot = nullptr;
|
||||
std::unique_ptr<Iterator> iter1(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter1->status());
|
||||
iter1->SeekToFirst();
|
||||
count = 0;
|
||||
while (iter1->Valid()) {
|
||||
@@ -740,9 +745,9 @@ TEST_F(DBTestCompactionFilter, SkipUntil) {
|
||||
for (int i = table * 6; i < 39 + table * 11; ++i) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "%010d", table * 100 + i);
|
||||
Put(key, std::to_string(table * 1000 + i));
|
||||
ASSERT_OK(Put(key, std::to_string(table * 1000 + i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
cfilter_skips = 0;
|
||||
@@ -781,10 +786,10 @@ TEST_F(DBTestCompactionFilter, SkipUntilWithBloomFilter) {
|
||||
options.create_if_missing = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Put("0000000010", "v10");
|
||||
Put("0000000020", "v20"); // skipped
|
||||
Put("0000000050", "v50");
|
||||
Flush();
|
||||
ASSERT_OK(Put("0000000010", "v10"));
|
||||
ASSERT_OK(Put("0000000020", "v20")); // skipped
|
||||
ASSERT_OK(Put("0000000050", "v50"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
cfilter_skips = 0;
|
||||
EXPECT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
@@ -822,13 +827,13 @@ TEST_F(DBTestCompactionFilter, IgnoreSnapshotsFalse) {
|
||||
options.compaction_filter = new TestNotSupportedFilter();
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Put("a", "v10");
|
||||
Put("z", "v20");
|
||||
Flush();
|
||||
ASSERT_OK(Put("a", "v10"));
|
||||
ASSERT_OK(Put("z", "v20"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
Put("a", "v10");
|
||||
Put("z", "v20");
|
||||
Flush();
|
||||
ASSERT_OK(Put("a", "v10"));
|
||||
ASSERT_OK(Put("z", "v20"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// Comapction should fail because IgnoreSnapshots() = false
|
||||
EXPECT_TRUE(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr)
|
||||
|
||||
+609
-319
File diff suppressed because it is too large.
Load diff
+21
-20
@@ -102,7 +102,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase) {
|
||||
}
|
||||
|
||||
// Test compact range works
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
// All data should be in the last level.
|
||||
ColumnFamilyMetaData cf_meta;
|
||||
db_->GetColumnFamilyMetaData(&cf_meta);
|
||||
@@ -166,8 +167,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(4U, int_prop);
|
||||
|
||||
@@ -184,8 +185,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(3U, int_prop);
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level1", &str_prop));
|
||||
@@ -205,8 +206,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(3U, int_prop);
|
||||
|
||||
@@ -234,8 +235,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
}));
|
||||
|
||||
TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:0");
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(2U, int_prop);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
@@ -264,7 +265,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
}
|
||||
TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:2");
|
||||
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
thread.join();
|
||||
|
||||
@@ -302,7 +303,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// Compact against empty DB
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
uint64_t int_prop;
|
||||
std::string str_prop;
|
||||
@@ -316,13 +317,13 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
ASSERT_OK(
|
||||
Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))), rnd.RandomString(80)));
|
||||
}
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
if (NumTableFilesAtLevel(0) == 0) {
|
||||
// Make sure level 0 is not empty
|
||||
ASSERT_OK(
|
||||
Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))), rnd.RandomString(80)));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
@@ -343,7 +344,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(output_levels.size(), 2);
|
||||
ASSERT_TRUE(output_levels.find(3) != output_levels.end());
|
||||
ASSERT_TRUE(output_levels.find(4) != output_levels.end());
|
||||
@@ -389,8 +390,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBaseInc) {
|
||||
PutFixed32(&value, static_cast<uint32_t>(i));
|
||||
ASSERT_OK(Put(Key(i), value));
|
||||
}
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
ASSERT_EQ(non_trivial, 0);
|
||||
@@ -449,7 +450,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
ASSERT_OK(Delete(Key(i / 10)));
|
||||
}
|
||||
verify_func(total_keys, false);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
options.level_compaction_dynamic_level_bytes = true;
|
||||
options.disable_auto_compactions = true;
|
||||
@@ -464,7 +465,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = options.num_levels - 1;
|
||||
dbfull()->CompactRange(compact_options, nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(compact_options, nullptr, nullptr));
|
||||
compaction_finished.store(true);
|
||||
});
|
||||
do {
|
||||
@@ -484,7 +485,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
}
|
||||
|
||||
verify_func(total_keys2, false);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
verify_func(total_keys2, false);
|
||||
|
||||
// Base level is not level 1
|
||||
|
||||
@@ -44,7 +44,7 @@ TEST_F(DBEncryptionTest, CheckEncrypted) {
|
||||
Env* target = GetTargetEnv();
|
||||
int hits = 0;
|
||||
for (auto it = fileNames.begin() ; it != fileNames.end(); ++it) {
|
||||
if ((*it == "..") || (*it == ".") || (*it == "LOCK")) {
|
||||
if (*it == "LOCK") {
|
||||
continue;
|
||||
}
|
||||
auto filePath = dbname_ + "/" + *it;
|
||||
|
||||
+206
-13
@@ -19,6 +19,7 @@
|
||||
#include "util/cast_util.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
#include "utilities/fault_injection_fs.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -451,7 +452,6 @@ TEST_F(DBFlushTest, FlushWithBlob) {
|
||||
constexpr uint64_t min_blob_size = 10;
|
||||
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = min_blob_size;
|
||||
options.disable_auto_compactions = true;
|
||||
@@ -525,14 +525,209 @@ TEST_F(DBFlushTest, FlushWithBlob) {
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
|
||||
TEST_F(DBFlushTest, FlushWithChecksumHandoff1) {
|
||||
if (mem_env_ || encrypted_env_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires non-mem or non-encrypted environment");
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<FaultInjectionTestFS> fault_fs(
|
||||
new FaultInjectionTestFS(FileSystem::Default()));
|
||||
std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
|
||||
Options options = CurrentOptions();
|
||||
options.write_buffer_size = 100;
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 3;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = fault_fs_env.get();
|
||||
options.checksum_handoff_file_types.Add(FileType::kTableFile);
|
||||
Reopen(options);
|
||||
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
ASSERT_OK(Put("key1", "value1"));
|
||||
ASSERT_OK(Put("key2", "value2"));
|
||||
ASSERT_OK(dbfull()->TEST_SwitchMemtable());
|
||||
|
||||
// The hash does not match, write fails
|
||||
// fault_fs->SetChecksumHandoffFuncType(ChecksumType::kxxHash);
|
||||
// Since the file system returns IOStatus::Corruption, it is an
|
||||
// unrecoverable error.
|
||||
SyncPoint::GetInstance()->SetCallBack("FlushJob::Start", [&](void*) {
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kxxHash);
|
||||
});
|
||||
ASSERT_OK(Put("key3", "value3"));
|
||||
ASSERT_OK(Put("key4", "value4"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Status s = Flush();
|
||||
ASSERT_EQ(s.severity(),
|
||||
ROCKSDB_NAMESPACE::Status::Severity::kUnrecoverableError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
Destroy(options);
|
||||
Reopen(options);
|
||||
|
||||
// The file system does not support checksum handoff. The check
|
||||
// will be ignored.
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kNoChecksum);
|
||||
ASSERT_OK(Put("key5", "value5"));
|
||||
ASSERT_OK(Put("key6", "value6"));
|
||||
ASSERT_OK(dbfull()->TEST_SwitchMemtable());
|
||||
|
||||
// Each write will be similated as corrupted.
|
||||
// Since the file system returns IOStatus::Corruption, it is an
|
||||
// unrecoverable error.
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
SyncPoint::GetInstance()->SetCallBack("FlushJob::Start", [&](void*) {
|
||||
fault_fs->IngestDataCorruptionBeforeWrite();
|
||||
});
|
||||
ASSERT_OK(Put("key7", "value7"));
|
||||
ASSERT_OK(Put("key8", "value8"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(),
|
||||
ROCKSDB_NAMESPACE::Status::Severity::kUnrecoverableError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBFlushTest, FlushWithChecksumHandoff2) {
|
||||
if (mem_env_ || encrypted_env_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires non-mem or non-encrypted environment");
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<FaultInjectionTestFS> fault_fs(
|
||||
new FaultInjectionTestFS(FileSystem::Default()));
|
||||
std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
|
||||
Options options = CurrentOptions();
|
||||
options.write_buffer_size = 100;
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 3;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = fault_fs_env.get();
|
||||
Reopen(options);
|
||||
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
ASSERT_OK(Put("key1", "value1"));
|
||||
ASSERT_OK(Put("key2", "value2"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// options is not set, the checksum handoff will not be triggered
|
||||
SyncPoint::GetInstance()->SetCallBack("FlushJob::Start", [&](void*) {
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kxxHash);
|
||||
});
|
||||
ASSERT_OK(Put("key3", "value3"));
|
||||
ASSERT_OK(Put("key4", "value4"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
ASSERT_OK(Flush());
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
Destroy(options);
|
||||
Reopen(options);
|
||||
|
||||
// The file system does not support checksum handoff. The check
|
||||
// will be ignored.
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kNoChecksum);
|
||||
ASSERT_OK(Put("key5", "value5"));
|
||||
ASSERT_OK(Put("key6", "value6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// options is not set, the checksum handoff will not be triggered
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
SyncPoint::GetInstance()->SetCallBack("FlushJob::Start", [&](void*) {
|
||||
fault_fs->IngestDataCorruptionBeforeWrite();
|
||||
});
|
||||
ASSERT_OK(Put("key7", "value7"));
|
||||
ASSERT_OK(Put("key8", "value8"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
ASSERT_OK(Flush());
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBFlushTest, FlushWithChecksumHandoffManifest1) {
|
||||
if (mem_env_ || encrypted_env_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires non-mem or non-encrypted environment");
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<FaultInjectionTestFS> fault_fs(
|
||||
new FaultInjectionTestFS(FileSystem::Default()));
|
||||
std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
|
||||
Options options = CurrentOptions();
|
||||
options.write_buffer_size = 100;
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 3;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = fault_fs_env.get();
|
||||
options.checksum_handoff_file_types.Add(FileType::kDescriptorFile);
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put("key1", "value1"));
|
||||
ASSERT_OK(Put("key2", "value2"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// The hash does not match, write fails
|
||||
// fault_fs->SetChecksumHandoffFuncType(ChecksumType::kxxHash);
|
||||
// Since the file system returns IOStatus::Corruption, it is mapped to
|
||||
// kFatalError error.
|
||||
ASSERT_OK(Put("key3", "value3"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionSet::LogAndApply:WriteManifest", [&](void*) {
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kxxHash);
|
||||
});
|
||||
ASSERT_OK(Put("key3", "value3"));
|
||||
ASSERT_OK(Put("key4", "value4"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Status s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kFatalError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBFlushTest, FlushWithChecksumHandoffManifest2) {
|
||||
if (mem_env_ || encrypted_env_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires non-mem or non-encrypted environment");
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<FaultInjectionTestFS> fault_fs(
|
||||
new FaultInjectionTestFS(FileSystem::Default()));
|
||||
std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
|
||||
Options options = CurrentOptions();
|
||||
options.write_buffer_size = 100;
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 3;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = fault_fs_env.get();
|
||||
options.checksum_handoff_file_types.Add(FileType::kDescriptorFile);
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kNoChecksum);
|
||||
Reopen(options);
|
||||
// The file system does not support checksum handoff. The check
|
||||
// will be ignored.
|
||||
ASSERT_OK(Put("key5", "value5"));
|
||||
ASSERT_OK(Put("key6", "value6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// Each write will be similated as corrupted.
|
||||
// Since the file system returns IOStatus::Corruption, it is mapped to
|
||||
// kFatalError error.
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionSet::LogAndApply:WriteManifest",
|
||||
[&](void*) { fault_fs->IngestDataCorruptionBeforeWrite(); });
|
||||
ASSERT_OK(Put("key7", "value7"));
|
||||
ASSERT_OK(Put("key8", "value8"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Status s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kFatalError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
class DBFlushTestBlobError : public DBFlushTest,
|
||||
public testing::WithParamInterface<std::string> {
|
||||
public:
|
||||
DBFlushTestBlobError()
|
||||
: fault_injection_env_(env_), sync_point_(GetParam()) {}
|
||||
~DBFlushTestBlobError() { Close(); }
|
||||
DBFlushTestBlobError() : sync_point_(GetParam()) {}
|
||||
|
||||
FaultInjectionTestEnv fault_injection_env_;
|
||||
std::string sync_point_;
|
||||
};
|
||||
|
||||
@@ -545,20 +740,18 @@ TEST_P(DBFlushTestBlobError, FlushError) {
|
||||
Options options;
|
||||
options.enable_blob_files = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = &fault_injection_env_;
|
||||
options.env = env_;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put("key", "blob"));
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* /* arg */) {
|
||||
fault_injection_env_.SetFilesystemActive(false,
|
||||
Status::IOError(sync_point_));
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* arg) {
|
||||
Status* const s = static_cast<Status*>(arg);
|
||||
assert(s);
|
||||
|
||||
(*s) = Status::IOError(sync_point_);
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeDeleteFile", [this](void* /* arg */) {
|
||||
fault_injection_env_.SetFilesystemActive(true);
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_NOK(Flush());
|
||||
|
||||
+76
-50
@@ -53,7 +53,6 @@
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "db/write_callback.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/file_util.h"
|
||||
#include "file/filename.h"
|
||||
#include "file/random_access_file_reader.h"
|
||||
@@ -83,6 +82,7 @@
|
||||
#include "rocksdb/stats_history.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "rocksdb/version.h"
|
||||
#include "rocksdb/write_buffer_manager.h"
|
||||
#include "table/block_based/block.h"
|
||||
#include "table/block_based/block_based_table_factory.h"
|
||||
@@ -94,7 +94,6 @@
|
||||
#include "table/two_level_iterator.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/autovector.h"
|
||||
#include "util/build_version.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/compression.h"
|
||||
@@ -307,18 +306,21 @@ Status DBImpl::ResumeImpl(DBRecoverContext context) {
|
||||
mutex_.AssertHeld();
|
||||
WaitForBackgroundWork();
|
||||
|
||||
Status bg_error = error_handler_.GetBGError();
|
||||
Status s;
|
||||
if (shutdown_initiated_) {
|
||||
// Returning shutdown status to SFM during auto recovery will cause it
|
||||
// to abort the recovery and allow the shutdown to progress
|
||||
s = Status::ShutdownInProgress();
|
||||
}
|
||||
if (s.ok() && bg_error.severity() > Status::Severity::kHardError) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"DB resume requested but failed due to Fatal/Unrecoverable error");
|
||||
s = bg_error;
|
||||
|
||||
if (s.ok()) {
|
||||
Status bg_error = error_handler_.GetBGError();
|
||||
if (bg_error.severity() > Status::Severity::kHardError) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"DB resume requested but failed due to Fatal/Unrecoverable error");
|
||||
s = bg_error;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the IO Status stored in version set is set to OK.
|
||||
@@ -393,6 +395,11 @@ Status DBImpl::ResumeImpl(DBRecoverContext context) {
|
||||
FindObsoleteFiles(&job_context, true);
|
||||
if (s.ok()) {
|
||||
s = error_handler_.ClearBGError();
|
||||
} else {
|
||||
// NOTE: this is needed to pass ASSERT_STATUS_CHECKED
|
||||
// in the DBSSTTest.DBWithMaxSpaceAllowedRandomized test.
|
||||
// See https://github.com/facebook/rocksdb/pull/7715#issuecomment-754947952
|
||||
error_handler_.GetRecoveryError().PermitUncheckedError();
|
||||
}
|
||||
mutex_.Unlock();
|
||||
|
||||
@@ -409,6 +416,12 @@ Status DBImpl::ResumeImpl(DBRecoverContext context) {
|
||||
if (file_deletion_disabled) {
|
||||
// Always return ok
|
||||
s = EnableFileDeletions(/*force=*/true);
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"DB resume requested but could not enable file deletions [%s]",
|
||||
s.ToString().c_str());
|
||||
}
|
||||
}
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log, "Successfully resumed DB");
|
||||
}
|
||||
@@ -690,6 +703,18 @@ void DBImpl::PrintStatistics() {
|
||||
|
||||
void DBImpl::StartPeriodicWorkScheduler() {
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
#ifndef NDEBUG
|
||||
// It only used by test to disable scheduler
|
||||
bool disable_scheduler = false;
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"DBImpl::StartPeriodicWorkScheduler:DisableScheduler",
|
||||
&disable_scheduler);
|
||||
if (disable_scheduler) {
|
||||
return;
|
||||
}
|
||||
#endif // !NDEBUG
|
||||
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
periodic_work_scheduler_ = PeriodicWorkScheduler::Default();
|
||||
@@ -1693,7 +1718,9 @@ Status DBImpl::GetImpl(const ReadOptions& read_options, const Slice& key,
|
||||
}
|
||||
// If timestamp is used, we use read callback to ensure <key,t,s> is returned
|
||||
// only if t <= read_opts.timestamp and s <= snapshot.
|
||||
if (ts_sz > 0 && !get_impl_options.callback) {
|
||||
if (ts_sz > 0) {
|
||||
assert(!get_impl_options
|
||||
.callback); // timestamp with callback is not supported
|
||||
read_cb.Refresh(snapshot);
|
||||
get_impl_options.callback = &read_cb;
|
||||
}
|
||||
@@ -2369,8 +2396,9 @@ void DBImpl::MultiGetWithCallback(
|
||||
}
|
||||
|
||||
GetWithTimestampReadCallback timestamp_read_callback(0);
|
||||
ReadCallback* read_callback = nullptr;
|
||||
ReadCallback* read_callback = callback;
|
||||
if (read_options.timestamp && read_options.timestamp->size() > 0) {
|
||||
assert(!read_callback); // timestamp with callback is not supported
|
||||
timestamp_read_callback.Refresh(consistent_seqnum);
|
||||
read_callback = ×tamp_read_callback;
|
||||
}
|
||||
@@ -3099,8 +3127,8 @@ const std::string& DBImpl::GetName() const { return dbname_; }
|
||||
Env* DBImpl::GetEnv() const { return env_; }
|
||||
|
||||
FileSystem* DB::GetFileSystem() const {
|
||||
static LegacyFileSystemWrapper fs_wrap(GetEnv());
|
||||
return &fs_wrap;
|
||||
const auto& fs = GetEnv()->GetFileSystem();
|
||||
return fs.get();
|
||||
}
|
||||
|
||||
FileSystem* DBImpl::GetFileSystem() const {
|
||||
@@ -3483,7 +3511,6 @@ Status DBImpl::DeleteFile(std::string name) {
|
||||
return Status::InvalidArgument("Invalid file name");
|
||||
}
|
||||
|
||||
Status status;
|
||||
if (type == kWalFile) {
|
||||
// Only allow deleting archived log files
|
||||
if (log_type != kArchivedLogFile) {
|
||||
@@ -3492,7 +3519,7 @@ Status DBImpl::DeleteFile(std::string name) {
|
||||
name.c_str());
|
||||
return Status::NotSupported("Delete only supported for archived logs");
|
||||
}
|
||||
status = wal_manager_.DeleteFile(name, number);
|
||||
Status status = wal_manager_.DeleteFile(name, number);
|
||||
if (!status.ok()) {
|
||||
ROCKS_LOG_ERROR(immutable_db_options_.info_log,
|
||||
"DeleteFile %s failed -- %s.\n", name.c_str(),
|
||||
@@ -3501,6 +3528,7 @@ Status DBImpl::DeleteFile(std::string name) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Status status;
|
||||
int level;
|
||||
FileMetaData* metadata;
|
||||
ColumnFamilyData* cfd;
|
||||
@@ -3574,7 +3602,7 @@ Status DBImpl::DeleteFile(std::string name) {
|
||||
Status DBImpl::DeleteFilesInRanges(ColumnFamilyHandle* column_family,
|
||||
const RangePtr* ranges, size_t n,
|
||||
bool include_end) {
|
||||
Status status;
|
||||
Status status = Status::OK();
|
||||
auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);
|
||||
ColumnFamilyData* cfd = cfh->cfd();
|
||||
VersionEdit edit;
|
||||
@@ -3633,7 +3661,7 @@ Status DBImpl::DeleteFilesInRanges(ColumnFamilyHandle* column_family,
|
||||
}
|
||||
if (edit.GetDeletedFiles().empty()) {
|
||||
job_context.Clean();
|
||||
return Status::OK();
|
||||
return status;
|
||||
}
|
||||
input_version->Ref();
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
@@ -4180,16 +4208,17 @@ void DBImpl::EraseThreadStatusDbInfo() const {}
|
||||
//
|
||||
// A global method that can dump out the build version
|
||||
void DumpRocksDBBuildVersion(Logger* log) {
|
||||
#if !defined(IOS_CROSS_COMPILE)
|
||||
// if we compile with Xcode, we don't run build_detect_version, so we don't
|
||||
// generate util/build_version.cc
|
||||
ROCKS_LOG_HEADER(log, "RocksDB version: %d.%d.%d\n", ROCKSDB_MAJOR,
|
||||
ROCKSDB_MINOR, ROCKSDB_PATCH);
|
||||
ROCKS_LOG_HEADER(log, "Git sha %s", rocksdb_build_git_sha);
|
||||
ROCKS_LOG_HEADER(log, "Compile date %s", rocksdb_build_compile_date);
|
||||
#else
|
||||
(void)log; // ignore "-Wunused-parameter"
|
||||
#endif
|
||||
ROCKS_LOG_HEADER(log, "RocksDB version: %s\n",
|
||||
GetRocksVersionAsString().c_str());
|
||||
const auto& props = GetRocksBuildProperties();
|
||||
const auto& sha = props.find("rocksdb_build_git_sha");
|
||||
if (sha != props.end()) {
|
||||
ROCKS_LOG_HEADER(log, "Git sha %s", sha->second.c_str());
|
||||
}
|
||||
const auto date = props.find("rocksdb_build_date");
|
||||
if (date != props.end()) {
|
||||
ROCKS_LOG_HEADER(log, "Compile date %s", date->second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
@@ -4354,7 +4383,7 @@ Status DBImpl::IngestExternalFiles(
|
||||
}
|
||||
}
|
||||
// Ingest multiple external SST files atomically.
|
||||
size_t num_cfs = args.size();
|
||||
const size_t num_cfs = args.size();
|
||||
for (size_t i = 0; i != num_cfs; ++i) {
|
||||
if (args[i].external_files.empty()) {
|
||||
char err_msg[128] = {0};
|
||||
@@ -4395,10 +4424,7 @@ Status DBImpl::IngestExternalFiles(
|
||||
env_, versions_.get(), cfd, immutable_db_options_, file_options_,
|
||||
&snapshots_, arg.options, &directories_, &event_logger_, io_tracer_);
|
||||
}
|
||||
std::vector<std::pair<bool, Status>> exec_results;
|
||||
for (size_t i = 0; i != num_cfs; ++i) {
|
||||
exec_results.emplace_back(false, Status::OK());
|
||||
}
|
||||
|
||||
// TODO(yanqin) maybe make jobs run in parallel
|
||||
uint64_t start_file_number = next_file_number;
|
||||
for (size_t i = 1; i != num_cfs; ++i) {
|
||||
@@ -4406,10 +4432,13 @@ Status DBImpl::IngestExternalFiles(
|
||||
auto* cfd =
|
||||
static_cast<ColumnFamilyHandleImpl*>(args[i].column_family)->cfd();
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
exec_results[i].second = ingestion_jobs[i].Prepare(
|
||||
Status es = ingestion_jobs[i].Prepare(
|
||||
args[i].external_files, args[i].files_checksums,
|
||||
args[i].files_checksum_func_names, start_file_number, super_version);
|
||||
exec_results[i].first = true;
|
||||
// capture first error only
|
||||
if (!es.ok() && status.ok()) {
|
||||
status = es;
|
||||
}
|
||||
CleanupSuperVersion(super_version);
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::IngestExternalFiles:BeforeLastJobPrepare:0");
|
||||
@@ -4418,23 +4447,17 @@ Status DBImpl::IngestExternalFiles(
|
||||
auto* cfd =
|
||||
static_cast<ColumnFamilyHandleImpl*>(args[0].column_family)->cfd();
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
exec_results[0].second = ingestion_jobs[0].Prepare(
|
||||
Status es = ingestion_jobs[0].Prepare(
|
||||
args[0].external_files, args[0].files_checksums,
|
||||
args[0].files_checksum_func_names, next_file_number, super_version);
|
||||
exec_results[0].first = true;
|
||||
CleanupSuperVersion(super_version);
|
||||
}
|
||||
for (const auto& exec_result : exec_results) {
|
||||
if (!exec_result.second.ok()) {
|
||||
status = exec_result.second;
|
||||
break;
|
||||
if (!es.ok()) {
|
||||
status = es;
|
||||
}
|
||||
CleanupSuperVersion(super_version);
|
||||
}
|
||||
if (!status.ok()) {
|
||||
for (size_t i = 0; i != num_cfs; ++i) {
|
||||
if (exec_results[i].first) {
|
||||
ingestion_jobs[i].Cleanup(status);
|
||||
}
|
||||
ingestion_jobs[i].Cleanup(status);
|
||||
}
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
ReleaseFileNumberFromPendingOutputs(pending_output_elem);
|
||||
@@ -4878,7 +4901,7 @@ Status DBImpl::VerifySstFileChecksum(const FileMetaData& fmeta,
|
||||
fs_.get(), fname, immutable_db_options_.file_checksum_gen_factory.get(),
|
||||
fmeta.file_checksum_func_name, &file_checksum, &func_name,
|
||||
read_options.readahead_size, immutable_db_options_.allow_mmap_reads,
|
||||
io_tracer_);
|
||||
io_tracer_, immutable_db_options_.rate_limiter.get());
|
||||
if (s.ok()) {
|
||||
assert(fmeta.file_checksum_func_name == func_name);
|
||||
if (file_checksum != fmeta.file_checksum) {
|
||||
@@ -4950,24 +4973,27 @@ Status DBImpl::EndBlockCacheTrace() {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status DBImpl::TraceIteratorSeek(const uint32_t& cf_id, const Slice& key) {
|
||||
Status DBImpl::TraceIteratorSeek(const uint32_t& cf_id, const Slice& key,
|
||||
const Slice& lower_bound,
|
||||
const Slice upper_bound) {
|
||||
Status s;
|
||||
if (tracer_) {
|
||||
InstrumentedMutexLock lock(&trace_mutex_);
|
||||
if (tracer_) {
|
||||
s = tracer_->IteratorSeek(cf_id, key);
|
||||
s = tracer_->IteratorSeek(cf_id, key, lower_bound, upper_bound);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::TraceIteratorSeekForPrev(const uint32_t& cf_id,
|
||||
const Slice& key) {
|
||||
Status DBImpl::TraceIteratorSeekForPrev(const uint32_t& cf_id, const Slice& key,
|
||||
const Slice& lower_bound,
|
||||
const Slice upper_bound) {
|
||||
Status s;
|
||||
if (tracer_) {
|
||||
InstrumentedMutexLock lock(&trace_mutex_);
|
||||
if (tracer_) {
|
||||
s = tracer_->IteratorSeekForPrev(cf_id, key);
|
||||
s = tracer_->IteratorSeekForPrev(cf_id, key, lower_bound, upper_bound);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
|
||||
+10
-2
@@ -595,8 +595,11 @@ class DBImpl : public DB {
|
||||
bool* found_record_for_key,
|
||||
bool* is_blob_index = nullptr);
|
||||
|
||||
Status TraceIteratorSeek(const uint32_t& cf_id, const Slice& key);
|
||||
Status TraceIteratorSeekForPrev(const uint32_t& cf_id, const Slice& key);
|
||||
Status TraceIteratorSeek(const uint32_t& cf_id, const Slice& key,
|
||||
const Slice& lower_bound, const Slice upper_bound);
|
||||
Status TraceIteratorSeekForPrev(const uint32_t& cf_id, const Slice& key,
|
||||
const Slice& lower_bound,
|
||||
const Slice upper_bound);
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Similar to GetSnapshot(), but also lets the db know that this snapshot
|
||||
@@ -954,6 +957,9 @@ class DBImpl : public DB {
|
||||
// is only for the special test of CancelledCompactions
|
||||
Status TEST_WaitForCompact(bool waitUnscheduled = false);
|
||||
|
||||
// Get the background error status
|
||||
Status TEST_GetBGError();
|
||||
|
||||
// Return the maximum overlapping data (in bytes) at next level for any
|
||||
// file at a level >= 1.
|
||||
int64_t TEST_MaxNextLevelOverlappingBytes(
|
||||
@@ -1870,6 +1876,8 @@ class DBImpl : public DB {
|
||||
|
||||
Status DisableFileDeletionsWithLock();
|
||||
|
||||
Status IncreaseFullHistoryTsLow(ColumnFamilyData* cfd, std::string ts_low);
|
||||
|
||||
// table_cache_ provides its own synchronization
|
||||
std::shared_ptr<Cache> table_cache_;
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@ bool DBImpl::EnoughRoomForCompaction(
|
||||
// Pass the current bg_error_ to SFM so it can decide what checks to
|
||||
// perform. If this DB instance hasn't seen any error yet, the SFM can be
|
||||
// optimistic and not do disk space checks
|
||||
enough_room =
|
||||
sfm->EnoughRoomForCompaction(cfd, inputs, error_handler_.GetBGError());
|
||||
Status bg_error = error_handler_.GetBGError();
|
||||
enough_room = sfm->EnoughRoomForCompaction(cfd, inputs, bg_error);
|
||||
bg_error.PermitUncheckedError(); // bg_error is just a copy of the Status
|
||||
// from the error_handler_
|
||||
if (enough_room) {
|
||||
*sfm_reserved_compact_space = true;
|
||||
}
|
||||
@@ -284,7 +286,10 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
// Notify sst_file_manager that a new file was added
|
||||
std::string file_path = MakeTableFileName(
|
||||
cfd->ioptions()->cf_paths[0].path, file_meta.fd.GetNumber());
|
||||
sfm->OnAddFile(file_path);
|
||||
// TODO (PR7798). We should only add the file to the FileManager if it
|
||||
// exists. Otherwise, some tests may fail. Ignore the error in the
|
||||
// interim.
|
||||
sfm->OnAddFile(file_path).PermitUncheckedError();
|
||||
if (sfm->IsMaxAllowedSpaceReached()) {
|
||||
Status new_bg_error =
|
||||
Status::SpaceLimit("Max allowed space was reached");
|
||||
@@ -618,7 +623,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(
|
||||
immutable_db_options_.sst_file_manager.get());
|
||||
assert(all_mutable_cf_options.size() == static_cast<size_t>(num_cfs));
|
||||
for (int i = 0; i != num_cfs; ++i) {
|
||||
for (int i = 0; s.ok() && i != num_cfs; ++i) {
|
||||
if (cfds[i]->IsDropped()) {
|
||||
continue;
|
||||
}
|
||||
@@ -627,7 +632,10 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
if (sfm) {
|
||||
std::string file_path = MakeTableFileName(
|
||||
cfds[i]->ioptions()->cf_paths[0].path, file_meta[i].fd.GetNumber());
|
||||
sfm->OnAddFile(file_path);
|
||||
// TODO (PR7798). We should only add the file to the FileManager if it
|
||||
// exists. Otherwise, some tests may fail. Ignore the error in the
|
||||
// interim.
|
||||
sfm->OnAddFile(file_path).PermitUncheckedError();
|
||||
if (sfm->IsMaxAllowedSpaceReached() &&
|
||||
error_handler_.GetBGError().ok()) {
|
||||
Status new_bg_error =
|
||||
@@ -798,6 +806,25 @@ Status DBImpl::CompactRange(const CompactRangeOptions& options,
|
||||
end_with_ts);
|
||||
}
|
||||
|
||||
Status DBImpl::IncreaseFullHistoryTsLow(ColumnFamilyData* cfd,
|
||||
std::string ts_low) {
|
||||
VersionEdit edit;
|
||||
edit.SetColumnFamily(cfd->GetID());
|
||||
edit.SetFullHistoryTsLow(ts_low);
|
||||
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
std::string current_ts_low = cfd->GetFullHistoryTsLow();
|
||||
const Comparator* ucmp = cfd->user_comparator();
|
||||
if (!current_ts_low.empty() &&
|
||||
ucmp->CompareTimestamp(ts_low, current_ts_low) < 0) {
|
||||
return Status::InvalidArgument(
|
||||
"Cannot decrease full_history_timestamp_low");
|
||||
}
|
||||
|
||||
return versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(), &edit,
|
||||
&mutex_);
|
||||
}
|
||||
|
||||
Status DBImpl::CompactRangeInternal(const CompactRangeOptions& options,
|
||||
ColumnFamilyHandle* column_family,
|
||||
const Slice* begin, const Slice* end) {
|
||||
@@ -809,20 +836,36 @@ Status DBImpl::CompactRangeInternal(const CompactRangeOptions& options,
|
||||
}
|
||||
|
||||
bool flush_needed = true;
|
||||
|
||||
// Update full_history_ts_low if it's set
|
||||
if (options.full_history_ts_low != nullptr &&
|
||||
!options.full_history_ts_low->empty()) {
|
||||
std::string ts_low = options.full_history_ts_low->ToString();
|
||||
if (begin != nullptr || end != nullptr) {
|
||||
return Status::InvalidArgument(
|
||||
"Cannot specify compaction range with full_history_ts_low");
|
||||
}
|
||||
Status s = IncreaseFullHistoryTsLow(cfd, ts_low);
|
||||
if (!s.ok()) {
|
||||
LogFlush(immutable_db_options_.info_log);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
Status s;
|
||||
if (begin != nullptr && end != nullptr) {
|
||||
// TODO(ajkr): We could also optimize away the flush in certain cases where
|
||||
// one/both sides of the interval are unbounded. But it requires more
|
||||
// changes to RangesOverlapWithMemtables.
|
||||
Range range(*begin, *end);
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
cfd->RangesOverlapWithMemtables({range}, super_version,
|
||||
immutable_db_options_.allow_data_in_errors,
|
||||
&flush_needed);
|
||||
s = cfd->RangesOverlapWithMemtables(
|
||||
{range}, super_version, immutable_db_options_.allow_data_in_errors,
|
||||
&flush_needed);
|
||||
CleanupSuperVersion(super_version);
|
||||
}
|
||||
|
||||
Status s;
|
||||
if (flush_needed) {
|
||||
if (s.ok() && flush_needed) {
|
||||
FlushOptions fo;
|
||||
fo.allow_write_stall = options.allow_write_stall;
|
||||
if (immutable_db_options_.atomic_flush) {
|
||||
@@ -1194,7 +1237,8 @@ Status DBImpl::CompactFilesImpl(
|
||||
mutex_.Unlock();
|
||||
TEST_SYNC_POINT("CompactFilesImpl:0");
|
||||
TEST_SYNC_POINT("CompactFilesImpl:1");
|
||||
compaction_job.Run();
|
||||
// Ignore the status here, as it will be checked in the Install down below...
|
||||
compaction_job.Run().PermitUncheckedError();
|
||||
TEST_SYNC_POINT("CompactFilesImpl:2");
|
||||
TEST_SYNC_POINT("CompactFilesImpl:3");
|
||||
mutex_.Lock();
|
||||
@@ -1391,8 +1435,6 @@ Status DBImpl::ReFitLevel(ColumnFamilyData* cfd, int level, int target_level) {
|
||||
|
||||
SuperVersionContext sv_context(/* create_superversion */ true);
|
||||
|
||||
Status status;
|
||||
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
|
||||
// only allow one thread refitting
|
||||
@@ -1456,8 +1498,9 @@ Status DBImpl::ReFitLevel(ColumnFamilyData* cfd, int level, int target_level) {
|
||||
"[%s] Apply version edit:\n%s", cfd->GetName().c_str(),
|
||||
edit.DebugString().data());
|
||||
|
||||
status = versions_->LogAndApply(cfd, mutable_cf_options, &edit, &mutex_,
|
||||
directories_.GetDbDir());
|
||||
Status status = versions_->LogAndApply(cfd, mutable_cf_options, &edit,
|
||||
&mutex_, directories_.GetDbDir());
|
||||
|
||||
InstallSuperVersionAndScheduleWork(cfd, &sv_context, mutable_cf_options);
|
||||
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log, "[%s] LogAndApply: %s\n",
|
||||
@@ -1468,12 +1511,14 @@ Status DBImpl::ReFitLevel(ColumnFamilyData* cfd, int level, int target_level) {
|
||||
"[%s] After refitting:\n%s", cfd->GetName().c_str(),
|
||||
cfd->current()->DebugString().data());
|
||||
}
|
||||
sv_context.Clean();
|
||||
refitting_level_ = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
sv_context.Clean();
|
||||
refitting_level_ = false;
|
||||
|
||||
return status;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int DBImpl::NumberLevels(ColumnFamilyHandle* column_family) {
|
||||
|
||||
@@ -177,6 +177,11 @@ Status DBImpl::TEST_WaitForCompact(bool wait_unscheduled) {
|
||||
return error_handler_.GetBGError();
|
||||
}
|
||||
|
||||
Status DBImpl::TEST_GetBGError() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
return error_handler_.GetBGError();
|
||||
}
|
||||
|
||||
void DBImpl::TEST_LockMutex() { mutex_.Lock(); }
|
||||
|
||||
void DBImpl::TEST_UnlockMutex() { mutex_.Unlock(); }
|
||||
|
||||
@@ -191,7 +191,8 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
// set of all files in the directory. We'll exclude files that are still
|
||||
// alive in the subsequent processings.
|
||||
std::vector<std::string> files;
|
||||
env_->GetChildren(path, &files).PermitUncheckedError(); // Ignore errors
|
||||
Status s = env_->GetChildren(path, &files);
|
||||
s.PermitUncheckedError(); // TODO: What should we do on error?
|
||||
for (const std::string& file : files) {
|
||||
uint64_t number;
|
||||
FileType type;
|
||||
@@ -207,7 +208,8 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(icanadi) clean up this mess to avoid having one-off "/" prefixes
|
||||
// TODO(icanadi) clean up this mess to avoid having one-off "/"
|
||||
// prefixes
|
||||
job_context->full_scan_candidate_files.emplace_back("/" + file, path);
|
||||
}
|
||||
}
|
||||
@@ -215,9 +217,8 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
// Add log files in wal_dir
|
||||
if (immutable_db_options_.wal_dir != dbname_) {
|
||||
std::vector<std::string> log_files;
|
||||
env_->GetChildren(immutable_db_options_.wal_dir,
|
||||
&log_files)
|
||||
.PermitUncheckedError(); // Ignore errors
|
||||
Status s = env_->GetChildren(immutable_db_options_.wal_dir, &log_files);
|
||||
s.PermitUncheckedError(); // TODO: What should we do on error?
|
||||
for (const std::string& log_file : log_files) {
|
||||
job_context->full_scan_candidate_files.emplace_back(
|
||||
log_file, immutable_db_options_.wal_dir);
|
||||
@@ -227,9 +228,9 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
if (!immutable_db_options_.db_log_dir.empty() &&
|
||||
immutable_db_options_.db_log_dir != dbname_) {
|
||||
std::vector<std::string> info_log_files;
|
||||
// Ignore errors
|
||||
env_->GetChildren(immutable_db_options_.db_log_dir, &info_log_files)
|
||||
.PermitUncheckedError();
|
||||
Status s =
|
||||
env_->GetChildren(immutable_db_options_.db_log_dir, &info_log_files);
|
||||
s.PermitUncheckedError(); // TODO: What should we do on error?
|
||||
for (std::string& log_file : info_log_files) {
|
||||
job_context->full_scan_candidate_files.emplace_back(
|
||||
log_file, immutable_db_options_.db_log_dir);
|
||||
|
||||
@@ -147,7 +147,8 @@ DBOptions SanitizeOptions(const std::string& dbname, const DBOptions& src) {
|
||||
// DeleteScheduler::CleanupDirectory on the same dir later, it will be
|
||||
// safe
|
||||
std::vector<std::string> filenames;
|
||||
result.env->GetChildren(result.wal_dir, &filenames).PermitUncheckedError();
|
||||
Status s = result.env->GetChildren(result.wal_dir, &filenames);
|
||||
s.PermitUncheckedError(); //**TODO: What to do on error?
|
||||
for (std::string& filename : filenames) {
|
||||
if (filename.find(".log.trash", filename.length() -
|
||||
std::string(".log.trash").length()) !=
|
||||
@@ -163,7 +164,8 @@ DBOptions SanitizeOptions(const std::string& dbname, const DBOptions& src) {
|
||||
// was not used)
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(result.sst_file_manager.get());
|
||||
for (size_t i = 0; i < result.db_paths.size(); i++) {
|
||||
DeleteScheduler::CleanupDirectory(result.env, sfm, result.db_paths[i].path);
|
||||
DeleteScheduler::CleanupDirectory(result.env, sfm, result.db_paths[i].path)
|
||||
.PermitUncheckedError();
|
||||
}
|
||||
|
||||
// Create a default SstFileManager for purposes of tracking compaction size
|
||||
@@ -287,11 +289,13 @@ Status DBImpl::NewDB(std::vector<std::string>* new_filenames) {
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
FileTypeSet tmp_set = immutable_db_options_.checksum_handoff_file_types;
|
||||
file->SetPreallocationBlockSize(
|
||||
immutable_db_options_.manifest_preallocation_size);
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(file), manifest, file_options, env_, io_tracer_,
|
||||
nullptr /* stats */, immutable_db_options_.listeners));
|
||||
nullptr /* stats */, immutable_db_options_.listeners, nullptr,
|
||||
tmp_set.Contains(FileType::kDescriptorFile)));
|
||||
log::Writer log(std::move(file_writer), 0, false);
|
||||
std::string record;
|
||||
new_db.EncodeTo(&record);
|
||||
@@ -1389,7 +1393,9 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
|
||||
meta.oldest_ancester_time, meta.file_creation_time,
|
||||
meta.file_checksum, meta.file_checksum_func_name);
|
||||
|
||||
edit->SetBlobFileAdditions(std::move(blob_file_additions));
|
||||
for (const auto& blob : blob_file_additions) {
|
||||
edit->AddBlobFile(blob);
|
||||
}
|
||||
}
|
||||
|
||||
InternalStats::CompactionStats stats(CompactionReason::kFlush, 1);
|
||||
@@ -1483,9 +1489,11 @@ IOStatus DBImpl::CreateWAL(uint64_t log_file_num, uint64_t recycle_log_number,
|
||||
lfile->SetPreallocationBlockSize(preallocate_block_size);
|
||||
|
||||
const auto& listeners = immutable_db_options_.listeners;
|
||||
FileTypeSet tmp_set = immutable_db_options_.checksum_handoff_file_types;
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(lfile), log_fname, opt_file_options, env_, io_tracer_,
|
||||
nullptr /* stats */, listeners));
|
||||
nullptr /* stats */, listeners, nullptr,
|
||||
tmp_set.Contains(FileType::kWalFile)));
|
||||
*new_log = new log::Writer(std::move(file_writer), log_file_num,
|
||||
immutable_db_options_.recycle_log_file_num > 0,
|
||||
immutable_db_options_.manual_wal_flush);
|
||||
@@ -1739,9 +1747,8 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
paths.erase(std::unique(paths.begin(), paths.end()), paths.end());
|
||||
for (auto& path : paths) {
|
||||
std::vector<std::string> existing_files;
|
||||
// TODO: Check for errors here?
|
||||
impl->immutable_db_options_.env->GetChildren(path, &existing_files)
|
||||
.PermitUncheckedError();
|
||||
.PermitUncheckedError(); //**TODO: What do to on error?
|
||||
for (auto& file_name : existing_files) {
|
||||
uint64_t file_number;
|
||||
FileType file_type;
|
||||
|
||||
@@ -143,9 +143,6 @@ Status OpenForReadOnlyCheckExistence(const DBOptions& db_options,
|
||||
uint64_t manifest_file_number;
|
||||
s = VersionSet::GetCurrentManifestPath(dbname, fs.get(), &manifest_path,
|
||||
&manifest_file_number);
|
||||
if (!s.ok()) {
|
||||
return Status::NotFound(CurrentFileName(dbname), "does not exist");
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,6 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
StopWatch write_sw(env_, immutable_db_options_.statistics.get(), DB_WRITE);
|
||||
|
||||
write_thread_.JoinBatchGroup(&w);
|
||||
Status status;
|
||||
if (w.state == WriteThread::STATE_PARALLEL_MEMTABLE_WRITER) {
|
||||
// we are a non-leader in a parallel group
|
||||
|
||||
@@ -193,8 +192,6 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
}
|
||||
assert(w.state == WriteThread::STATE_COMPLETED);
|
||||
// STATE_COMPLETED conditional below handles exit
|
||||
|
||||
status = w.FinalStatus();
|
||||
}
|
||||
if (w.state == WriteThread::STATE_COMPLETED) {
|
||||
if (log_used != nullptr) {
|
||||
@@ -204,13 +201,11 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
*seq_used = w.sequence;
|
||||
}
|
||||
// write is complete and leader has updated sequence
|
||||
// Should we handle it?
|
||||
status.PermitUncheckedError();
|
||||
return w.FinalStatus();
|
||||
}
|
||||
// else we are the leader of the write batch group
|
||||
assert(w.state == WriteThread::STATE_GROUP_LEADER);
|
||||
|
||||
Status status;
|
||||
// Once reaches this point, the current writer "w" will try to do its write
|
||||
// job. It may also pick up some of the remaining writers in the "writers_"
|
||||
// when it finds suitable, and finish them in the same write batch.
|
||||
@@ -531,6 +526,8 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
|
||||
PERF_TIMER_STOP(write_pre_and_post_process_time);
|
||||
|
||||
IOStatus io_s;
|
||||
io_s.PermitUncheckedError(); // Allow io_s to be uninitialized
|
||||
|
||||
if (w.status.ok() && !write_options.disableWAL) {
|
||||
PERF_TIMER_GUARD(write_wal_time);
|
||||
stats->AddDBStats(InternalStats::kIntStatsWriteDoneBySelf, 1);
|
||||
@@ -566,7 +563,12 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
|
||||
write_thread_.ExitAsBatchGroupLeader(wal_write_group, w.status);
|
||||
}
|
||||
|
||||
// NOTE: the memtable_write_group is declared before the following
|
||||
// `if` statement because its lifetime needs to be longer
|
||||
// that the inner context of the `if` as a reference to it
|
||||
// may be used further below within the outer _write_thread
|
||||
WriteThread::WriteGroup memtable_write_group;
|
||||
|
||||
if (w.state == WriteThread::STATE_MEMTABLE_WRITER_LEADER) {
|
||||
PERF_TIMER_GUARD(write_memtable_time);
|
||||
assert(w.ShouldWriteToMemtable());
|
||||
@@ -583,6 +585,10 @@ Status DBImpl::PipelinedWriteImpl(const WriteOptions& write_options,
|
||||
versions_->SetLastSequence(memtable_write_group.last_sequence);
|
||||
write_thread_.ExitAsMemTableWriter(&w, memtable_write_group);
|
||||
}
|
||||
} else {
|
||||
// NOTE: the memtable_write_group is never really used,
|
||||
// so we need to set its status to pass ASSERT_STATUS_CHECKED
|
||||
memtable_write_group.status.PermitUncheckedError();
|
||||
}
|
||||
|
||||
if (w.state == WriteThread::STATE_PARALLEL_MEMTABLE_WRITER) {
|
||||
@@ -767,6 +773,7 @@ Status DBImpl::WriteImplWALOnly(
|
||||
}
|
||||
Status status;
|
||||
IOStatus io_s;
|
||||
io_s.PermitUncheckedError(); // Allow io_s to be uninitialized
|
||||
if (!write_options.disableWAL) {
|
||||
io_s = ConcurrentWriteToWAL(write_group, log_used, &last_sequence, seq_inc);
|
||||
status = io_s;
|
||||
|
||||
@@ -64,9 +64,10 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
break;
|
||||
case kWalFile:
|
||||
if (env->GetFileSize(dbname + "/" + file, &file_size).ok()) {
|
||||
char str[16];
|
||||
snprintf(str, sizeof(str), "%" PRIu64, file_size);
|
||||
wal_info.append(file).append(" size: ").append(str).append(" ; ");
|
||||
wal_info.append(file)
|
||||
.append(" size: ")
|
||||
.append(std::to_string(file_size))
|
||||
.append(" ; ");
|
||||
} else {
|
||||
Error(options.info_log, "Error when reading LOG file: %s/%s\n",
|
||||
dbname.c_str(), file.c_str());
|
||||
@@ -120,9 +121,10 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
if (ParseFileName(file, &number, &type)) {
|
||||
if (type == kWalFile) {
|
||||
if (env->GetFileSize(options.wal_dir + "/" + file, &file_size).ok()) {
|
||||
char str[16];
|
||||
snprintf(str, sizeof(str), "%" PRIu64, file_size);
|
||||
wal_info.append(file).append(" size: ").append(str).append(" ; ");
|
||||
wal_info.append(file)
|
||||
.append(" size: ")
|
||||
.append(std::to_string(file_size))
|
||||
.append(" ; ");
|
||||
} else {
|
||||
Error(options.info_log, "Error when reading LOG file %s/%s\n",
|
||||
options.wal_dir.c_str(), file.c_str());
|
||||
|
||||
+68
-46
@@ -43,11 +43,15 @@ TEST_F(DBIOFailureTest, DropWrites) {
|
||||
if (level > 0 && level == dbfull()->NumberLevels() - 1) {
|
||||
break;
|
||||
}
|
||||
dbfull()->TEST_CompactRange(level, nullptr, nullptr, nullptr,
|
||||
true /* disallow trivial move */);
|
||||
Status s =
|
||||
dbfull()->TEST_CompactRange(level, nullptr, nullptr, nullptr,
|
||||
true /* disallow trivial move */);
|
||||
ASSERT_TRUE(s.ok() || s.IsCorruption());
|
||||
}
|
||||
} else {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
Status s =
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_TRUE(s.ok() || s.IsCorruption());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +60,8 @@ TEST_F(DBIOFailureTest, DropWrites) {
|
||||
ASSERT_EQ("5", property_value);
|
||||
|
||||
env_->drop_writes_.store(false, std::memory_order_release);
|
||||
ASSERT_LT(CountFiles(), num_files + 3);
|
||||
const size_t count = CountFiles();
|
||||
ASSERT_LT(count, num_files + 3);
|
||||
|
||||
// Check that compaction attempts slept after errors
|
||||
// TODO @krad: Figure out why ASSERT_EQ 5 keeps failing in certain compiler
|
||||
@@ -82,7 +87,8 @@ TEST_F(DBIOFailureTest, DropWritesFlush) {
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.background-errors", &property_value));
|
||||
ASSERT_EQ("0", property_value);
|
||||
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
// ASSERT file is too short
|
||||
ASSERT_TRUE(dbfull()->TEST_FlushMemTable(true).IsCorruption());
|
||||
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.background-errors", &property_value));
|
||||
ASSERT_EQ("1", property_value);
|
||||
@@ -166,7 +172,7 @@ TEST_F(DBIOFailureTest, ManifestWriteError) {
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
|
||||
// Memtable compaction (will succeed)
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
const int last = 2;
|
||||
MoveFilesToLevel(2);
|
||||
@@ -174,7 +180,8 @@ TEST_F(DBIOFailureTest, ManifestWriteError) {
|
||||
|
||||
// Merging compaction (will fail)
|
||||
error_type->store(true, std::memory_order_release);
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr); // Should fail
|
||||
ASSERT_NOK(
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr)); // Should fail
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
|
||||
error_type->store(false, std::memory_order_release);
|
||||
@@ -192,7 +199,13 @@ TEST_F(DBIOFailureTest, ManifestWriteError) {
|
||||
|
||||
// Merging compaction (will fail)
|
||||
error_type->store(true, std::memory_order_release);
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr); // Should fail
|
||||
Status s =
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr); // Should fail
|
||||
if (iter == 0) {
|
||||
ASSERT_OK(s);
|
||||
} else {
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
}
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
|
||||
// Recovery: should not lose data
|
||||
@@ -220,18 +233,15 @@ TEST_F(DBIOFailureTest, PutFailsParanoid) {
|
||||
options.paranoid_checks = true;
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
// simulate error
|
||||
env_->log_write_error_.store(true, std::memory_order_release);
|
||||
s = Put(1, "foo2", "bar2");
|
||||
ASSERT_TRUE(!s.ok());
|
||||
ASSERT_NOK(Put(1, "foo2", "bar2"));
|
||||
env_->log_write_error_.store(false, std::memory_order_release);
|
||||
s = Put(1, "foo3", "bar3");
|
||||
// the next put should fail, too
|
||||
ASSERT_TRUE(!s.ok());
|
||||
ASSERT_NOK(Put(1, "foo3", "bar3"));
|
||||
// but we're still able to read
|
||||
ASSERT_EQ("bar", Get(1, "foo"));
|
||||
|
||||
@@ -244,12 +254,10 @@ TEST_F(DBIOFailureTest, PutFailsParanoid) {
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
// simulate error
|
||||
env_->log_write_error_.store(true, std::memory_order_release);
|
||||
s = Put(1, "foo2", "bar2");
|
||||
ASSERT_TRUE(!s.ok());
|
||||
ASSERT_NOK(Put(1, "foo2", "bar2"));
|
||||
env_->log_write_error_.store(false, std::memory_order_release);
|
||||
s = Put(1, "foo3", "bar3");
|
||||
// the next put should NOT fail
|
||||
ASSERT_TRUE(s.ok());
|
||||
ASSERT_OK(Put(1, "foo3", "bar3"));
|
||||
}
|
||||
#if !(defined NDEBUG) || !defined(OS_WIN)
|
||||
TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
@@ -269,14 +277,14 @@ TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
const char* io_error_msg = "range sync dummy error";
|
||||
std::atomic<int> range_sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::RangeSync", [&](void* arg) {
|
||||
if (range_sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("range sync dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
@@ -298,7 +306,9 @@ TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
ASSERT_OK(Put(1, "foo3_2", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo3_3", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo4", "bar"));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
Status s = dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -328,7 +338,6 @@ TEST_F(DBIOFailureTest, CompactSstRangeSyncError) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
Random rnd(301);
|
||||
std::string rnd_str =
|
||||
@@ -342,21 +351,22 @@ TEST_F(DBIOFailureTest, CompactSstRangeSyncError) {
|
||||
ASSERT_OK(Put(1, "foo1_1", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo1_2", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo1_3", rnd_str));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo3_1", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo3_2", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo3_3", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo4", "bar"));
|
||||
Flush(1);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(handles_[1]));
|
||||
|
||||
const char* io_error_msg = "range sync dummy error";
|
||||
std::atomic<int> range_sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::RangeSync", [&](void* arg) {
|
||||
if (range_sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("range sync dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
@@ -365,7 +375,9 @@ TEST_F(DBIOFailureTest, CompactSstRangeSyncError) {
|
||||
{
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
Status s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -389,13 +401,14 @@ TEST_F(DBIOFailureTest, FlushSstCloseError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
const char* io_error_msg = "close dummy error";
|
||||
std::atomic<int> close_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Close", [&](void* arg) {
|
||||
if (close_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("close dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -404,7 +417,9 @@ TEST_F(DBIOFailureTest, FlushSstCloseError) {
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
Status s = dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -429,25 +444,25 @@ TEST_F(DBIOFailureTest, CompactionSstCloseError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar3"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
const char* io_error_msg = "close dummy error";
|
||||
std::atomic<int> close_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Close", [&](void* arg) {
|
||||
if (close_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("close dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -456,7 +471,9 @@ TEST_F(DBIOFailureTest, CompactionSstCloseError) {
|
||||
{
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
Status s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as compaction failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -480,13 +497,14 @@ TEST_F(DBIOFailureTest, FlushSstSyncError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
const char* io_error_msg = "sync dummy error";
|
||||
std::atomic<int> sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Sync", [&](void* arg) {
|
||||
if (sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("sync dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -495,7 +513,9 @@ TEST_F(DBIOFailureTest, FlushSstSyncError) {
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
Status s = dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -521,25 +541,25 @@ TEST_F(DBIOFailureTest, CompactionSstSyncError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar3"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
const char* io_error_msg = "sync dummy error";
|
||||
std::atomic<int> sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Sync", [&](void* arg) {
|
||||
if (sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("close dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -548,7 +568,9 @@ TEST_F(DBIOFailureTest, CompactionSstSyncError) {
|
||||
{
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
Status s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as compaction failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
|
||||
+27
-2
@@ -1254,7 +1254,19 @@ void DBIter::Seek(const Slice& target) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (db_impl_ != nullptr && cfd_ != nullptr) {
|
||||
// TODO: What do we do if this returns an error?
|
||||
db_impl_->TraceIteratorSeek(cfd_->GetID(), target).PermitUncheckedError();
|
||||
Slice lower_bound, upper_bound;
|
||||
if (iterate_lower_bound_ != nullptr) {
|
||||
lower_bound = *iterate_lower_bound_;
|
||||
} else {
|
||||
lower_bound = Slice("");
|
||||
}
|
||||
if (iterate_upper_bound_ != nullptr) {
|
||||
upper_bound = *iterate_upper_bound_;
|
||||
} else {
|
||||
upper_bound = Slice("");
|
||||
}
|
||||
db_impl_->TraceIteratorSeek(cfd_->GetID(), target, lower_bound, upper_bound)
|
||||
.PermitUncheckedError();
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
@@ -1316,7 +1328,20 @@ void DBIter::SeekForPrev(const Slice& target) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (db_impl_ != nullptr && cfd_ != nullptr) {
|
||||
// TODO: What do we do if this returns an error?
|
||||
db_impl_->TraceIteratorSeekForPrev(cfd_->GetID(), target)
|
||||
Slice lower_bound, upper_bound;
|
||||
if (iterate_lower_bound_ != nullptr) {
|
||||
lower_bound = *iterate_lower_bound_;
|
||||
} else {
|
||||
lower_bound = Slice("");
|
||||
}
|
||||
if (iterate_upper_bound_ != nullptr) {
|
||||
upper_bound = *iterate_upper_bound_;
|
||||
} else {
|
||||
upper_bound = Slice("");
|
||||
}
|
||||
db_impl_
|
||||
->TraceIteratorSeekForPrev(cfd_->GetID(), target, lower_bound,
|
||||
upper_bound)
|
||||
.PermitUncheckedError();
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
+17
-1
@@ -392,6 +392,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
|
||||
|
||||
db_iter->SeekToLast();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
// Test case to check SeekToLast with iterate_upper_bound set
|
||||
// (same key put may times - SeekToLast should start with the
|
||||
@@ -489,6 +490,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
|
||||
|
||||
db_iter->SeekToLast();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
// Test to check the SeekToLast() with the iterate_upper_bound set
|
||||
// (Deletion cases)
|
||||
@@ -596,6 +598,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
|
||||
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -689,6 +692,7 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
|
||||
nullptr /* read_callback */));
|
||||
db_iter->SeekToLast();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -702,6 +706,7 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
|
||||
nullptr /* read_callback */));
|
||||
db_iter->SeekToFirst();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,6 +749,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkipCountSkips) {
|
||||
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
ASSERT_EQ(TestGetTickerCount(options, NUMBER_OF_RESEEKS_IN_ITERATION), 3u);
|
||||
}
|
||||
|
||||
@@ -788,6 +794,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
db_iter->Prev();
|
||||
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,6 +827,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
db_iter->Prev();
|
||||
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -855,6 +863,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
db_iter->Prev();
|
||||
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,9 +882,11 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
nullptr /* read_callback */));
|
||||
db_iter->SeekToLast();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
|
||||
db_iter->SeekToFirst();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
|
||||
TestIterator* internal_iter = new TestIterator(BytewiseComparator());
|
||||
@@ -896,6 +907,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
|
||||
db_iter->SeekToFirst();
|
||||
ASSERT_TRUE(db_iter->Valid());
|
||||
@@ -904,6 +916,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
|
||||
db_iter->Next();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -943,6 +956,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
db_iter->Prev();
|
||||
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,6 +997,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1039,7 +1054,7 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
|
||||
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(!db_iter->Valid());
|
||||
ASSERT_TRUE(db_iter->status().ok());
|
||||
ASSERT_OK(db_iter->status());
|
||||
}
|
||||
|
||||
// Test to make sure that the request will *not* fail as incomplete if
|
||||
@@ -3136,6 +3151,7 @@ TEST_F(DBIteratorTest, SeekToFirstLowerBound) {
|
||||
if (i == kNumKeys + 1) {
|
||||
// lower bound was beyond the last key
|
||||
ASSERT_FALSE(db_iter->Valid());
|
||||
ASSERT_OK(db_iter->status());
|
||||
} else {
|
||||
ASSERT_TRUE(db_iter->Valid());
|
||||
int expected;
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) 2020-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
enum class WriteBatchOpType {
|
||||
kPut = 0,
|
||||
kDelete,
|
||||
kSingleDelete,
|
||||
kDeleteRange,
|
||||
kMerge,
|
||||
kBlobIndex,
|
||||
kNum,
|
||||
};
|
||||
|
||||
// Integer addition is needed for `::testing::Range()` to take the enum type.
|
||||
WriteBatchOpType operator+(WriteBatchOpType lhs, const int rhs) {
|
||||
using T = std::underlying_type<WriteBatchOpType>::type;
|
||||
return static_cast<WriteBatchOpType>(static_cast<T>(lhs) + rhs);
|
||||
}
|
||||
|
||||
class DbKvChecksumTest
|
||||
: public DBTestBase,
|
||||
public ::testing::WithParamInterface<std::tuple<WriteBatchOpType, char>> {
|
||||
public:
|
||||
DbKvChecksumTest()
|
||||
: DBTestBase("/db_kv_checksum_test", /*env_do_fsync=*/false) {
|
||||
op_type_ = std::get<0>(GetParam());
|
||||
corrupt_byte_addend_ = std::get<1>(GetParam());
|
||||
}
|
||||
|
||||
std::pair<WriteBatch, Status> GetWriteBatch(size_t ts_sz,
|
||||
ColumnFamilyHandle* cf_handle) {
|
||||
Status s;
|
||||
WriteBatch wb(0 /* reserved_bytes */, 0 /* max_bytes */, ts_sz,
|
||||
8 /* protection_bytes_per_entry */);
|
||||
switch (op_type_) {
|
||||
case WriteBatchOpType::kPut:
|
||||
s = wb.Put(cf_handle, "key", "val");
|
||||
break;
|
||||
case WriteBatchOpType::kDelete:
|
||||
s = wb.Delete(cf_handle, "key");
|
||||
break;
|
||||
case WriteBatchOpType::kSingleDelete:
|
||||
s = wb.SingleDelete(cf_handle, "key");
|
||||
break;
|
||||
case WriteBatchOpType::kDeleteRange:
|
||||
s = wb.DeleteRange(cf_handle, "begin", "end");
|
||||
break;
|
||||
case WriteBatchOpType::kMerge:
|
||||
s = wb.Merge(cf_handle, "key", "val");
|
||||
break;
|
||||
case WriteBatchOpType::kBlobIndex:
|
||||
// TODO(ajkr): use public API once available.
|
||||
uint32_t cf_id;
|
||||
if (cf_handle == nullptr) {
|
||||
cf_id = 0;
|
||||
} else {
|
||||
cf_id = cf_handle->GetID();
|
||||
}
|
||||
s = WriteBatchInternal::PutBlobIndex(&wb, cf_id, "key", "val");
|
||||
break;
|
||||
case WriteBatchOpType::kNum:
|
||||
assert(false);
|
||||
}
|
||||
return {std::move(wb), std::move(s)};
|
||||
}
|
||||
|
||||
void CorruptNextByteCallBack(void* arg) {
|
||||
Slice encoded = *static_cast<Slice*>(arg);
|
||||
if (entry_len_ == port::kMaxSizet) {
|
||||
// We learn the entry size on the first attempt
|
||||
entry_len_ = encoded.size();
|
||||
}
|
||||
// All entries should be the same size
|
||||
assert(entry_len_ == encoded.size());
|
||||
char* buf = const_cast<char*>(encoded.data());
|
||||
buf[corrupt_byte_offset_] += corrupt_byte_addend_;
|
||||
++corrupt_byte_offset_;
|
||||
}
|
||||
|
||||
bool MoreBytesToCorrupt() { return corrupt_byte_offset_ < entry_len_; }
|
||||
|
||||
protected:
|
||||
WriteBatchOpType op_type_;
|
||||
char corrupt_byte_addend_;
|
||||
size_t corrupt_byte_offset_ = 0;
|
||||
size_t entry_len_ = port::kMaxSizet;
|
||||
};
|
||||
|
||||
std::string GetTestNameSuffix(
|
||||
::testing::TestParamInfo<std::tuple<WriteBatchOpType, char>> info) {
|
||||
std::ostringstream oss;
|
||||
switch (std::get<0>(info.param)) {
|
||||
case WriteBatchOpType::kPut:
|
||||
oss << "Put";
|
||||
break;
|
||||
case WriteBatchOpType::kDelete:
|
||||
oss << "Delete";
|
||||
break;
|
||||
case WriteBatchOpType::kSingleDelete:
|
||||
oss << "SingleDelete";
|
||||
break;
|
||||
case WriteBatchOpType::kDeleteRange:
|
||||
oss << "DeleteRange";
|
||||
break;
|
||||
case WriteBatchOpType::kMerge:
|
||||
oss << "Merge";
|
||||
break;
|
||||
case WriteBatchOpType::kBlobIndex:
|
||||
oss << "BlobIndex";
|
||||
break;
|
||||
case WriteBatchOpType::kNum:
|
||||
assert(false);
|
||||
}
|
||||
oss << "Add"
|
||||
<< static_cast<int>(static_cast<unsigned char>(std::get<1>(info.param)));
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
DbKvChecksumTest, DbKvChecksumTest,
|
||||
::testing::Combine(::testing::Range(static_cast<WriteBatchOpType>(0),
|
||||
WriteBatchOpType::kNum),
|
||||
::testing::Values(2, 103, 251)),
|
||||
GetTestNameSuffix);
|
||||
|
||||
TEST_P(DbKvChecksumTest, MemTableAddCorrupted) {
|
||||
// This test repeatedly attempts to write `WriteBatch`es containing a single
|
||||
// entry of type `op_type_`. Each attempt has one byte corrupted in its
|
||||
// memtable entry by adding `corrupt_byte_addend_` to its original value. The
|
||||
// test repeats until an attempt has been made on each byte in the encoded
|
||||
// memtable entry. All attempts are expected to fail with `Status::Corruption`
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"MemTable::Add:Encoded",
|
||||
std::bind(&DbKvChecksumTest::CorruptNextByteCallBack, this,
|
||||
std::placeholders::_1));
|
||||
|
||||
while (MoreBytesToCorrupt()) {
|
||||
// Failed memtable insert always leads to read-only mode, so we have to
|
||||
// reopen for every attempt.
|
||||
Options options = CurrentOptions();
|
||||
if (op_type_ == WriteBatchOpType::kMerge) {
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
}
|
||||
Reopen(options);
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
auto batch_and_status =
|
||||
GetWriteBatch(0 /* ts_sz */, nullptr /* cf_handle */);
|
||||
ASSERT_OK(batch_and_status.second);
|
||||
ASSERT_TRUE(
|
||||
db_->Write(WriteOptions(), &batch_and_status.first).IsCorruption());
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DbKvChecksumTest, MemTableAddWithColumnFamilyCorrupted) {
|
||||
// This test repeatedly attempts to write `WriteBatch`es containing a single
|
||||
// entry of type `op_type_` to a non-default column family. Each attempt has
|
||||
// one byte corrupted in its memtable entry by adding `corrupt_byte_addend_`
|
||||
// to its original value. The test repeats until an attempt has been made on
|
||||
// each byte in the encoded memtable entry. All attempts are expected to fail
|
||||
// with `Status::Corruption`.
|
||||
Options options = CurrentOptions();
|
||||
if (op_type_ == WriteBatchOpType::kMerge) {
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
}
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"MemTable::Add:Encoded",
|
||||
std::bind(&DbKvChecksumTest::CorruptNextByteCallBack, this,
|
||||
std::placeholders::_1));
|
||||
|
||||
while (MoreBytesToCorrupt()) {
|
||||
// Failed memtable insert always leads to read-only mode, so we have to
|
||||
// reopen for every attempt.
|
||||
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "pikachu"}, options);
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
auto batch_and_status = GetWriteBatch(0 /* ts_sz */, handles_[1]);
|
||||
ASSERT_OK(batch_and_status.second);
|
||||
ASSERT_TRUE(
|
||||
db_->Write(WriteOptions(), &batch_and_status.first).IsCorruption());
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+51
-47
@@ -33,9 +33,8 @@ class DBTestXactLogIterator : public DBTestBase {
|
||||
};
|
||||
|
||||
namespace {
|
||||
SequenceNumber ReadRecords(
|
||||
std::unique_ptr<TransactionLogIterator>& iter,
|
||||
int& count) {
|
||||
SequenceNumber ReadRecords(std::unique_ptr<TransactionLogIterator>& iter,
|
||||
int& count, bool expect_ok = true) {
|
||||
count = 0;
|
||||
SequenceNumber lastSequence = 0;
|
||||
BatchResult res;
|
||||
@@ -47,6 +46,11 @@ SequenceNumber ReadRecords(
|
||||
EXPECT_OK(iter->status());
|
||||
iter->Next();
|
||||
}
|
||||
if (expect_ok) {
|
||||
EXPECT_OK(iter->status());
|
||||
} else {
|
||||
EXPECT_NOK(iter->status());
|
||||
}
|
||||
return res.sequence;
|
||||
}
|
||||
|
||||
@@ -64,9 +68,9 @@ TEST_F(DBTestXactLogIterator, TransactionLogIterator) {
|
||||
Options options = OptionsForLogIterTest();
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Put(0, "key1", DummyString(1024));
|
||||
Put(1, "key2", DummyString(1024));
|
||||
Put(1, "key2", DummyString(1024));
|
||||
ASSERT_OK(Put(0, "key1", DummyString(1024)));
|
||||
ASSERT_OK(Put(1, "key2", DummyString(1024)));
|
||||
ASSERT_OK(Put(1, "key2", DummyString(1024)));
|
||||
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 3U);
|
||||
{
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
@@ -75,9 +79,9 @@ TEST_F(DBTestXactLogIterator, TransactionLogIterator) {
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
env_->SleepForMicroseconds(2 * 1000 * 1000);
|
||||
{
|
||||
Put(0, "key4", DummyString(1024));
|
||||
Put(1, "key5", DummyString(1024));
|
||||
Put(0, "key6", DummyString(1024));
|
||||
ASSERT_OK(Put(0, "key4", DummyString(1024)));
|
||||
ASSERT_OK(Put(1, "key5", DummyString(1024)));
|
||||
ASSERT_OK(Put(0, "key6", DummyString(1024)));
|
||||
}
|
||||
{
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
@@ -109,15 +113,15 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorRace) {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
Options options = OptionsForLogIterTest();
|
||||
DestroyAndReopen(options);
|
||||
Put("key1", DummyString(1024));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
Put("key2", DummyString(1024));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
Put("key3", DummyString(1024));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
Put("key4", DummyString(1024));
|
||||
ASSERT_OK(Put("key1", DummyString(1024)));
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
ASSERT_OK(Put("key2", DummyString(1024)));
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
ASSERT_OK(Put("key3", DummyString(1024)));
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
ASSERT_OK(Put("key4", DummyString(1024)));
|
||||
ASSERT_EQ(dbfull()->GetLatestSequenceNumber(), 4U);
|
||||
dbfull()->FlushWAL(false);
|
||||
ASSERT_OK(dbfull()->FlushWAL(false));
|
||||
|
||||
{
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
@@ -130,11 +134,11 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorRace) {
|
||||
// condition
|
||||
FlushOptions flush_options;
|
||||
flush_options.wait = false;
|
||||
dbfull()->Flush(flush_options);
|
||||
ASSERT_OK(dbfull()->Flush(flush_options));
|
||||
|
||||
// "key5" would be written in a new memtable and log
|
||||
Put("key5", DummyString(1024));
|
||||
dbfull()->FlushWAL(false);
|
||||
ASSERT_OK(Put("key5", DummyString(1024)));
|
||||
ASSERT_OK(dbfull()->FlushWAL(false));
|
||||
{
|
||||
// this iter would miss "key4" if not fixed
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
@@ -149,14 +153,14 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorStallAtLastRecord) {
|
||||
do {
|
||||
Options options = OptionsForLogIterTest();
|
||||
DestroyAndReopen(options);
|
||||
Put("key1", DummyString(1024));
|
||||
ASSERT_OK(Put("key1", DummyString(1024)));
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
iter->Next();
|
||||
ASSERT_TRUE(!iter->Valid());
|
||||
ASSERT_OK(iter->status());
|
||||
Put("key2", DummyString(1024));
|
||||
ASSERT_OK(Put("key2", DummyString(1024)));
|
||||
iter->Next();
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
@@ -167,9 +171,9 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorCheckAfterRestart) {
|
||||
do {
|
||||
Options options = OptionsForLogIterTest();
|
||||
DestroyAndReopen(options);
|
||||
Put("key1", DummyString(1024));
|
||||
Put("key2", DummyString(1023));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
ASSERT_OK(Put("key1", DummyString(1024)));
|
||||
ASSERT_OK(Put("key2", DummyString(1023)));
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
Reopen(options);
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
ExpectRecords(2, iter);
|
||||
@@ -181,10 +185,10 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorCorruptedLog) {
|
||||
Options options = OptionsForLogIterTest();
|
||||
DestroyAndReopen(options);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
Put("key"+ToString(i), DummyString(10));
|
||||
ASSERT_OK(Put("key" + ToString(i), DummyString(10)));
|
||||
}
|
||||
dbfull()->Flush(FlushOptions());
|
||||
dbfull()->FlushWAL(false);
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
ASSERT_OK(dbfull()->FlushWAL(false));
|
||||
// Corrupt this log to create a gap
|
||||
ROCKSDB_NAMESPACE::VectorLogPtr wal_files;
|
||||
ASSERT_OK(dbfull()->GetSortedWalFiles(wal_files));
|
||||
@@ -197,13 +201,13 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorCorruptedLog) {
|
||||
}
|
||||
|
||||
// Insert a new entry to a new log file
|
||||
Put("key1025", DummyString(10));
|
||||
dbfull()->FlushWAL(false);
|
||||
ASSERT_OK(Put("key1025", DummyString(10)));
|
||||
ASSERT_OK(dbfull()->FlushWAL(false));
|
||||
// Try to read from the beginning. Should stop before the gap and read less
|
||||
// than 1025 entries
|
||||
auto iter = OpenTransactionLogIter(0);
|
||||
int count;
|
||||
SequenceNumber last_sequence_read = ReadRecords(iter, count);
|
||||
SequenceNumber last_sequence_read = ReadRecords(iter, count, false);
|
||||
ASSERT_LT(last_sequence_read, 1025U);
|
||||
// Try to read past the gap, should be able to seek to key1025
|
||||
auto iter2 = OpenTransactionLogIter(last_sequence_read + 1);
|
||||
@@ -217,15 +221,15 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorBatchOperations) {
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
WriteBatch batch;
|
||||
batch.Put(handles_[1], "key1", DummyString(1024));
|
||||
batch.Put(handles_[0], "key2", DummyString(1024));
|
||||
batch.Put(handles_[1], "key3", DummyString(1024));
|
||||
batch.Delete(handles_[0], "key2");
|
||||
dbfull()->Write(WriteOptions(), &batch);
|
||||
Flush(1);
|
||||
Flush(0);
|
||||
ASSERT_OK(batch.Put(handles_[1], "key1", DummyString(1024)));
|
||||
ASSERT_OK(batch.Put(handles_[0], "key2", DummyString(1024)));
|
||||
ASSERT_OK(batch.Put(handles_[1], "key3", DummyString(1024)));
|
||||
ASSERT_OK(batch.Delete(handles_[0], "key2"));
|
||||
ASSERT_OK(dbfull()->Write(WriteOptions(), &batch));
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Flush(0));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
Put(1, "key4", DummyString(1024));
|
||||
ASSERT_OK(Put(1, "key4", DummyString(1024)));
|
||||
auto iter = OpenTransactionLogIter(3);
|
||||
ExpectRecords(2, iter);
|
||||
} while (ChangeCompactOptions());
|
||||
@@ -237,13 +241,13 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorBlobs) {
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
{
|
||||
WriteBatch batch;
|
||||
batch.Put(handles_[1], "key1", DummyString(1024));
|
||||
batch.Put(handles_[0], "key2", DummyString(1024));
|
||||
batch.PutLogData(Slice("blob1"));
|
||||
batch.Put(handles_[1], "key3", DummyString(1024));
|
||||
batch.PutLogData(Slice("blob2"));
|
||||
batch.Delete(handles_[0], "key2");
|
||||
dbfull()->Write(WriteOptions(), &batch);
|
||||
ASSERT_OK(batch.Put(handles_[1], "key1", DummyString(1024)));
|
||||
ASSERT_OK(batch.Put(handles_[0], "key2", DummyString(1024)));
|
||||
ASSERT_OK(batch.PutLogData(Slice("blob1")));
|
||||
ASSERT_OK(batch.Put(handles_[1], "key3", DummyString(1024)));
|
||||
ASSERT_OK(batch.PutLogData(Slice("blob2")));
|
||||
ASSERT_OK(batch.Delete(handles_[0], "key2"));
|
||||
ASSERT_OK(dbfull()->Write(WriteOptions(), &batch));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
}
|
||||
|
||||
@@ -268,7 +272,7 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorBlobs) {
|
||||
return Status::OK();
|
||||
}
|
||||
} handler;
|
||||
res.writeBatchPtr->Iterate(&handler);
|
||||
ASSERT_OK(res.writeBatchPtr->Iterate(&handler));
|
||||
ASSERT_EQ(
|
||||
"Put(1, key1, 1024)"
|
||||
"Put(0, key2, 1024)"
|
||||
|
||||
+33
-19
@@ -145,15 +145,25 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
|
||||
kMaxSequenceNumber, 0 /* column_family_id */);
|
||||
|
||||
// Write some keys and make sure it returns false on duplicates
|
||||
ASSERT_OK(mem->Add(seq, kTypeValue, "key", "value2"));
|
||||
ASSERT_TRUE(mem->Add(seq, kTypeValue, "key", "value2").IsTryAgain());
|
||||
ASSERT_OK(
|
||||
mem->Add(seq, kTypeValue, "key", "value2", nullptr /* kv_prot_info */));
|
||||
ASSERT_TRUE(
|
||||
mem->Add(seq, kTypeValue, "key", "value2", nullptr /* kv_prot_info */)
|
||||
.IsTryAgain());
|
||||
// Changing the type should still cause the duplicatae key
|
||||
ASSERT_TRUE(mem->Add(seq, kTypeMerge, "key", "value2").IsTryAgain());
|
||||
ASSERT_TRUE(
|
||||
mem->Add(seq, kTypeMerge, "key", "value2", nullptr /* kv_prot_info */)
|
||||
.IsTryAgain());
|
||||
// Changing the seq number will make the key fresh
|
||||
ASSERT_OK(mem->Add(seq + 1, kTypeMerge, "key", "value2"));
|
||||
ASSERT_OK(mem->Add(seq + 1, kTypeMerge, "key", "value2",
|
||||
nullptr /* kv_prot_info */));
|
||||
// Test with different types for duplicate keys
|
||||
ASSERT_TRUE(mem->Add(seq, kTypeDeletion, "key", "").IsTryAgain());
|
||||
ASSERT_TRUE(mem->Add(seq, kTypeSingleDeletion, "key", "").IsTryAgain());
|
||||
ASSERT_TRUE(
|
||||
mem->Add(seq, kTypeDeletion, "key", "", nullptr /* kv_prot_info */)
|
||||
.IsTryAgain());
|
||||
ASSERT_TRUE(
|
||||
mem->Add(seq, kTypeSingleDeletion, "key", "", nullptr /* kv_prot_info */)
|
||||
.IsTryAgain());
|
||||
|
||||
// Test the duplicate keys under stress
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
@@ -161,7 +171,8 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
|
||||
if (!insert_dup) {
|
||||
seq++;
|
||||
}
|
||||
Status s = mem->Add(seq, kTypeValue, "foo", "value" + ToString(seq));
|
||||
Status s = mem->Add(seq, kTypeValue, "foo", "value" + ToString(seq),
|
||||
nullptr /* kv_prot_info */);
|
||||
if (insert_dup) {
|
||||
ASSERT_TRUE(s.IsTryAgain());
|
||||
} else {
|
||||
@@ -177,8 +188,11 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
|
||||
mem = new MemTable(cmp, ioptions, MutableCFOptions(options), &wb,
|
||||
kMaxSequenceNumber, 0 /* column_family_id */);
|
||||
// Insert a duplicate key with _ in it
|
||||
ASSERT_OK(mem->Add(seq, kTypeValue, "key_1", "value"));
|
||||
ASSERT_TRUE(mem->Add(seq, kTypeValue, "key_1", "value").IsTryAgain());
|
||||
ASSERT_OK(
|
||||
mem->Add(seq, kTypeValue, "key_1", "value", nullptr /* kv_prot_info */));
|
||||
ASSERT_TRUE(
|
||||
mem->Add(seq, kTypeValue, "key_1", "value", nullptr /* kv_prot_info */)
|
||||
.IsTryAgain());
|
||||
delete mem;
|
||||
|
||||
// Test when InsertConcurrently will be invoked
|
||||
@@ -187,11 +201,11 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
|
||||
mem = new MemTable(cmp, ioptions, MutableCFOptions(options), &wb,
|
||||
kMaxSequenceNumber, 0 /* column_family_id */);
|
||||
MemTablePostProcessInfo post_process_info;
|
||||
ASSERT_OK(
|
||||
mem->Add(seq, kTypeValue, "key", "value", true, &post_process_info));
|
||||
ASSERT_TRUE(
|
||||
mem->Add(seq, kTypeValue, "key", "value", true, &post_process_info)
|
||||
.IsTryAgain());
|
||||
ASSERT_OK(mem->Add(seq, kTypeValue, "key", "value",
|
||||
nullptr /* kv_prot_info */, true, &post_process_info));
|
||||
ASSERT_TRUE(mem->Add(seq, kTypeValue, "key", "value",
|
||||
nullptr /* kv_prot_info */, true, &post_process_info)
|
||||
.IsTryAgain());
|
||||
delete mem;
|
||||
}
|
||||
|
||||
@@ -217,7 +231,7 @@ TEST_F(DBMemTableTest, ConcurrentMergeWrite) {
|
||||
|
||||
// Put 0 as the base
|
||||
PutFixed64(&value, static_cast<uint64_t>(0));
|
||||
ASSERT_OK(mem->Add(0, kTypeValue, "key", value));
|
||||
ASSERT_OK(mem->Add(0, kTypeValue, "key", value, nullptr /* kv_prot_info */));
|
||||
value.clear();
|
||||
|
||||
// Write Merge concurrently
|
||||
@@ -226,8 +240,8 @@ TEST_F(DBMemTableTest, ConcurrentMergeWrite) {
|
||||
std::string v1;
|
||||
for (int seq = 1; seq < num_ops / 2; seq++) {
|
||||
PutFixed64(&v1, seq);
|
||||
ASSERT_OK(
|
||||
mem->Add(seq, kTypeMerge, "key", v1, true, &post_process_info1));
|
||||
ASSERT_OK(mem->Add(seq, kTypeMerge, "key", v1, nullptr /* kv_prot_info */,
|
||||
true, &post_process_info1));
|
||||
v1.clear();
|
||||
}
|
||||
});
|
||||
@@ -236,8 +250,8 @@ TEST_F(DBMemTableTest, ConcurrentMergeWrite) {
|
||||
std::string v2;
|
||||
for (int seq = num_ops / 2; seq < num_ops; seq++) {
|
||||
PutFixed64(&v2, seq);
|
||||
ASSERT_OK(
|
||||
mem->Add(seq, kTypeMerge, "key", v2, true, &post_process_info2));
|
||||
ASSERT_OK(mem->Add(seq, kTypeMerge, "key", v2, nullptr /* kv_prot_info */,
|
||||
true, &post_process_info2));
|
||||
v2.clear();
|
||||
}
|
||||
});
|
||||
|
||||
+81
-3
@@ -129,6 +129,83 @@ TEST_F(DBOptionsTest, GetLatestCFOptions) {
|
||||
GetMutableCFOptionsMap(dbfull()->GetOptions(handles_[1])));
|
||||
}
|
||||
|
||||
TEST_F(DBOptionsTest, SetMutableTableOptions) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.env = env_;
|
||||
options.blob_file_size = 16384;
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.no_block_cache = true;
|
||||
bbto.block_size = 8192;
|
||||
bbto.block_restart_interval = 7;
|
||||
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
Reopen(options);
|
||||
|
||||
ColumnFamilyHandle* cfh = dbfull()->DefaultColumnFamily();
|
||||
Options c_opts = dbfull()->GetOptions(cfh);
|
||||
const auto* c_bbto =
|
||||
c_opts.table_factory->GetOptions<BlockBasedTableOptions>();
|
||||
ASSERT_NE(c_bbto, nullptr);
|
||||
ASSERT_EQ(c_opts.blob_file_size, 16384);
|
||||
ASSERT_EQ(c_bbto->no_block_cache, true);
|
||||
ASSERT_EQ(c_bbto->block_size, 8192);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 7);
|
||||
ASSERT_OK(dbfull()->SetOptions(
|
||||
cfh, {{"table_factory.block_size", "16384"},
|
||||
{"table_factory.block_restart_interval", "11"}}));
|
||||
ASSERT_EQ(c_bbto->block_size, 16384);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 11);
|
||||
|
||||
// Now set an option that is not mutable - options should not change
|
||||
ASSERT_NOK(
|
||||
dbfull()->SetOptions(cfh, {{"table_factory.no_block_cache", "false"}}));
|
||||
ASSERT_EQ(c_bbto->no_block_cache, true);
|
||||
ASSERT_EQ(c_bbto->block_size, 16384);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 11);
|
||||
|
||||
// Set some that are mutable and some that are not - options should not change
|
||||
ASSERT_NOK(dbfull()->SetOptions(
|
||||
cfh, {{"table_factory.no_block_cache", "false"},
|
||||
{"table_factory.block_size", "8192"},
|
||||
{"table_factory.block_restart_interval", "7"}}));
|
||||
ASSERT_EQ(c_bbto->no_block_cache, true);
|
||||
ASSERT_EQ(c_bbto->block_size, 16384);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 11);
|
||||
|
||||
// Set some that are mutable and some that do not exist - options should not
|
||||
// change
|
||||
ASSERT_NOK(dbfull()->SetOptions(
|
||||
cfh, {{"table_factory.block_size", "8192"},
|
||||
{"table_factory.does_not_exist", "true"},
|
||||
{"table_factory.block_restart_interval", "7"}}));
|
||||
ASSERT_EQ(c_bbto->no_block_cache, true);
|
||||
ASSERT_EQ(c_bbto->block_size, 16384);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 11);
|
||||
|
||||
// Trying to change the table factory fails
|
||||
ASSERT_NOK(dbfull()->SetOptions(
|
||||
cfh, {{"table_factory", TableFactory::kPlainTableName()}}));
|
||||
|
||||
// Set some on the table and some on the Column Family
|
||||
ASSERT_OK(dbfull()->SetOptions(
|
||||
cfh, {{"table_factory.block_size", "16384"},
|
||||
{"blob_file_size", "32768"},
|
||||
{"table_factory.block_restart_interval", "13"}}));
|
||||
c_opts = dbfull()->GetOptions(cfh);
|
||||
ASSERT_EQ(c_opts.blob_file_size, 32768);
|
||||
ASSERT_EQ(c_bbto->block_size, 16384);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 13);
|
||||
// Set some on the table and a bad one on the ColumnFamily - options should
|
||||
// not change
|
||||
ASSERT_NOK(dbfull()->SetOptions(
|
||||
cfh, {{"table_factory.block_size", "1024"},
|
||||
{"no_such_option", "32768"},
|
||||
{"table_factory.block_restart_interval", "7"}}));
|
||||
ASSERT_EQ(c_bbto->block_size, 16384);
|
||||
ASSERT_EQ(c_bbto->block_restart_interval, 13);
|
||||
}
|
||||
|
||||
TEST_F(DBOptionsTest, SetBytesPerSync) {
|
||||
const size_t kValueSize = 1024 * 1024; // 1MB
|
||||
Options options;
|
||||
@@ -190,10 +267,11 @@ TEST_F(DBOptionsTest, SetWalBytesPerSync) {
|
||||
options.env = env_;
|
||||
Reopen(options);
|
||||
ASSERT_EQ(512, dbfull()->GetDBOptions().wal_bytes_per_sync);
|
||||
int counter = 0;
|
||||
std::atomic_int counter{0};
|
||||
int low_bytes_per_sync = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::RangeSync:0", [&](void* /*arg*/) { counter++; });
|
||||
"WritableFileWriter::RangeSync:0",
|
||||
[&](void* /*arg*/) { counter.fetch_add(1); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
const std::string kValue(kValueSize, 'v');
|
||||
int i = 0;
|
||||
@@ -729,7 +807,7 @@ TEST_F(DBOptionsTest, SetFIFOCompactionOptions) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 10);
|
||||
|
||||
+130
-112
@@ -56,7 +56,7 @@ TEST_F(DBRangeDelTest, EndSameAsStartCoversNothing) {
|
||||
}
|
||||
|
||||
TEST_F(DBRangeDelTest, EndComesBeforeStartInvalidArgument) {
|
||||
db_->Put(WriteOptions(), "b", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "b", "val"));
|
||||
ASSERT_TRUE(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "b", "a")
|
||||
.IsInvalidArgument());
|
||||
@@ -82,13 +82,14 @@ TEST_F(DBRangeDelTest, CompactionOutputHasOnlyRangeTombstone) {
|
||||
|
||||
// snapshot protects range tombstone from dropping due to becoming obsolete.
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z");
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
ASSERT_EQ(0, TestGetTickerCount(opts, COMPACTION_RANGE_DEL_DROP_OBSOLETE));
|
||||
@@ -118,7 +119,8 @@ TEST_F(DBRangeDelTest, CompactionOutputFilesExactlyFilled) {
|
||||
|
||||
// snapshot protects range tombstone from dropping due to becoming obsolete.
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), Key(0), Key(1));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), Key(0),
|
||||
Key(1)));
|
||||
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < kNumFiles; ++i) {
|
||||
@@ -128,18 +130,18 @@ TEST_F(DBRangeDelTest, CompactionOutputFilesExactlyFilled) {
|
||||
values.push_back(rnd.RandomString(3 << 10));
|
||||
ASSERT_OK(Put(Key(i * kNumPerFile + j), values[j]));
|
||||
if (j == 0 && i > 0) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
}
|
||||
}
|
||||
}
|
||||
// put extra key to trigger final flush
|
||||
ASSERT_OK(Put("", ""));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ(kNumFiles, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(2, NumTableFilesAtLevel(1));
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
@@ -178,12 +180,12 @@ TEST_F(DBRangeDelTest, MaxCompactionBytesCutsOutputFiles) {
|
||||
}
|
||||
// extra entry to trigger SpecialSkipListFactory's flush
|
||||
ASSERT_OK(Put(GetNumericStr(kNumPerFile), ""));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ(i + 1, NumTableFilesAtLevel(0));
|
||||
}
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_GE(NumTableFilesAtLevel(1), 2);
|
||||
|
||||
@@ -221,10 +223,10 @@ TEST_F(DBRangeDelTest, SentinelsOmittedFromOutputFile) {
|
||||
}
|
||||
|
||||
TEST_F(DBRangeDelTest, FlushRangeDelsSameStartKey) {
|
||||
db_->Put(WriteOptions(), "b1", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "b1", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "c"));
|
||||
db_->Put(WriteOptions(), "b2", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "b2", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "b"));
|
||||
// first iteration verifies query correctness in memtable, second verifies
|
||||
@@ -241,8 +243,9 @@ TEST_F(DBRangeDelTest, FlushRangeDelsSameStartKey) {
|
||||
}
|
||||
|
||||
TEST_F(DBRangeDelTest, CompactRangeDelsSameStartKey) {
|
||||
db_->Put(WriteOptions(), "unused", "val"); // prevents empty after compaction
|
||||
db_->Put(WriteOptions(), "b1", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "unused",
|
||||
"val")); // prevents empty after compaction
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "b1", "val"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "c"));
|
||||
@@ -254,8 +257,8 @@ TEST_F(DBRangeDelTest, CompactRangeDelsSameStartKey) {
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (i > 0) {
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
}
|
||||
@@ -279,12 +282,13 @@ TEST_F(DBRangeDelTest, FlushRemovesCoveredKeys) {
|
||||
if (i == kNum / 3) {
|
||||
snapshot = db_->GetSnapshot();
|
||||
} else if (i == 2 * kNum / 3) {
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin), GetNumericStr(kRangeEnd));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin),
|
||||
GetNumericStr(kRangeEnd)));
|
||||
}
|
||||
db_->Put(WriteOptions(), GetNumericStr(i), "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), GetNumericStr(i), "val"));
|
||||
}
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
|
||||
for (int i = 0; i < kNum; ++i) {
|
||||
ReadOptions read_opts;
|
||||
@@ -314,24 +318,27 @@ TEST_F(DBRangeDelTest, CompactionRemovesCoveredKeys) {
|
||||
for (int i = 0; i < kNumFiles; ++i) {
|
||||
if (i > 0) {
|
||||
// range tombstone covers first half of the previous file
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr((i - 1) * kNumPerFile),
|
||||
GetNumericStr((i - 1) * kNumPerFile + kNumPerFile / 2));
|
||||
ASSERT_OK(db_->DeleteRange(
|
||||
WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr((i - 1) * kNumPerFile),
|
||||
GetNumericStr((i - 1) * kNumPerFile + kNumPerFile / 2)));
|
||||
}
|
||||
// Make sure a given key appears in each file so compaction won't be able to
|
||||
// use trivial move, which would happen if the ranges were non-overlapping.
|
||||
// Also, we need an extra element since flush is only triggered when the
|
||||
// number of keys is one greater than SpecialSkipListFactory's limit.
|
||||
// We choose a key outside the key-range used by the test to avoid conflict.
|
||||
db_->Put(WriteOptions(), GetNumericStr(kNumPerFile * kNumFiles), "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), GetNumericStr(kNumPerFile * kNumFiles),
|
||||
"val"));
|
||||
|
||||
for (int j = 0; j < kNumPerFile; ++j) {
|
||||
db_->Put(WriteOptions(), GetNumericStr(i * kNumPerFile + j), "val");
|
||||
ASSERT_OK(
|
||||
db_->Put(WriteOptions(), GetNumericStr(i * kNumPerFile + j), "val"));
|
||||
}
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ(i + 1, NumTableFilesAtLevel(0));
|
||||
}
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_GT(NumTableFilesAtLevel(1), 0);
|
||||
ASSERT_EQ((kNumFiles - 1) * kNumPerFile / 2,
|
||||
@@ -373,8 +380,8 @@ TEST_F(DBRangeDelTest, ValidLevelSubcompactionBoundaries) {
|
||||
if (i > 0) {
|
||||
// delete [95,105) in two files, [295,305) in next two
|
||||
int mid = (j + (1 - j % 2)) * kNumPerFile;
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(mid - 5), Key(mid + 5));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(mid - 5), Key(mid + 5)));
|
||||
}
|
||||
std::vector<std::string> values;
|
||||
// Write 100KB (100 values, each 1K)
|
||||
@@ -384,7 +391,7 @@ TEST_F(DBRangeDelTest, ValidLevelSubcompactionBoundaries) {
|
||||
}
|
||||
// put extra key to trigger flush
|
||||
ASSERT_OK(Put("", ""));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
if (j < kNumFiles - 1) {
|
||||
// background compaction may happen early for kNumFiles'th file
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), j + 1);
|
||||
@@ -400,7 +407,7 @@ TEST_F(DBRangeDelTest, ValidLevelSubcompactionBoundaries) {
|
||||
// oversized L0 (relative to base_level) causes the compaction to run
|
||||
// earlier.
|
||||
ASSERT_OK(db_->EnableAutoCompaction({db_->DefaultColumnFamily()}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_OK(db_->SetOptions(db_->DefaultColumnFamily(),
|
||||
{{"disable_auto_compactions", "true"}}));
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
@@ -433,8 +440,8 @@ TEST_F(DBRangeDelTest, ValidUniversalSubcompactionBoundaries) {
|
||||
// insert range deletions [95,105) in two files, [295,305) in next two
|
||||
// to prepare L1 for later manual compaction.
|
||||
int mid = (j + (1 - j % 2)) * kNumPerFile;
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(mid - 5), Key(mid + 5));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(mid - 5), Key(mid + 5)));
|
||||
}
|
||||
std::vector<std::string> values;
|
||||
// Write 100KB (100 values, each 1K)
|
||||
@@ -444,13 +451,13 @@ TEST_F(DBRangeDelTest, ValidUniversalSubcompactionBoundaries) {
|
||||
}
|
||||
// put extra key to trigger flush
|
||||
ASSERT_OK(Put("", ""));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
if (j < kFilesPerLevel - 1) {
|
||||
// background compaction may happen early for kFilesPerLevel'th file
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), j + 1);
|
||||
}
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
ASSERT_GT(NumTableFilesAtLevel(kNumLevels - 1 - i), kFilesPerLevel - 1);
|
||||
}
|
||||
@@ -483,17 +490,17 @@ TEST_F(DBRangeDelTest, CompactionRemovesCoveredMergeOperands) {
|
||||
for (int i = 0; i <= kNumFiles * kNumPerFile; ++i) {
|
||||
if (i % kNumPerFile == 0 && i / kNumPerFile == kNumFiles - 1) {
|
||||
// Delete merge operands from all but the last file
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "key",
|
||||
"key_");
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
"key", "key_"));
|
||||
}
|
||||
std::string val;
|
||||
PutFixed64(&val, i);
|
||||
db_->Merge(WriteOptions(), "key", val);
|
||||
ASSERT_OK(db_->Merge(WriteOptions(), "key", val));
|
||||
// we need to prevent trivial move using Puts so compaction will actually
|
||||
// process the merge operands.
|
||||
db_->Put(WriteOptions(), "prevent_trivial_move", "");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "prevent_trivial_move", ""));
|
||||
if (i > 0 && i % kNumPerFile == 0) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +511,7 @@ TEST_F(DBRangeDelTest, CompactionRemovesCoveredMergeOperands) {
|
||||
PutFixed64(&expected, 45); // 1+2+...+9
|
||||
ASSERT_EQ(expected, actual);
|
||||
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
expected.clear();
|
||||
ASSERT_OK(db_->Get(read_opts, "key", &actual));
|
||||
@@ -550,19 +557,19 @@ TEST_F(DBRangeDelTest, ObsoleteTombstoneCleanup) {
|
||||
opts.statistics = CreateDBStatistics();
|
||||
Reopen(opts);
|
||||
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "dr1",
|
||||
"dr10"); // obsolete after compaction
|
||||
db_->Put(WriteOptions(), "key", "val");
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "dr1",
|
||||
"dr10")); // obsolete after compaction
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "dr2",
|
||||
"dr20"); // protected by snapshot
|
||||
db_->Put(WriteOptions(), "key", "val");
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "dr2",
|
||||
"dr20")); // protected by snapshot
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
|
||||
ASSERT_EQ(2, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
ASSERT_EQ(1, TestGetTickerCount(opts, COMPACTION_RANGE_DEL_DROP_OBSOLETE));
|
||||
@@ -609,22 +616,24 @@ TEST_F(DBRangeDelTest, TableEvictedDuringScan) {
|
||||
// to bottommost level (i.e., L1).
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
for (int i = 0; i < kNum; ++i) {
|
||||
db_->Put(WriteOptions(), GetNumericStr(i), "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), GetNumericStr(i), "val"));
|
||||
if (i > 0) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
}
|
||||
if (i >= kNum / 2 && i < kNum / 2 + kNumRanges) {
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin), GetNumericStr(kRangeEnd));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin),
|
||||
GetNumericStr(kRangeEnd)));
|
||||
}
|
||||
}
|
||||
// Must be > 1 so the first L1 file can be closed before scan finishes
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_GT(NumTableFilesAtLevel(1), 1);
|
||||
std::vector<uint64_t> file_numbers = ListTableFiles(env_, dbname_);
|
||||
|
||||
ReadOptions read_opts;
|
||||
auto* iter = db_->NewIterator(read_opts);
|
||||
ASSERT_OK(iter->status());
|
||||
int expected = kRangeEnd;
|
||||
iter->SeekToFirst();
|
||||
for (auto file_number : file_numbers) {
|
||||
@@ -647,7 +656,7 @@ TEST_F(DBRangeDelTest, TableEvictedDuringScan) {
|
||||
TEST_F(DBRangeDelTest, GetCoveredKeyFromMutableMemtable) {
|
||||
do {
|
||||
DestroyAndReopen(CurrentOptions());
|
||||
db_->Put(WriteOptions(), "key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
|
||||
@@ -669,10 +678,10 @@ TEST_F(DBRangeDelTest, GetCoveredKeyFromImmutableMemtable) {
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
DestroyAndReopen(opts);
|
||||
|
||||
db_->Put(WriteOptions(), "key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
db_->Put(WriteOptions(), "blah", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "blah", "val"));
|
||||
|
||||
ReadOptions read_opts;
|
||||
std::string value;
|
||||
@@ -683,7 +692,7 @@ TEST_F(DBRangeDelTest, GetCoveredKeyFromImmutableMemtable) {
|
||||
TEST_F(DBRangeDelTest, GetCoveredKeyFromSst) {
|
||||
do {
|
||||
DestroyAndReopen(CurrentOptions());
|
||||
db_->Put(WriteOptions(), "key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
// snapshot prevents key from being deleted during flush
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
ASSERT_OK(
|
||||
@@ -706,11 +715,11 @@ TEST_F(DBRangeDelTest, GetCoveredMergeOperandFromMemtable) {
|
||||
for (int i = 0; i < kNumMergeOps; ++i) {
|
||||
std::string val;
|
||||
PutFixed64(&val, i);
|
||||
db_->Merge(WriteOptions(), "key", val);
|
||||
ASSERT_OK(db_->Merge(WriteOptions(), "key", val));
|
||||
if (i == kNumMergeOps / 2) {
|
||||
// deletes [0, 5]
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "key",
|
||||
"key_");
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
"key", "key_"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,16 +743,16 @@ TEST_F(DBRangeDelTest, GetIgnoresRangeDeletions) {
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
Reopen(opts);
|
||||
|
||||
db_->Put(WriteOptions(), "sst_key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "sst_key", "val"));
|
||||
// snapshot prevents key from being deleted during flush
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
db_->Put(WriteOptions(), "imm_key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "imm_key", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
db_->Put(WriteOptions(), "mem_key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "mem_key", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
|
||||
@@ -768,13 +777,15 @@ TEST_F(DBRangeDelTest, IteratorRemovesCoveredKeys) {
|
||||
// should be deleted.
|
||||
for (int i = 0; i < kNum; ++i) {
|
||||
if (i == kNum / 2) {
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin), GetNumericStr(kRangeEnd));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin),
|
||||
GetNumericStr(kRangeEnd)));
|
||||
}
|
||||
db_->Put(WriteOptions(), GetNumericStr(i), "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), GetNumericStr(i), "val"));
|
||||
}
|
||||
ReadOptions read_opts;
|
||||
auto* iter = db_->NewIterator(read_opts);
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
int expected = 0;
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
@@ -802,14 +813,16 @@ TEST_F(DBRangeDelTest, IteratorOverUserSnapshot) {
|
||||
for (int i = 0; i < kNum; ++i) {
|
||||
if (i == kNum / 2) {
|
||||
snapshot = db_->GetSnapshot();
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin), GetNumericStr(kRangeEnd));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
GetNumericStr(kRangeBegin),
|
||||
GetNumericStr(kRangeEnd)));
|
||||
}
|
||||
db_->Put(WriteOptions(), GetNumericStr(i), "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), GetNumericStr(i), "val"));
|
||||
}
|
||||
ReadOptions read_opts;
|
||||
read_opts.snapshot = snapshot;
|
||||
auto* iter = db_->NewIterator(read_opts);
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
int expected = 0;
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
@@ -828,22 +841,23 @@ TEST_F(DBRangeDelTest, IteratorIgnoresRangeDeletions) {
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
Reopen(opts);
|
||||
|
||||
db_->Put(WriteOptions(), "sst_key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "sst_key", "val"));
|
||||
// snapshot prevents key from being deleted during flush
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
db_->Put(WriteOptions(), "imm_key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "imm_key", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
db_->Put(WriteOptions(), "mem_key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "mem_key", "val"));
|
||||
ASSERT_OK(
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), "a", "z"));
|
||||
|
||||
ReadOptions read_opts;
|
||||
read_opts.ignore_range_deletions = true;
|
||||
auto* iter = db_->NewIterator(read_opts);
|
||||
ASSERT_OK(iter->status());
|
||||
int i = 0;
|
||||
std::string expected[] = {"imm_key", "mem_key", "sst_key"};
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next(), ++i) {
|
||||
@@ -857,7 +871,7 @@ TEST_F(DBRangeDelTest, IteratorIgnoresRangeDeletions) {
|
||||
|
||||
#ifndef ROCKSDB_UBSAN_RUN
|
||||
TEST_F(DBRangeDelTest, TailingIteratorRangeTombstoneUnsupported) {
|
||||
db_->Put(WriteOptions(), "key", "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
// snapshot prevents key from being deleted during flush
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
ASSERT_OK(
|
||||
@@ -873,6 +887,7 @@ TEST_F(DBRangeDelTest, TailingIteratorRangeTombstoneUnsupported) {
|
||||
iter->SeekToFirst();
|
||||
}
|
||||
ASSERT_TRUE(iter->status().IsNotSupported());
|
||||
|
||||
delete iter;
|
||||
if (i == 0) {
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
@@ -882,7 +897,6 @@ TEST_F(DBRangeDelTest, TailingIteratorRangeTombstoneUnsupported) {
|
||||
}
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
}
|
||||
|
||||
#endif // !ROCKSDB_UBSAN_RUN
|
||||
|
||||
TEST_F(DBRangeDelTest, SubcompactionHasEmptyDedicatedRangeDelFile) {
|
||||
@@ -926,8 +940,8 @@ TEST_F(DBRangeDelTest, SubcompactionHasEmptyDedicatedRangeDelFile) {
|
||||
ASSERT_EQ(kNumFiles, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
|
||||
db_->EnableAutoCompaction({db_->DefaultColumnFamily()});
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(db_->EnableAutoCompaction({db_->DefaultColumnFamily()}));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
}
|
||||
|
||||
@@ -949,7 +963,7 @@ TEST_F(DBRangeDelTest, MemtableBloomFilter) {
|
||||
for (int i = 0; i < kNumKeys; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), Key(0),
|
||||
Key(kNumKeys)));
|
||||
for (int i = 0; i < kNumKeys; ++i) {
|
||||
@@ -987,8 +1001,8 @@ TEST_F(DBRangeDelTest, CompactionTreatsSplitInputLevelDeletionAtomically) {
|
||||
|
||||
// snapshot protects range tombstone from dropping due to becoming obsolete.
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), Key(0),
|
||||
Key(2 * kNumFilesPerLevel));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(0), Key(2 * kNumFilesPerLevel)));
|
||||
|
||||
Random rnd(301);
|
||||
std::string value = rnd.RandomString(kValueBytes);
|
||||
@@ -997,14 +1011,14 @@ TEST_F(DBRangeDelTest, CompactionTreatsSplitInputLevelDeletionAtomically) {
|
||||
ASSERT_OK(Put(Key(j), value));
|
||||
ASSERT_OK(Put(Key(2 * kNumFilesPerLevel - 1 - j), value));
|
||||
if (j > 0) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ(j, NumTableFilesAtLevel(0));
|
||||
}
|
||||
}
|
||||
// put extra key to trigger final flush
|
||||
ASSERT_OK(Put("", ""));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(kNumFilesPerLevel, NumTableFilesAtLevel(1));
|
||||
|
||||
@@ -1022,7 +1036,7 @@ TEST_F(DBRangeDelTest, CompactionTreatsSplitInputLevelDeletionAtomically) {
|
||||
} else if (i == 2) {
|
||||
ASSERT_OK(db_->SetOptions(db_->DefaultColumnFamily(),
|
||||
{{"max_bytes_for_level_base", "10000"}}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
}
|
||||
ASSERT_GT(NumTableFilesAtLevel(2), 0);
|
||||
@@ -1056,8 +1070,8 @@ TEST_F(DBRangeDelTest, RangeTombstoneEndKeyAsSstableUpperBound) {
|
||||
// A snapshot protects the range tombstone from dropping due to
|
||||
// becoming obsolete.
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
Key(0), Key(2 * kNumFilesPerLevel));
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), Key(0),
|
||||
Key(2 * kNumFilesPerLevel)));
|
||||
|
||||
// Create 2 additional sstables in L0. Note that the first sstable
|
||||
// contains the range tombstone.
|
||||
@@ -1096,7 +1110,7 @@ TEST_F(DBRangeDelTest, RangeTombstoneEndKeyAsSstableUpperBound) {
|
||||
ASSERT_EQ(value, Get(Key(2)));
|
||||
auto begin_str = Key(3);
|
||||
const ROCKSDB_NAMESPACE::Slice begin = begin_str;
|
||||
dbfull()->TEST_CompactRange(1, &begin, nullptr);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, &begin, nullptr));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
ASSERT_EQ(2, NumTableFilesAtLevel(2));
|
||||
ASSERT_EQ(value, Get(Key(2)));
|
||||
@@ -1115,7 +1129,7 @@ TEST_F(DBRangeDelTest, RangeTombstoneEndKeyAsSstableUpperBound) {
|
||||
// [key000002#6,1, key000004#72057594037927935,15]
|
||||
auto begin_str = Key(0);
|
||||
const ROCKSDB_NAMESPACE::Slice begin = begin_str;
|
||||
dbfull()->TEST_CompactRange(1, &begin, &begin);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, &begin, &begin));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
ASSERT_EQ(3, NumTableFilesAtLevel(2));
|
||||
}
|
||||
@@ -1216,9 +1230,9 @@ TEST_F(DBRangeDelTest, KeyAtOverlappingEndpointReappears) {
|
||||
std::string value;
|
||||
ASSERT_TRUE(db_->Get(ReadOptions(), "key", &value).IsNotFound());
|
||||
|
||||
dbfull()->TEST_CompactRange(0 /* level */, nullptr /* begin */,
|
||||
nullptr /* end */, nullptr /* column_family */,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(
|
||||
0 /* level */, nullptr /* begin */, nullptr /* end */,
|
||||
nullptr /* column_family */, true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
// Now we have multiple files at L1 all containing a single user key, thus
|
||||
// guaranteeing overlap in the file endpoints.
|
||||
@@ -1229,9 +1243,9 @@ TEST_F(DBRangeDelTest, KeyAtOverlappingEndpointReappears) {
|
||||
|
||||
// Compact and verify again. It's worthwhile because now the files have
|
||||
// tighter endpoints, so we can verify that doesn't mess anything up.
|
||||
dbfull()->TEST_CompactRange(1 /* level */, nullptr /* begin */,
|
||||
nullptr /* end */, nullptr /* column_family */,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(
|
||||
1 /* level */, nullptr /* begin */, nullptr /* end */,
|
||||
nullptr /* column_family */, true /* disallow_trivial_move */));
|
||||
ASSERT_GT(NumTableFilesAtLevel(2), 1);
|
||||
ASSERT_TRUE(db_->Get(ReadOptions(), "key", &value).IsNotFound());
|
||||
|
||||
@@ -1307,6 +1321,7 @@ TEST_F(DBRangeDelTest, UntruncatedTombstoneDoesNotDeleteNewerKey) {
|
||||
|
||||
auto get_key_count = [this]() -> int {
|
||||
auto* iter = db_->NewIterator(ReadOptions());
|
||||
assert(iter->status().ok());
|
||||
iter->SeekToFirst();
|
||||
int keys_found = 0;
|
||||
for (; iter->Valid(); iter->Next()) {
|
||||
@@ -1409,6 +1424,7 @@ TEST_F(DBRangeDelTest, DeletedMergeOperandReappearsIterPrev) {
|
||||
ASSERT_GT(NumTableFilesAtLevel(1), 1);
|
||||
|
||||
auto* iter = db_->NewIterator(ReadOptions());
|
||||
ASSERT_OK(iter->status());
|
||||
iter->SeekToLast();
|
||||
int keys_found = 0;
|
||||
for (; iter->Valid(); iter->Prev()) {
|
||||
@@ -1435,11 +1451,12 @@ TEST_F(DBRangeDelTest, SnapshotPreventsDroppedKeys) {
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), Key(0),
|
||||
Key(10)));
|
||||
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
|
||||
ReadOptions read_opts;
|
||||
read_opts.snapshot = snapshot;
|
||||
auto* iter = db_->NewIterator(read_opts);
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
iter->SeekToFirst();
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
@@ -1482,6 +1499,7 @@ TEST_F(DBRangeDelTest, SnapshotPreventsDroppedKeysInImmMemTables) {
|
||||
ReadOptions read_opts;
|
||||
read_opts.snapshot = snapshot.get();
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_opts));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
TEST_SYNC_POINT("SnapshotPreventsDroppedKeysInImmMemTables:AfterNewIterator");
|
||||
|
||||
@@ -1519,7 +1537,7 @@ TEST_F(DBRangeDelTest, RangeTombstoneWrittenToMinimalSsts) {
|
||||
std::string value = rnd.RandomString(kValueBytes);
|
||||
ASSERT_OK(Put(key, value));
|
||||
}
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
MoveFilesToLevel(2);
|
||||
}
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
@@ -1538,7 +1556,7 @@ TEST_F(DBRangeDelTest, RangeTombstoneWrittenToMinimalSsts) {
|
||||
// TODO(ajkr): remove this `Put` after file cutting accounts for range
|
||||
// tombstones (#3977).
|
||||
ASSERT_OK(Put("c" + Key(1), "value"));
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
|
||||
// Ensure manual L0->L1 compaction cuts the outputs before the range tombstone
|
||||
// and the range tombstone is only placed in the second SST.
|
||||
@@ -1546,9 +1564,9 @@ TEST_F(DBRangeDelTest, RangeTombstoneWrittenToMinimalSsts) {
|
||||
Slice begin_key(begin_key_storage);
|
||||
std::string end_key_storage("d");
|
||||
Slice end_key(end_key_storage);
|
||||
dbfull()->TEST_CompactRange(0 /* level */, &begin_key /* begin */,
|
||||
&end_key /* end */, nullptr /* column_family */,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(
|
||||
0 /* level */, &begin_key /* begin */, &end_key /* end */,
|
||||
nullptr /* column_family */, true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(2, NumTableFilesAtLevel(1));
|
||||
|
||||
std::vector<LiveFileMetaData> all_metadata;
|
||||
@@ -1613,15 +1631,15 @@ TEST_F(DBRangeDelTest, OverlappedTombstones) {
|
||||
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(0));
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
|
||||
// The tombstone range is not broken up into multiple SSTs which may incur a
|
||||
// large compaction with L2.
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
std::vector<std::vector<FileMetaData>> files;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(2));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
}
|
||||
@@ -1654,13 +1672,13 @@ TEST_F(DBRangeDelTest, OverlappedKeys) {
|
||||
|
||||
// The key range is broken up into three SSTs to avoid a future big compaction
|
||||
// with the grandparent
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(3, NumTableFilesAtLevel(1));
|
||||
|
||||
std::vector<std::vector<FileMetaData>> files;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, nullptr,
|
||||
true /* disallow_trivial_move */));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(2));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
}
|
||||
|
||||
+56
-29
@@ -98,7 +98,7 @@ TEST_F(DBSSTTest, SSTsWithLdbSuffixHandling) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
GenerateNewFile(&rnd, &key_id, false);
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
int const num_files = GetSstFileCount(dbname_);
|
||||
ASSERT_GT(num_files, 0);
|
||||
@@ -170,7 +170,7 @@ TEST_F(DBSSTTest, DontDeleteMovedFile) {
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
// this should execute both L0->L1 and L1->(move)->L2 compactions
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ("0,0,1", FilesPerLevel(0));
|
||||
|
||||
// If the moved file is actually deleted (the move-safeguard in
|
||||
@@ -218,7 +218,7 @@ TEST_F(DBSSTTest, DeleteObsoleteFilesPendingOutputs) {
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
// this should execute both L0->L1 and L1->(move)->L2 compactions
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ("0,0,1", FilesPerLevel(0));
|
||||
|
||||
test::SleepingBackgroundTask blocking_thread;
|
||||
@@ -264,9 +264,9 @@ TEST_F(DBSSTTest, DeleteObsoleteFilesPendingOutputs) {
|
||||
// finish the flush!
|
||||
blocking_thread.WakeUp();
|
||||
blocking_thread.WaitUntilDone();
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
// File just flushed is too big for L0 and L1 so gets moved to L2.
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ("0,0,1,0,1", FilesPerLevel(0));
|
||||
|
||||
metadata.clear();
|
||||
@@ -302,8 +302,8 @@ TEST_F(DBSSTTest, DBWithSstFileManager) {
|
||||
for (int i = 0; i < 25; i++) {
|
||||
GenerateNewRandomFile(&rnd);
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
// Verify that we are tracking all sst files in dbname_
|
||||
std::unordered_map<std::string, uint64_t> files_in_db;
|
||||
ASSERT_OK(GetAllSSTFiles(&files_in_db));
|
||||
@@ -374,6 +374,14 @@ TEST_F(DBSSTTest, RateLimitedDelete) {
|
||||
*abs_time_us = Env::Default()->NowMicros();
|
||||
});
|
||||
|
||||
// Disable PeriodicWorkScheduler as it also has TimedWait, which could update
|
||||
// the simulated sleep time
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::StartPeriodicWorkScheduler:DisableScheduler", [&](void* arg) {
|
||||
bool* disable_scheduler = static_cast<bool*>(arg);
|
||||
*disable_scheduler = true;
|
||||
});
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Options options = CurrentOptions();
|
||||
@@ -393,7 +401,7 @@ TEST_F(DBSSTTest, RateLimitedDelete) {
|
||||
|
||||
WriteOptions wo;
|
||||
wo.disableWAL = true;
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
// Create 4 files in L0
|
||||
for (char v = 'a'; v <= 'd'; v++) {
|
||||
ASSERT_OK(Put("Key2", DummyString(1024, v), wo));
|
||||
@@ -540,10 +548,15 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(options.sst_file_manager.get());
|
||||
sfm->delete_scheduler()->SetMaxTrashDBRatio(3.1);
|
||||
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
|
||||
// Create 4 files in L0
|
||||
for (char v = 'a'; v <= 'd'; v++) {
|
||||
if (v == 'd') {
|
||||
// Maximize the change that the last log file will be preserved in trash
|
||||
// before restarting the DB.
|
||||
options.sst_file_manager->SetDeleteRateBytesPerSecond(1);
|
||||
}
|
||||
ASSERT_OK(Put("Key2", DummyString(1024, v)));
|
||||
ASSERT_OK(Put("Key3", DummyString(1024, v)));
|
||||
ASSERT_OK(Put("Key4", DummyString(1024, v)));
|
||||
@@ -562,11 +575,11 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
if (!wal_dir_same_as_dbname_) {
|
||||
// Forcibly create some trash log files
|
||||
std::unique_ptr<WritableFile> result;
|
||||
env->NewWritableFile(options.wal_dir + "/1000.log.trash", &result,
|
||||
EnvOptions());
|
||||
ASSERT_OK(env->NewWritableFile(options.wal_dir + "/1000.log.trash", &result,
|
||||
EnvOptions()));
|
||||
result.reset();
|
||||
}
|
||||
env->GetChildren(options.wal_dir, &filenames);
|
||||
ASSERT_OK(env->GetChildren(options.wal_dir, &filenames));
|
||||
for (const std::string& fname : filenames) {
|
||||
if (fname.find(".log.trash") != std::string::npos) {
|
||||
trash_log_count++;
|
||||
@@ -575,11 +588,11 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
ASSERT_GE(trash_log_count, 1);
|
||||
|
||||
env->set_fake_log_delete(false);
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
|
||||
filenames.clear();
|
||||
trash_log_count = 0;
|
||||
env->GetChildren(options.wal_dir, &filenames);
|
||||
ASSERT_OK(env->GetChildren(options.wal_dir, &filenames));
|
||||
for (const std::string& fname : filenames) {
|
||||
if (fname.find(".log.trash") != std::string::npos) {
|
||||
trash_log_count++;
|
||||
@@ -603,13 +616,13 @@ TEST_F(DBSSTTest, OpenDBWithExistingTrash) {
|
||||
Destroy(last_options_);
|
||||
|
||||
// Add some trash files to the db directory so the DB can clean them up
|
||||
env_->CreateDirIfMissing(dbname_);
|
||||
ASSERT_OK(env_->CreateDirIfMissing(dbname_));
|
||||
ASSERT_OK(WriteStringToFile(env_, "abc", dbname_ + "/" + "001.sst.trash"));
|
||||
ASSERT_OK(WriteStringToFile(env_, "abc", dbname_ + "/" + "002.sst.trash"));
|
||||
ASSERT_OK(WriteStringToFile(env_, "abc", dbname_ + "/" + "003.sst.trash"));
|
||||
|
||||
// Reopen the DB and verify that it deletes existing trash files
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
sfm->WaitForEmptyTrash();
|
||||
ASSERT_NOK(env_->FileExists(dbname_ + "/" + "001.sst.trash"));
|
||||
ASSERT_NOK(env_->FileExists(dbname_ + "/" + "002.sst.trash"));
|
||||
@@ -728,7 +741,7 @@ TEST_F(DBSSTTest, DestroyDBWithRateLimitedDelete) {
|
||||
int num_sst_files = 0;
|
||||
int num_wal_files = 0;
|
||||
std::vector<std::string> db_files;
|
||||
env_->GetChildren(dbname_, &db_files);
|
||||
ASSERT_OK(env_->GetChildren(dbname_, &db_files));
|
||||
for (std::string f : db_files) {
|
||||
if (f.substr(f.find_last_of(".") + 1) == "sst") {
|
||||
num_sst_files++;
|
||||
@@ -817,7 +830,7 @@ TEST_F(DBSSTTest, CancellingCompactionsWorks) {
|
||||
ASSERT_OK(Put(Key(i), rnd.RandomString(50)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
// Because we set a callback in CancelledCompaction, we actually
|
||||
// let the compaction run
|
||||
@@ -867,10 +880,12 @@ TEST_F(DBSSTTest, CancellingManualCompactionsWorks) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// OK, now trigger a manual compaction
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_TRUE(dbfull()
|
||||
->CompactRange(CompactRangeOptions(), nullptr, nullptr)
|
||||
.IsCompactionTooLarge());
|
||||
|
||||
// Wait for manual compaction to get scheduled and finish
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_EQ(sfm->GetCompactionsReservedSize(), 0);
|
||||
// Make sure the stat is bumped
|
||||
@@ -880,10 +895,13 @@ TEST_F(DBSSTTest, CancellingManualCompactionsWorks) {
|
||||
|
||||
// Now make sure CompactFiles also gets cancelled
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files, 0);
|
||||
ASSERT_TRUE(
|
||||
dbfull()
|
||||
->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files, 0)
|
||||
.IsCompactionTooLarge());
|
||||
|
||||
// Wait for manual compaction to get scheduled and finish
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_EQ(dbfull()->immutable_db_options().statistics.get()->getTickerCount(
|
||||
COMPACTION_CANCELLED),
|
||||
@@ -898,8 +916,9 @@ TEST_F(DBSSTTest, CancellingManualCompactionsWorks) {
|
||||
"CompactFilesImpl:End", [&](void* /*arg*/) { completed_compactions++; });
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files, 0);
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(),
|
||||
l0_files, 0));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_EQ(sfm->GetCompactionsReservedSize(), 0);
|
||||
ASSERT_GT(completed_compactions, 0);
|
||||
@@ -1003,7 +1022,7 @@ TEST_F(DBSSTTest, OpenDBWithInfiniteMaxOpenFiles) {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = 2;
|
||||
db_->CompactRange(compact_options, nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(compact_options, nullptr, nullptr));
|
||||
|
||||
// Create 12 Files in L0
|
||||
for (int i = 0; i < 12; i++) {
|
||||
@@ -1055,7 +1074,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
std::string val = "val_file_" + ToString(i);
|
||||
ASSERT_OK(Put(Key(j), val));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ("5", FilesPerLevel(0));
|
||||
|
||||
@@ -1079,6 +1098,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter1->status());
|
||||
|
||||
// Compact 5 files into 1 file in L0
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
@@ -1102,12 +1122,13 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter2(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter2->status());
|
||||
|
||||
// Delete all keys and compact, this will delete all live files
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ("", FilesPerLevel(0));
|
||||
|
||||
@@ -1121,6 +1142,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
// Total SST files = 6 (5 original files + compacted file)
|
||||
ASSERT_EQ(total_sst_files_size, 6 * single_file_size);
|
||||
|
||||
ASSERT_OK(iter1->status());
|
||||
iter1.reset();
|
||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
|
||||
&total_sst_files_size));
|
||||
@@ -1128,6 +1150,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
// Total SST files = 1 (compacted file)
|
||||
ASSERT_EQ(total_sst_files_size, 1 * single_file_size);
|
||||
|
||||
ASSERT_OK(iter2->status());
|
||||
iter2.reset();
|
||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
|
||||
&total_sst_files_size));
|
||||
@@ -1146,7 +1169,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
// Generate 5 files in L0
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ("5", FilesPerLevel(0));
|
||||
|
||||
@@ -1171,6 +1194,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter1->status());
|
||||
|
||||
// Compaction will do trivial move from L0 to L1
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
@@ -1194,12 +1218,13 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter2(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter2->status());
|
||||
|
||||
// Delete all keys and compact, this will delete all live files
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ("", FilesPerLevel(0));
|
||||
|
||||
@@ -1213,7 +1238,9 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
// Total SST files = 5 (used in 2 version)
|
||||
ASSERT_EQ(total_sst_files_size, 5 * single_file_size);
|
||||
|
||||
ASSERT_OK(iter1->status());
|
||||
iter1.reset();
|
||||
ASSERT_OK(iter2->status());
|
||||
iter2.reset();
|
||||
|
||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
|
||||
|
||||
@@ -137,7 +137,7 @@ TEST_F(DBStatisticsTest, ResetStats) {
|
||||
ASSERT_EQ(1, TestGetTickerCount(options, NUMBER_KEYS_WRITTEN));
|
||||
options.statistics->histogramData(DB_WRITE, &histogram_data);
|
||||
ASSERT_GT(histogram_data.max, 0.0);
|
||||
options.statistics->Reset();
|
||||
ASSERT_OK(options.statistics->Reset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfAllTablesTest) {
|
||||
// Create 4 tables
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
db_->Put(WriteOptions(), ToString(table * 100 + i), "val");
|
||||
ASSERT_OK(db_->Put(WriteOptions(), ToString(table * 100 + i), "val"));
|
||||
}
|
||||
db_->Flush(FlushOptions());
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
// 1. Read table properties directly from file
|
||||
@@ -161,14 +161,14 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfTablesInRange) {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
ASSERT_OK(Put(test::RandomKey(&rnd, 5), rnd.RandomString(102)));
|
||||
}
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
if (NumTableFilesAtLevel(0) == 0) {
|
||||
ASSERT_OK(Put(test::RandomKey(&rnd, 5), rnd.RandomString(102)));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
db_->PauseBackgroundWork();
|
||||
ASSERT_OK(db_->PauseBackgroundWork());
|
||||
|
||||
// Ensure that we have at least L0, L1 and L2
|
||||
ASSERT_GT(NumTableFilesAtLevel(0), 0);
|
||||
@@ -236,8 +236,8 @@ TEST_F(DBTablePropertiesTest, GetColumnFamilyNameProperty) {
|
||||
// Create one table per CF, then verify it was created with the column family
|
||||
// name property.
|
||||
for (uint32_t cf = 0; cf < 2; ++cf) {
|
||||
Put(cf, "key", "val");
|
||||
Flush(cf);
|
||||
ASSERT_OK(Put(cf, "key", "val"));
|
||||
ASSERT_OK(Flush(cf));
|
||||
|
||||
TablePropertiesCollection fname_to_props;
|
||||
ASSERT_OK(db_->GetPropertiesOfAllTables(handles_[cf], &fname_to_props));
|
||||
@@ -260,17 +260,17 @@ TEST_F(DBTablePropertiesTest, GetDbIdentifiersProperty) {
|
||||
CreateAndReopenWithCF({"goku"}, CurrentOptions());
|
||||
|
||||
for (uint32_t cf = 0; cf < 2; ++cf) {
|
||||
Put(cf, "key", "val");
|
||||
Put(cf, "foo", "bar");
|
||||
Flush(cf);
|
||||
ASSERT_OK(Put(cf, "key", "val"));
|
||||
ASSERT_OK(Put(cf, "foo", "bar"));
|
||||
ASSERT_OK(Flush(cf));
|
||||
|
||||
TablePropertiesCollection fname_to_props;
|
||||
ASSERT_OK(db_->GetPropertiesOfAllTables(handles_[cf], &fname_to_props));
|
||||
ASSERT_EQ(1U, fname_to_props.size());
|
||||
|
||||
std::string id, sid;
|
||||
db_->GetDbIdentity(id);
|
||||
db_->GetDbSessionId(sid);
|
||||
ASSERT_OK(db_->GetDbIdentity(id));
|
||||
ASSERT_OK(db_->GetDbSessionId(sid));
|
||||
ASSERT_EQ(id, fname_to_props.begin()->second->db_id);
|
||||
ASSERT_EQ(sid, fname_to_props.begin()->second->db_session_id);
|
||||
}
|
||||
@@ -298,9 +298,9 @@ TEST_P(DBTableHostnamePropertyTest, DbHostLocationProperty) {
|
||||
CreateAndReopenWithCF({"goku"}, opts);
|
||||
|
||||
for (uint32_t cf = 0; cf < 2; ++cf) {
|
||||
Put(cf, "key", "val");
|
||||
Put(cf, "foo", "bar");
|
||||
Flush(cf);
|
||||
ASSERT_OK(Put(cf, "key", "val"));
|
||||
ASSERT_OK(Put(cf, "foo", "bar"));
|
||||
ASSERT_OK(Flush(cf));
|
||||
|
||||
TablePropertiesCollection fname_to_props;
|
||||
ASSERT_OK(db_->GetPropertiesOfAllTables(handles_[cf], &fname_to_props));
|
||||
@@ -356,8 +356,8 @@ TEST_P(DBTablePropertiesTest, DeletionTriggeredCompactionMarking) {
|
||||
|
||||
// add an L1 file to prevent tombstones from dropping due to obsolescence
|
||||
// during flush
|
||||
Put(Key(0), "val");
|
||||
Flush();
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Flush());
|
||||
MoveFilesToLevel(1);
|
||||
|
||||
DeletionTriggeredCompactionTestListener *listener =
|
||||
@@ -368,14 +368,14 @@ TEST_P(DBTablePropertiesTest, DeletionTriggeredCompactionMarking) {
|
||||
for (int i = 0; i < kNumKeys; ++i) {
|
||||
if (i >= kNumKeys - kWindowSize &&
|
||||
i < kNumKeys - kWindowSize + kNumDelsTrigger) {
|
||||
Delete(Key(i));
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
} else {
|
||||
Put(Key(i), "val");
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
|
||||
// Change the window size and deletion trigger and ensure new values take
|
||||
@@ -389,14 +389,14 @@ TEST_P(DBTablePropertiesTest, DeletionTriggeredCompactionMarking) {
|
||||
for (int i = 0; i < kNumKeys; ++i) {
|
||||
if (i >= kNumKeys - kWindowSize &&
|
||||
i < kNumKeys - kWindowSize + kNumDelsTrigger) {
|
||||
Delete(Key(i));
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
} else {
|
||||
Put(Key(i), "val");
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
|
||||
// Change the window size to disable delete triggered compaction
|
||||
@@ -408,14 +408,14 @@ TEST_P(DBTablePropertiesTest, DeletionTriggeredCompactionMarking) {
|
||||
for (int i = 0; i < kNumKeys; ++i) {
|
||||
if (i >= kNumKeys - kWindowSize &&
|
||||
i < kNumKeys - kWindowSize + kNumDelsTrigger) {
|
||||
Delete(Key(i));
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
} else {
|
||||
Put(Key(i), "val");
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(0));
|
||||
ASSERT_LT(0, opts.statistics->getTickerCount(COMPACT_WRITE_BYTES_MARKED));
|
||||
ASSERT_LT(0, opts.statistics->getTickerCount(COMPACT_READ_BYTES_MARKED));
|
||||
@@ -438,8 +438,8 @@ TEST_P(DBTablePropertiesTest, RatioBasedDeletionTriggeredCompactionMarking) {
|
||||
|
||||
// Add an L2 file to prevent tombstones from dropping due to obsolescence
|
||||
// during flush
|
||||
Put(Key(0), "val");
|
||||
Flush();
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Flush());
|
||||
MoveFilesToLevel(2);
|
||||
|
||||
auto* listener = new DeletionTriggeredCompactionTestListener();
|
||||
|
||||
@@ -31,6 +31,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorSingle) {
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
iter->SeekToFirst();
|
||||
ASSERT_TRUE(!iter->Valid());
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
// add a record and check that iter can see it
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "mirko", "fodor"));
|
||||
@@ -48,6 +49,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorKeepAdding) {
|
||||
read_options.tailing = true;
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
std::string value(1024, 'a');
|
||||
|
||||
const int num_records = 10000;
|
||||
@@ -70,7 +72,9 @@ TEST_F(DBTestTailingIterator, TailingIteratorSeekToNext) {
|
||||
read_options.tailing = true;
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
std::unique_ptr<Iterator> itern(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(itern->status());
|
||||
std::string value(1024, 'a');
|
||||
|
||||
const int num_records = 1000;
|
||||
@@ -138,8 +142,11 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
Slice keyu(bufe, 20);
|
||||
read_options.iterate_upper_bound = &keyu;
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
std::unique_ptr<Iterator> itern(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(itern->status());
|
||||
std::unique_ptr<Iterator> iterh(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iterh->status());
|
||||
std::string value(1024, 'a');
|
||||
bool file_iters_deleted = false;
|
||||
bool file_iters_renewed_null = false;
|
||||
@@ -179,7 +186,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
|
||||
if (i % 100 == 99) {
|
||||
ASSERT_OK(Flush(1));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
if (i == 299) {
|
||||
file_iters_deleted = true;
|
||||
}
|
||||
@@ -225,6 +232,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
read_options.read_tier = kBlockCacheTier;
|
||||
std::unique_ptr<Iterator> iteri(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iteri->status());
|
||||
char buf5[32];
|
||||
snprintf(buf5, sizeof(buf5), "00a0%016d", (num_records / 2) * 5 - 2);
|
||||
Slice target1(buf5, 20);
|
||||
@@ -236,6 +244,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory());
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
iter.reset(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
for (int i = 2 * num_records; i > 0; --i) {
|
||||
char buf1[32];
|
||||
char buf2[32];
|
||||
@@ -262,6 +271,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorDeletes) {
|
||||
read_options.tailing = true;
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
// write a single record, read it using the iterator, then delete it
|
||||
ASSERT_OK(Put(1, "0test", "test"));
|
||||
@@ -309,6 +319,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorPrefixSeek) {
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_OK(Put(1, "0101", "test"));
|
||||
|
||||
ASSERT_OK(Flush(1));
|
||||
@@ -339,6 +350,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorIncomplete) {
|
||||
ASSERT_OK(db_->Put(WriteOptions(), key, value));
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
iter->SeekToFirst();
|
||||
// we either see the entry or it's not in cache
|
||||
ASSERT_TRUE(iter->Valid() || iter->status().IsIncomplete());
|
||||
@@ -369,6 +381,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorSeekToSame) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
// Seek to 00001. We expect to find 00002.
|
||||
std::string start_key = "00001";
|
||||
iter->Seek(start_key);
|
||||
@@ -404,6 +417,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorUpperBound) {
|
||||
ASSERT_OK(Put(1, "21", "21"));
|
||||
|
||||
std::unique_ptr<Iterator> it(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(it->status());
|
||||
it->Seek("12");
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("12", it->key().ToString());
|
||||
@@ -411,7 +425,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorUpperBound) {
|
||||
it->Next();
|
||||
// Not valid since "21" is over the upper bound.
|
||||
ASSERT_FALSE(it->Valid());
|
||||
|
||||
ASSERT_OK(it->status());
|
||||
// This keeps track of the number of times NeedToSeekImmutable() was true.
|
||||
int immutable_seeks = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
@@ -424,6 +438,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorUpperBound) {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
ASSERT_FALSE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
ASSERT_EQ(0, immutable_seeks);
|
||||
}
|
||||
|
||||
@@ -478,6 +493,8 @@ TEST_F(DBTestTailingIterator, TailingIteratorGap) {
|
||||
it->Next();
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("40", it->key().ToString());
|
||||
|
||||
ASSERT_OK(it->status());
|
||||
}
|
||||
|
||||
TEST_F(DBTestTailingIterator, SeekWithUpperBoundBug) {
|
||||
@@ -496,6 +513,7 @@ TEST_F(DBTestTailingIterator, SeekWithUpperBoundBug) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
iter->Seek("aa");
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
@@ -518,6 +536,7 @@ TEST_F(DBTestTailingIterator, SeekToFirstWithUpperBoundBug) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
iter->SeekToFirst();
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
|
||||
+75
-87
@@ -1305,51 +1305,6 @@ TEST_F(DBTest, DISABLED_RepeatedWritesToSameKey) {
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
TEST_F(DBTest, SparseMerge) {
|
||||
do {
|
||||
Options options = CurrentOptions();
|
||||
options.compression = kNoCompression;
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
FillLevels("A", "Z", 1);
|
||||
|
||||
// Suppose there is:
|
||||
// small amount of data with prefix A
|
||||
// large amount of data with prefix B
|
||||
// small amount of data with prefix C
|
||||
// and that recent updates have made small changes to all three prefixes.
|
||||
// Check that we do not do a compaction that merges all of B in one shot.
|
||||
const std::string value(1000, 'x');
|
||||
Put(1, "A", "va");
|
||||
// Write approximately 100MB of "B" values
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
}
|
||||
Put(1, "C", "vc");
|
||||
ASSERT_OK(Flush(1));
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
|
||||
// Make sparse update
|
||||
Put(1, "A", "va2");
|
||||
Put(1, "B100", "bvalue2");
|
||||
Put(1, "C", "vc2");
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
// Compactions should not cause us to create a situation where
|
||||
// a file overlaps too much data at the next level.
|
||||
ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(handles_[1]),
|
||||
20 * 1048576);
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
|
||||
ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(handles_[1]),
|
||||
20 * 1048576);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr);
|
||||
ASSERT_LE(dbfull()->TEST_MaxNextLevelOverlappingBytes(handles_[1]),
|
||||
20 * 1048576);
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
static bool Between(uint64_t val, uint64_t low, uint64_t high) {
|
||||
bool result = (val >= low) && (val <= high);
|
||||
@@ -1382,17 +1337,19 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
SizeApproximationOptions size_approx_options;
|
||||
size_approx_options.include_memtabtles = true;
|
||||
size_approx_options.include_files = true;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_GT(size, 6000);
|
||||
ASSERT_LT(size, 204800);
|
||||
// Zero if not including mem table
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(500);
|
||||
end = Key(600);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
@@ -1402,13 +1359,15 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
start = Key(500);
|
||||
end = Key(600);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(100);
|
||||
end = Key(1020);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_GT(size, 6000);
|
||||
|
||||
options.max_write_buffer_number = 8;
|
||||
@@ -1434,29 +1393,32 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
start = Key(100);
|
||||
end = Key(300);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(1050);
|
||||
end = Key(1080);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_GT(size, 6000);
|
||||
|
||||
start = Key(2100);
|
||||
end = Key(2300);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(1050);
|
||||
end = Key(1080);
|
||||
r = Range(start, end);
|
||||
uint64_t size_with_mt, size_without_mt;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt));
|
||||
ASSERT_GT(size_with_mt, 6000);
|
||||
db_->GetApproximateSizes(&r, 1, &size_without_mt);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size_without_mt));
|
||||
ASSERT_EQ(size_without_mt, 0);
|
||||
|
||||
Flush();
|
||||
@@ -1468,15 +1430,16 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
start = Key(1050);
|
||||
end = Key(1080);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt);
|
||||
db_->GetApproximateSizes(&r, 1, &size_without_mt);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt));
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size_without_mt));
|
||||
ASSERT_GT(size_with_mt, size_without_mt);
|
||||
ASSERT_GT(size_without_mt, 6000);
|
||||
|
||||
// Check that include_memtabtles flag works as expected
|
||||
size_approx_options.include_memtabtles = false;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, size_without_mt);
|
||||
|
||||
// Check that files_size_error_margin works as expected, when the heuristic
|
||||
@@ -1485,10 +1448,12 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
end = Key(1000 + N - 2);
|
||||
r = Range(start, end);
|
||||
size_approx_options.files_size_error_margin = -1.0; // disabled
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
uint64_t size2;
|
||||
size_approx_options.files_size_error_margin = 0.5; // enabled, but not used
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size2);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size2));
|
||||
ASSERT_EQ(size, size2);
|
||||
}
|
||||
|
||||
@@ -1539,14 +1504,16 @@ TEST_F(DBTest, ApproximateSizesFilesWithErrorMargin) {
|
||||
|
||||
// Get the precise size without any approximation heuristic
|
||||
uint64_t size;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size));
|
||||
ASSERT_NE(size, 0);
|
||||
|
||||
// Get the size with an approximation heuristic
|
||||
uint64_t size2;
|
||||
const double error_margin = 0.2;
|
||||
size_approx_options.files_size_error_margin = error_margin;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size2);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size2));
|
||||
ASSERT_LT(size2, size * (1 + error_margin));
|
||||
ASSERT_GT(size2, size * (1 - error_margin));
|
||||
}
|
||||
@@ -1562,7 +1529,7 @@ TEST_F(DBTest, ApproximateSizesFilesWithErrorMargin) {
|
||||
const std::string end = Key(i + 11); // overlap by 1 key
|
||||
const Range r(start, end);
|
||||
uint64_t size;
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size));
|
||||
ASSERT_LE(size, 11 * 100);
|
||||
}
|
||||
}
|
||||
@@ -1630,9 +1597,12 @@ TEST_F(DBTest, ApproximateSizes) {
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
ASSERT_TRUE(Between(Size("", "xyz", 1), 0, 0));
|
||||
uint64_t size;
|
||||
ASSERT_OK(Size("", "xyz", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_TRUE(Between(Size("", "xyz", 1), 0, 0));
|
||||
ASSERT_OK(Size("", "xyz", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
|
||||
// Write 8MB (80 values, each 100K)
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
@@ -1645,7 +1615,8 @@ TEST_F(DBTest, ApproximateSizes) {
|
||||
}
|
||||
|
||||
// 0 because GetApproximateSizes() does not account for memtable space
|
||||
ASSERT_TRUE(Between(Size("", Key(50), 1), 0, 0));
|
||||
ASSERT_OK(Size("", Key(50), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
|
||||
// Check sizes across recovery by reopening a few times
|
||||
for (int run = 0; run < 3; run++) {
|
||||
@@ -1653,14 +1624,17 @@ TEST_F(DBTest, ApproximateSizes) {
|
||||
|
||||
for (int compact_start = 0; compact_start < N; compact_start += 10) {
|
||||
for (int i = 0; i < N; i += 10) {
|
||||
ASSERT_TRUE(Between(Size("", Key(i), 1), S1 * i, S2 * i));
|
||||
ASSERT_TRUE(Between(Size("", Key(i) + ".suffix", 1), S1 * (i + 1),
|
||||
S2 * (i + 1)));
|
||||
ASSERT_TRUE(Between(Size(Key(i), Key(i + 10), 1), S1 * 10, S2 * 10));
|
||||
ASSERT_OK(Size("", Key(i), 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * i, S2 * i));
|
||||
ASSERT_OK(Size("", Key(i) + ".suffix", 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * (i + 1), S2 * (i + 1)));
|
||||
ASSERT_OK(Size(Key(i), Key(i + 10), 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * 10, S2 * 10));
|
||||
}
|
||||
ASSERT_TRUE(Between(Size("", Key(50), 1), S1 * 50, S2 * 50));
|
||||
ASSERT_TRUE(
|
||||
Between(Size("", Key(50) + ".suffix", 1), S1 * 50, S2 * 50));
|
||||
ASSERT_OK(Size("", Key(50), 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * 50, S2 * 50));
|
||||
ASSERT_OK(Size("", Key(50) + ".suffix", 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * 50, S2 * 50));
|
||||
|
||||
std::string cstart_str = Key(compact_start);
|
||||
std::string cend_str = Key(compact_start + 9);
|
||||
@@ -1695,21 +1669,32 @@ TEST_F(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
|
||||
ASSERT_OK(Put(1, Key(7), rnd.RandomString(10000)));
|
||||
|
||||
// Check sizes across recovery by reopening a few times
|
||||
uint64_t size;
|
||||
for (int run = 0; run < 3; run++) {
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
|
||||
ASSERT_TRUE(Between(Size("", Key(0), 1), 0, 0));
|
||||
ASSERT_TRUE(Between(Size("", Key(1), 1), 10000, 11000));
|
||||
ASSERT_TRUE(Between(Size("", Key(2), 1), 20000, 21000));
|
||||
ASSERT_TRUE(Between(Size("", Key(3), 1), 120000, 121000));
|
||||
ASSERT_TRUE(Between(Size("", Key(4), 1), 130000, 131000));
|
||||
ASSERT_TRUE(Between(Size("", Key(5), 1), 230000, 232000));
|
||||
ASSERT_TRUE(Between(Size("", Key(6), 1), 240000, 242000));
|
||||
ASSERT_OK(Size("", Key(0), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
ASSERT_OK(Size("", Key(1), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 10000, 11000));
|
||||
ASSERT_OK(Size("", Key(2), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 20000, 21000));
|
||||
ASSERT_OK(Size("", Key(3), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 120000, 121000));
|
||||
ASSERT_OK(Size("", Key(4), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 130000, 131000));
|
||||
ASSERT_OK(Size("", Key(5), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 230000, 232000));
|
||||
ASSERT_OK(Size("", Key(6), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 240000, 242000));
|
||||
// Ensure some overhead is accounted for, even without including all
|
||||
ASSERT_TRUE(Between(Size("", Key(7), 1), 540500, 545000));
|
||||
ASSERT_TRUE(Between(Size("", Key(8), 1), 550500, 555000));
|
||||
ASSERT_OK(Size("", Key(7), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 540500, 545000));
|
||||
ASSERT_OK(Size("", Key(8), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 550500, 555000));
|
||||
|
||||
ASSERT_TRUE(Between(Size(Key(3), Key(5), 1), 110100, 111000));
|
||||
ASSERT_OK(Size(Key(3), Key(5), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 110100, 111000));
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
}
|
||||
@@ -1793,6 +1778,7 @@ TEST_F(DBTest, Snapshot) {
|
||||
TEST_F(DBTest, HiddenValuesAreRemoved) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
uint64_t size;
|
||||
do {
|
||||
Options options = CurrentOptions(options_override);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
@@ -1810,7 +1796,8 @@ TEST_F(DBTest, HiddenValuesAreRemoved) {
|
||||
ASSERT_GT(NumTableFilesAtLevel(0, 1), 0);
|
||||
|
||||
ASSERT_EQ(big, Get(1, "foo", snapshot));
|
||||
ASSERT_TRUE(Between(Size("", "pastfoo", 1), 50000, 60000));
|
||||
ASSERT_OK(Size("", "pastfoo", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 50000, 60000));
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
ASSERT_EQ(AllEntriesFor("foo", 1), "[ tiny, " + big + " ]");
|
||||
Slice x("x");
|
||||
@@ -1821,7 +1808,8 @@ TEST_F(DBTest, HiddenValuesAreRemoved) {
|
||||
dbfull()->TEST_CompactRange(1, nullptr, &x, handles_[1]);
|
||||
ASSERT_EQ(AllEntriesFor("foo", 1), "[ tiny ]");
|
||||
|
||||
ASSERT_TRUE(Between(Size("", "pastfoo", 1), 0, 1000));
|
||||
ASSERT_OK(Size("", "pastfoo", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 1000));
|
||||
// ApproximateOffsetOf() is not yet implemented in plain table format,
|
||||
// which is used by Size().
|
||||
} while (ChangeOptions(kSkipUniversalCompaction | kSkipFIFOCompaction |
|
||||
|
||||
+119
-48
@@ -41,9 +41,7 @@ TEST_F(DBTest2, OpenForReadOnly) {
|
||||
std::vector<std::string> files;
|
||||
ASSERT_OK(env_->GetChildren(dbname, &files));
|
||||
for (auto& f : files) {
|
||||
if (f != "." && f != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
// <dbname> should be empty now and we should be able to delete it
|
||||
ASSERT_OK(env_->DeleteDir(dbname));
|
||||
@@ -75,9 +73,7 @@ TEST_F(DBTest2, OpenForReadOnlyWithColumnFamilies) {
|
||||
std::vector<std::string> files;
|
||||
ASSERT_OK(env_->GetChildren(dbname, &files));
|
||||
for (auto& f : files) {
|
||||
if (f != "." && f != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
// <dbname> should be empty now and we should be able to delete it
|
||||
ASSERT_OK(env_->DeleteDir(dbname));
|
||||
@@ -1414,67 +1410,94 @@ INSTANTIATE_TEST_CASE_P(
|
||||
|
||||
TEST_P(PresetCompressionDictTest, Flush) {
|
||||
// Verifies that dictionary is generated and written during flush only when
|
||||
// `ColumnFamilyOptions::compression` enables dictionary.
|
||||
// `ColumnFamilyOptions::compression` enables dictionary. Also verifies the
|
||||
// size of the dictionary is within expectations according to the limit on
|
||||
// buffering set by `CompressionOptions::max_dict_buffer_bytes`.
|
||||
const size_t kValueLen = 256;
|
||||
const size_t kKeysPerFile = 1 << 10;
|
||||
const size_t kDictLen = 4 << 10;
|
||||
const size_t kDictLen = 16 << 10;
|
||||
const size_t kBlockLen = 4 << 10;
|
||||
|
||||
Options options = CurrentOptions();
|
||||
if (bottommost_) {
|
||||
options.bottommost_compression = compression_type_;
|
||||
options.bottommost_compression_opts.enabled = true;
|
||||
options.bottommost_compression_opts.max_dict_bytes = kDictLen;
|
||||
options.bottommost_compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
} else {
|
||||
options.compression = compression_type_;
|
||||
options.compression_opts.max_dict_bytes = kDictLen;
|
||||
options.compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
}
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kKeysPerFile));
|
||||
options.statistics = CreateDBStatistics();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.block_size = kBlockLen;
|
||||
bbto.cache_index_and_filter_blocks = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
Reopen(options);
|
||||
|
||||
uint64_t prev_compression_dict_misses =
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_MISS);
|
||||
Random rnd(301);
|
||||
for (size_t i = 0; i <= kKeysPerFile; ++i) {
|
||||
ASSERT_OK(Put(Key(static_cast<int>(i)), rnd.RandomString(kValueLen)));
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
|
||||
// If there's a compression dictionary, it should have been loaded when the
|
||||
// flush finished, incurring a cache miss.
|
||||
uint64_t expected_compression_dict_misses;
|
||||
// We can use `BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT` to detect whether a
|
||||
// compression dictionary exists since dictionaries would be preloaded when
|
||||
// the flush finishes.
|
||||
if (bottommost_) {
|
||||
expected_compression_dict_misses = prev_compression_dict_misses;
|
||||
// Flush is never considered bottommost. This should change in the future
|
||||
// since flushed files may have nothing underneath them, like the one in
|
||||
// this test case.
|
||||
ASSERT_EQ(
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
0);
|
||||
} else {
|
||||
expected_compression_dict_misses = prev_compression_dict_misses + 1;
|
||||
ASSERT_GT(
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
0);
|
||||
// TODO(ajkr): fix the below assertion to work with ZSTD. The expectation on
|
||||
// number of bytes needs to be adjusted in case the cached block is in
|
||||
// ZSTD's digested dictionary format.
|
||||
if (compression_type_ != kZSTD &&
|
||||
compression_type_ != kZSTDNotFinalCompression) {
|
||||
// Although we limited buffering to `kBlockLen`, there may be up to two
|
||||
// blocks of data included in the dictionary since we only check limit
|
||||
// after each block is built.
|
||||
ASSERT_LE(TestGetTickerCount(options,
|
||||
BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
2 * kBlockLen);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(expected_compression_dict_misses,
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_MISS));
|
||||
}
|
||||
|
||||
TEST_P(PresetCompressionDictTest, CompactNonBottommost) {
|
||||
// Verifies that dictionary is generated and written during compaction to
|
||||
// non-bottommost level only when `ColumnFamilyOptions::compression` enables
|
||||
// dictionary.
|
||||
// dictionary. Also verifies the size of the dictionary is within expectations
|
||||
// according to the limit on buffering set by
|
||||
// `CompressionOptions::max_dict_buffer_bytes`.
|
||||
const size_t kValueLen = 256;
|
||||
const size_t kKeysPerFile = 1 << 10;
|
||||
const size_t kDictLen = 4 << 10;
|
||||
const size_t kDictLen = 16 << 10;
|
||||
const size_t kBlockLen = 4 << 10;
|
||||
|
||||
Options options = CurrentOptions();
|
||||
if (bottommost_) {
|
||||
options.bottommost_compression = compression_type_;
|
||||
options.bottommost_compression_opts.enabled = true;
|
||||
options.bottommost_compression_opts.max_dict_bytes = kDictLen;
|
||||
options.bottommost_compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
} else {
|
||||
options.compression = compression_type_;
|
||||
options.compression_opts.max_dict_bytes = kDictLen;
|
||||
options.compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
}
|
||||
options.disable_auto_compactions = true;
|
||||
options.statistics = CreateDBStatistics();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.block_size = kBlockLen;
|
||||
bbto.cache_index_and_filter_blocks = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
Reopen(options);
|
||||
@@ -1496,8 +1519,8 @@ TEST_P(PresetCompressionDictTest, CompactNonBottommost) {
|
||||
ASSERT_EQ("2,0,1", FilesPerLevel(0));
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
uint64_t prev_compression_dict_misses =
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_MISS);
|
||||
uint64_t prev_compression_dict_bytes_inserted =
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT);
|
||||
// This L0->L1 compaction merges the two L0 files into L1. The produced L1
|
||||
// file is not bottommost due to the existing L2 file covering the same key-
|
||||
// range.
|
||||
@@ -1505,38 +1528,58 @@ TEST_P(PresetCompressionDictTest, CompactNonBottommost) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ("0,1,1", FilesPerLevel(0));
|
||||
#endif // ROCKSDB_LITE
|
||||
// If there's a compression dictionary, it should have been loaded when the
|
||||
// compaction finished, incurring a cache miss.
|
||||
uint64_t expected_compression_dict_misses;
|
||||
// We can use `BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT` to detect whether a
|
||||
// compression dictionary exists since dictionaries would be preloaded when
|
||||
// the compaction finishes.
|
||||
if (bottommost_) {
|
||||
expected_compression_dict_misses = prev_compression_dict_misses;
|
||||
ASSERT_EQ(
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
prev_compression_dict_bytes_inserted);
|
||||
} else {
|
||||
expected_compression_dict_misses = prev_compression_dict_misses + 1;
|
||||
ASSERT_GT(
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
prev_compression_dict_bytes_inserted);
|
||||
// TODO(ajkr): fix the below assertion to work with ZSTD. The expectation on
|
||||
// number of bytes needs to be adjusted in case the cached block is in
|
||||
// ZSTD's digested dictionary format.
|
||||
if (compression_type_ != kZSTD &&
|
||||
compression_type_ != kZSTDNotFinalCompression) {
|
||||
// Although we limited buffering to `kBlockLen`, there may be up to two
|
||||
// blocks of data included in the dictionary since we only check limit
|
||||
// after each block is built.
|
||||
ASSERT_LE(TestGetTickerCount(options,
|
||||
BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
prev_compression_dict_bytes_inserted + 2 * kBlockLen);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(expected_compression_dict_misses,
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_MISS));
|
||||
}
|
||||
|
||||
TEST_P(PresetCompressionDictTest, CompactBottommost) {
|
||||
// Verifies that dictionary is generated and written during compaction to
|
||||
// non-bottommost level only when either `ColumnFamilyOptions::compression` or
|
||||
// `ColumnFamilyOptions::bottommost_compression` enables dictionary.
|
||||
// `ColumnFamilyOptions::bottommost_compression` enables dictionary. Also
|
||||
// verifies the size of the dictionary is within expectations according to the
|
||||
// limit on buffering set by `CompressionOptions::max_dict_buffer_bytes`.
|
||||
const size_t kValueLen = 256;
|
||||
const size_t kKeysPerFile = 1 << 10;
|
||||
const size_t kDictLen = 4 << 10;
|
||||
const size_t kDictLen = 16 << 10;
|
||||
const size_t kBlockLen = 4 << 10;
|
||||
|
||||
Options options = CurrentOptions();
|
||||
if (bottommost_) {
|
||||
options.bottommost_compression = compression_type_;
|
||||
options.bottommost_compression_opts.enabled = true;
|
||||
options.bottommost_compression_opts.max_dict_bytes = kDictLen;
|
||||
options.bottommost_compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
} else {
|
||||
options.compression = compression_type_;
|
||||
options.compression_opts.max_dict_bytes = kDictLen;
|
||||
options.compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
}
|
||||
options.disable_auto_compactions = true;
|
||||
options.statistics = CreateDBStatistics();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.block_size = kBlockLen;
|
||||
bbto.cache_index_and_filter_blocks = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
Reopen(options);
|
||||
@@ -1552,17 +1595,28 @@ TEST_P(PresetCompressionDictTest, CompactBottommost) {
|
||||
ASSERT_EQ("2", FilesPerLevel(0));
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
uint64_t prev_compression_dict_misses =
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_MISS);
|
||||
uint64_t prev_compression_dict_bytes_inserted =
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT);
|
||||
CompactRangeOptions cro;
|
||||
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ("0,1", FilesPerLevel(0));
|
||||
#endif // ROCKSDB_LITE
|
||||
// If there's a compression dictionary, it should have been loaded when the
|
||||
// compaction finished, incurring a cache miss.
|
||||
ASSERT_EQ(prev_compression_dict_misses + 1,
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_MISS));
|
||||
ASSERT_GT(
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
prev_compression_dict_bytes_inserted);
|
||||
// TODO(ajkr): fix the below assertion to work with ZSTD. The expectation on
|
||||
// number of bytes needs to be adjusted in case the cached block is in ZSTD's
|
||||
// digested dictionary format.
|
||||
if (compression_type_ != kZSTD &&
|
||||
compression_type_ != kZSTDNotFinalCompression) {
|
||||
// Although we limited buffering to `kBlockLen`, there may be up to two
|
||||
// blocks of data included in the dictionary since we only check limit after
|
||||
// each block is built.
|
||||
ASSERT_LE(
|
||||
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT),
|
||||
prev_compression_dict_bytes_inserted + 2 * kBlockLen);
|
||||
}
|
||||
}
|
||||
|
||||
class CompactionCompressionListener : public EventListener {
|
||||
@@ -3685,20 +3739,26 @@ TEST_F(DBTest2, LiveFilesOmitObsoleteFiles) {
|
||||
|
||||
TEST_F(DBTest2, TestNumPread) {
|
||||
Options options = CurrentOptions();
|
||||
bool prefetch_supported =
|
||||
test::IsPrefetchSupported(env_->GetFileSystem(), dbname_);
|
||||
// disable block cache
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.no_block_cache = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
env_->count_random_reads_ = true;
|
||||
|
||||
env_->random_file_open_counter_.store(0);
|
||||
ASSERT_OK(Put("bar", "foo"));
|
||||
ASSERT_OK(Put("foo", "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
if (prefetch_supported) {
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
} else {
|
||||
// With prefetch not supported, we will do a single read into a buffer
|
||||
ASSERT_EQ(1, env_->random_read_counter_.Read());
|
||||
}
|
||||
ASSERT_EQ(1, env_->random_file_open_counter_.load());
|
||||
|
||||
// One pread per a normal data block read
|
||||
@@ -3714,19 +3774,30 @@ TEST_F(DBTest2, TestNumPread) {
|
||||
ASSERT_OK(Put("bar2", "foo2"));
|
||||
ASSERT_OK(Put("foo2", "bar2"));
|
||||
ASSERT_OK(Flush());
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
if (prefetch_supported) {
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
} else {
|
||||
// With prefetch not supported, we will do a single read into a buffer
|
||||
ASSERT_EQ(1, env_->random_read_counter_.Read());
|
||||
}
|
||||
ASSERT_EQ(1, env_->random_file_open_counter_.load());
|
||||
|
||||
// Compaction needs two input blocks, which requires 2 preads, and
|
||||
// generate a new SST file which needs 4 preads (footer, meta block,
|
||||
// property block and index block). In total 6.
|
||||
env_->random_file_open_counter_.store(0);
|
||||
env_->random_read_counter_.Reset();
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(6, env_->random_read_counter_.Read());
|
||||
// All compactin input files should have already been opened.
|
||||
if (prefetch_supported) {
|
||||
// Compaction needs two input blocks, which requires 2 preads, and
|
||||
// generate a new SST file which needs 4 preads (footer, meta block,
|
||||
// property block and index block). In total 6.
|
||||
ASSERT_EQ(6, env_->random_read_counter_.Read());
|
||||
} else {
|
||||
// With prefetch off, compaction needs two input blocks,
|
||||
// followed by a single buffered read. In total 3.
|
||||
ASSERT_EQ(3, env_->random_read_counter_.Read());
|
||||
}
|
||||
// All compaction input files should have already been opened.
|
||||
ASSERT_EQ(1, env_->random_file_open_counter_.load());
|
||||
|
||||
// One pread per a normal data block read
|
||||
|
||||
+38
-16
@@ -236,7 +236,7 @@ bool DBTestBase::ChangeWalOptions() {
|
||||
auto options = CurrentOptions();
|
||||
Destroy(options);
|
||||
options.create_if_missing = true;
|
||||
TryReopen(options);
|
||||
Reopen(options);
|
||||
return true;
|
||||
} else if (option_config_ == kDBLogDir) {
|
||||
option_config_ = kWalDirAndMmapReads;
|
||||
@@ -244,14 +244,14 @@ bool DBTestBase::ChangeWalOptions() {
|
||||
auto options = CurrentOptions();
|
||||
Destroy(options);
|
||||
options.create_if_missing = true;
|
||||
TryReopen(options);
|
||||
Reopen(options);
|
||||
return true;
|
||||
} else if (option_config_ == kWalDirAndMmapReads) {
|
||||
option_config_ = kRecycleLogFiles;
|
||||
Destroy(last_options_);
|
||||
auto options = CurrentOptions();
|
||||
Destroy(options);
|
||||
TryReopen(options);
|
||||
Reopen(options);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -1128,26 +1128,48 @@ std::string DBTestBase::FilesPerLevel(int cf) {
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
size_t DBTestBase::CountFiles() {
|
||||
size_t count = 0;
|
||||
std::vector<std::string> files;
|
||||
env_->GetChildren(dbname_, &files);
|
||||
|
||||
std::vector<std::string> logfiles;
|
||||
if (dbname_ != last_options_.wal_dir) {
|
||||
env_->GetChildren(last_options_.wal_dir, &logfiles);
|
||||
if (env_->GetChildren(dbname_, &files).ok()) {
|
||||
count += files.size();
|
||||
}
|
||||
|
||||
return files.size() + logfiles.size();
|
||||
if (dbname_ != last_options_.wal_dir) {
|
||||
if (env_->GetChildren(last_options_.wal_dir, &files).ok()) {
|
||||
count += files.size();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
Status DBTestBase::CountFiles(size_t* count) {
|
||||
std::vector<std::string> files;
|
||||
Status s = env_->GetChildren(dbname_, &files);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
size_t files_count = files.size();
|
||||
|
||||
if (dbname_ != last_options_.wal_dir) {
|
||||
s = env_->GetChildren(last_options_.wal_dir, &files);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
*count = files_count + files.size();
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
uint64_t DBTestBase::Size(const Slice& start, const Slice& limit, int cf) {
|
||||
Status DBTestBase::Size(const Slice& start, const Slice& limit, int cf,
|
||||
uint64_t* size) {
|
||||
Range r(start, limit);
|
||||
uint64_t size;
|
||||
if (cf == 0) {
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
return db_->GetApproximateSizes(&r, 1, size);
|
||||
} else {
|
||||
db_->GetApproximateSizes(handles_[1], &r, 1, &size);
|
||||
return db_->GetApproximateSizes(handles_[1], &r, 1, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void DBTestBase::Compact(int cf, const Slice& start, const Slice& limit,
|
||||
@@ -1266,8 +1288,8 @@ void DBTestBase::GenerateNewRandomFile(Random* rnd, bool nowait) {
|
||||
}
|
||||
ASSERT_OK(Put("key" + rnd->RandomString(7), rnd->RandomString(200)));
|
||||
if (!nowait) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -1070,7 +1070,13 @@ class DBTestBase : public testing::Test {
|
||||
|
||||
size_t CountFiles();
|
||||
|
||||
uint64_t Size(const Slice& start, const Slice& limit, int cf = 0);
|
||||
Status CountFiles(size_t* count);
|
||||
|
||||
Status Size(const Slice& start, const Slice& limit, uint64_t* size) {
|
||||
return Size(start, limit, 0, size);
|
||||
}
|
||||
|
||||
Status Size(const Slice& start, const Slice& limit, int cf, uint64_t* size);
|
||||
|
||||
void Compact(int cf, const Slice& start, const Slice& limit,
|
||||
uint32_t target_path_id);
|
||||
|
||||
@@ -996,7 +996,7 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionStopStyleSimilarSize) {
|
||||
// First, clean up memtable before inserting new data. This will generate
|
||||
// a level-0 file, with size around 0.4 (according to previously written
|
||||
// data amount).
|
||||
dbfull()->Flush(FlushOptions());
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
for (int num = 0; num < options.level0_file_num_compaction_trigger - 3;
|
||||
num++) {
|
||||
// Write 110KB (11 values, each 10K)
|
||||
@@ -1781,7 +1781,7 @@ TEST_P(DBTestUniversalCompaction, FinalSortedRunCompactFilesConflict) {
|
||||
dbfull()->TEST_write_controler().GetCompactionPressureToken();
|
||||
|
||||
ASSERT_OK(Put("key", "val"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(NumTableFilesAtLevel(num_levels_ - 1), 1);
|
||||
ColumnFamilyMetaData cf_meta;
|
||||
@@ -1807,7 +1807,7 @@ TEST_P(DBTestUniversalCompaction, FinalSortedRunCompactFilesConflict) {
|
||||
"DBTestUniversalCompaction:FinalSortedRunCompactFilesConflict:0");
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ASSERT_OK(Put("key", "val"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
@@ -1911,7 +1911,7 @@ TEST_F(DBTestUniversalCompaction2, BasicL0toL1) {
|
||||
for (i = 0; i < 2000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
// MoveFilesToLevel(6);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
@@ -1923,7 +1923,7 @@ TEST_F(DBTestUniversalCompaction2, BasicL0toL1) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
@@ -1954,7 +1954,7 @@ TEST_F(DBTestUniversalCompaction2, SingleLevel) {
|
||||
for (i = 0; i < 2000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
for (i = 1999; i < kNumKeys; ++i) {
|
||||
if (i >= kNumKeys - kWindowSize &&
|
||||
@@ -1964,7 +1964,7 @@ TEST_F(DBTestUniversalCompaction2, SingleLevel) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush()(;
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(0));
|
||||
@@ -1992,19 +1992,19 @@ TEST_F(DBTestUniversalCompaction2, MultipleLevels) {
|
||||
for (i = 0; i < 500; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 500; i < 1000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 1000; i < 1500; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 1500; i < 2000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
@@ -2013,15 +2013,15 @@ TEST_F(DBTestUniversalCompaction2, MultipleLevels) {
|
||||
for (i = 1999; i < 2333; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 2333; i < 2666; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 2666; i < 2999; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
@@ -2031,7 +2031,7 @@ TEST_F(DBTestUniversalCompaction2, MultipleLevels) {
|
||||
for (i = 1900; i < 2100; ++i) {
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
@@ -2064,19 +2064,19 @@ TEST_F(DBTestUniversalCompaction2, OverlappingL0) {
|
||||
for (i = 0; i < 2000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 2000; i < 3000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 3500; i < 4000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
for (i = 2900; i < 3100; ++i) {
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(2, NumTableFilesAtLevel(0));
|
||||
@@ -2106,7 +2106,7 @@ TEST_F(DBTestUniversalCompaction2, IngestBehind) {
|
||||
for (i = 0; i < 2000; ++i) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
// MoveFilesToLevel(6);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
@@ -2118,7 +2118,7 @@ TEST_F(DBTestUniversalCompaction2, IngestBehind) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
}
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
@@ -2184,7 +2184,7 @@ TEST_F(DBTestUniversalCompaction2, PeriodicCompaction) {
|
||||
|
||||
// Case 1: Oldest flushed file excceeds periodic compaction threshold.
|
||||
ASSERT_OK(Put("foo", "bar"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(0, periodic_compactions);
|
||||
// Move clock forward so that the flushed file would qualify periodic
|
||||
// compaction.
|
||||
@@ -2192,7 +2192,7 @@ TEST_F(DBTestUniversalCompaction2, PeriodicCompaction) {
|
||||
|
||||
// Another flush would trigger compaction the oldest file.
|
||||
ASSERT_OK(Put("foo", "bar2"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_EQ(1, periodic_compactions);
|
||||
@@ -2203,7 +2203,7 @@ TEST_F(DBTestUniversalCompaction2, PeriodicCompaction) {
|
||||
periodic_compactions = 0;
|
||||
// A flush doesn't trigger a periodic compaction when threshold not hit
|
||||
ASSERT_OK(Put("foo", "bar2"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(0, periodic_compactions);
|
||||
|
||||
@@ -2211,7 +2211,7 @@ TEST_F(DBTestUniversalCompaction2, PeriodicCompaction) {
|
||||
// a compaction
|
||||
ASSERT_OK(Put("foo", "bar2"));
|
||||
env_->MockSleepForSeconds(48 * 60 * 60 + 100);
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_EQ(1, periodic_compactions);
|
||||
ASSERT_EQ(0, start_level);
|
||||
|
||||
+162
-29
@@ -14,6 +14,7 @@
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
#include "utilities/fault_injection_fs.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class DBWALTestBase : public DBTestBase {
|
||||
@@ -437,15 +438,159 @@ TEST_F(DBWALTest, RecoverWithBlob) {
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
|
||||
TEST_F(DBWALTest, RecoverWithBlobMultiSST) {
|
||||
// Write several large (4 KB) values without flushing. Note that blob files
|
||||
// are not actually enabled at this point.
|
||||
std::string large_value(1 << 12, 'a');
|
||||
|
||||
constexpr int num_keys = 64;
|
||||
|
||||
for (int i = 0; i < num_keys; ++i) {
|
||||
ASSERT_OK(Put(Key(i), large_value));
|
||||
}
|
||||
|
||||
// There should be no files just yet since we haven't flushed.
|
||||
{
|
||||
VersionSet* const versions = dbfull()->TEST_GetVersionSet();
|
||||
ASSERT_NE(versions, nullptr);
|
||||
|
||||
ColumnFamilyData* const cfd = versions->GetColumnFamilySet()->GetDefault();
|
||||
ASSERT_NE(cfd, nullptr);
|
||||
|
||||
Version* const current = cfd->current();
|
||||
ASSERT_NE(current, nullptr);
|
||||
|
||||
const VersionStorageInfo* const storage_info = current->storage_info();
|
||||
ASSERT_NE(storage_info, nullptr);
|
||||
|
||||
ASSERT_EQ(storage_info->num_non_empty_levels(), 0);
|
||||
ASSERT_TRUE(storage_info->GetBlobFiles().empty());
|
||||
}
|
||||
|
||||
// Reopen the database with blob files enabled and write buffer size set to a
|
||||
// smaller value. Multiple table files+blob files should be written and added
|
||||
// to the Version during recovery.
|
||||
Options options;
|
||||
options.write_buffer_size = 1 << 16; // 64 KB
|
||||
options.enable_blob_files = true;
|
||||
options.avoid_flush_during_recovery = false;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = env_;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
for (int i = 0; i < num_keys; ++i) {
|
||||
ASSERT_EQ(Get(Key(i)), large_value);
|
||||
}
|
||||
|
||||
VersionSet* const versions = dbfull()->TEST_GetVersionSet();
|
||||
ASSERT_NE(versions, nullptr);
|
||||
|
||||
ColumnFamilyData* const cfd = versions->GetColumnFamilySet()->GetDefault();
|
||||
ASSERT_NE(cfd, nullptr);
|
||||
|
||||
Version* const current = cfd->current();
|
||||
ASSERT_NE(current, nullptr);
|
||||
|
||||
const VersionStorageInfo* const storage_info = current->storage_info();
|
||||
ASSERT_NE(storage_info, nullptr);
|
||||
|
||||
const auto& l0_files = storage_info->LevelFiles(0);
|
||||
ASSERT_GT(l0_files.size(), 1);
|
||||
|
||||
const auto& blob_files = storage_info->GetBlobFiles();
|
||||
ASSERT_GT(blob_files.size(), 1);
|
||||
|
||||
ASSERT_EQ(l0_files.size(), blob_files.size());
|
||||
}
|
||||
|
||||
TEST_F(DBWALTest, WALWithChecksumHandoff) {
|
||||
#ifndef ROCKSDB_ASSERT_STATUS_CHECKED
|
||||
if (mem_env_ || encrypted_env_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires non-mem or non-encrypted environment");
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<FaultInjectionTestFS> fault_fs(
|
||||
new FaultInjectionTestFS(FileSystem::Default()));
|
||||
std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
|
||||
do {
|
||||
Options options = CurrentOptions();
|
||||
|
||||
options.checksum_handoff_file_types.Add(FileType::kWalFile);
|
||||
options.env = fault_fs_env.get();
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
WriteOptions writeOpt = WriteOptions();
|
||||
writeOpt.disableWAL = true;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "foo", "v1"));
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "bar", "v1"));
|
||||
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_EQ("v1", Get(1, "foo"));
|
||||
ASSERT_EQ("v1", Get(1, "bar"));
|
||||
|
||||
writeOpt.disableWAL = false;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "bar", "v2"));
|
||||
writeOpt.disableWAL = true;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "foo", "v2"));
|
||||
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
// Both value's should be present.
|
||||
ASSERT_EQ("v2", Get(1, "bar"));
|
||||
ASSERT_EQ("v2", Get(1, "foo"));
|
||||
|
||||
writeOpt.disableWAL = true;
|
||||
// This put, data is persisted by Flush
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "bar", "v3"));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
writeOpt.disableWAL = false;
|
||||
// Data is persisted in the WAL
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "zoo", "v3"));
|
||||
// The hash does not match, write fails
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kxxHash);
|
||||
writeOpt.disableWAL = false;
|
||||
ASSERT_NOK(dbfull()->Put(writeOpt, handles_[1], "foo", "v3"));
|
||||
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
// Due to the write failure, Get should not find
|
||||
ASSERT_NE("v3", Get(1, "foo"));
|
||||
ASSERT_EQ("v3", Get(1, "zoo"));
|
||||
ASSERT_EQ("v3", Get(1, "bar"));
|
||||
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kCRC32c);
|
||||
// Each write will be similated as corrupted.
|
||||
fault_fs->IngestDataCorruptionBeforeWrite();
|
||||
writeOpt.disableWAL = true;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "bar", "v4"));
|
||||
writeOpt.disableWAL = false;
|
||||
ASSERT_NOK(dbfull()->Put(writeOpt, handles_[1], "foo", "v4"));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_NE("v4", Get(1, "foo"));
|
||||
ASSERT_NE("v4", Get(1, "bar"));
|
||||
fault_fs->NoDataCorruptionBeforeWrite();
|
||||
|
||||
fault_fs->SetChecksumHandoffFuncType(ChecksumType::kNoChecksum);
|
||||
// The file system does not provide checksum method and verification.
|
||||
writeOpt.disableWAL = true;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "bar", "v5"));
|
||||
writeOpt.disableWAL = false;
|
||||
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "foo", "v5"));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_EQ("v5", Get(1, "foo"));
|
||||
ASSERT_EQ("v5", Get(1, "bar"));
|
||||
|
||||
Destroy(options);
|
||||
} while (ChangeWalOptions());
|
||||
#endif // ROCKSDB_ASSERT_STATUS_CHECKED
|
||||
}
|
||||
|
||||
class DBRecoveryTestBlobError
|
||||
: public DBWALTest,
|
||||
public testing::WithParamInterface<std::string> {
|
||||
public:
|
||||
DBRecoveryTestBlobError()
|
||||
: fault_injection_env_(env_), sync_point_(GetParam()) {}
|
||||
~DBRecoveryTestBlobError() { Close(); }
|
||||
DBRecoveryTestBlobError() : sync_point_(GetParam()) {}
|
||||
|
||||
FaultInjectionTestEnv fault_injection_env_;
|
||||
std::string sync_point_;
|
||||
};
|
||||
|
||||
@@ -460,21 +605,19 @@ TEST_P(DBRecoveryTestBlobError, RecoverWithBlobError) {
|
||||
|
||||
// Reopen with blob files enabled but make blob file writing fail during
|
||||
// recovery.
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* /* arg */) {
|
||||
fault_injection_env_.SetFilesystemActive(false,
|
||||
Status::IOError(sync_point_));
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* arg) {
|
||||
Status* const s = static_cast<Status*>(arg);
|
||||
assert(s);
|
||||
|
||||
(*s) = Status::IOError(sync_point_);
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeDeleteFile", [this](void* /* arg */) {
|
||||
fault_injection_env_.SetFilesystemActive(true);
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Options options;
|
||||
options.enable_blob_files = true;
|
||||
options.avoid_flush_during_recovery = false;
|
||||
options.disable_auto_compactions = true;
|
||||
options.env = &fault_injection_env_;
|
||||
options.env = env_;
|
||||
|
||||
ASSERT_NOK(TryReopen(options));
|
||||
|
||||
@@ -506,9 +649,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> old_files;
|
||||
ASSERT_OK(env_->GetChildren(backup_logs, &old_files));
|
||||
for (auto& file : old_files) {
|
||||
if (file != "." && file != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -528,9 +669,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> logs;
|
||||
ASSERT_OK(env_->GetChildren(options.wal_dir, &logs));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(options.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
CopyFile(options.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
|
||||
// recover the DB
|
||||
@@ -541,9 +680,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
|
||||
// copy the logs from backup back to wal dir
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
// this should ignore the log files, recovery should not happen again
|
||||
// if the recovery happens, the same merge operator would be called twice,
|
||||
@@ -559,9 +696,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
// copy the logs from backup back to wal dir
|
||||
ASSERT_OK(env_->CreateDirIfMissing(options.wal_dir));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
// assert that we successfully recovered only from logs, even though we
|
||||
// destroyed the DB
|
||||
@@ -574,11 +709,9 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
// copy the logs from backup back to wal dir
|
||||
ASSERT_OK(env_->CreateDirIfMissing(options.wal_dir));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
// we won't be needing this file no more
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + log));
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
// we won't be needing this file no more
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + log));
|
||||
}
|
||||
Status s = TryReopen(options);
|
||||
ASSERT_NOK(s);
|
||||
|
||||
@@ -223,6 +223,111 @@ TEST_F(DBBasicTestWithTimestamp, CompactRangeWithSpecifiedRange) {
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTestWithTimestamp, UpdateFullHistoryTsLow) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
const std::string kKey = "test kKey";
|
||||
|
||||
// Test set ts_low first and flush()
|
||||
int current_ts_low = 5;
|
||||
std::string ts_low_str = Timestamp(current_ts_low, 0);
|
||||
Slice ts_low = ts_low_str;
|
||||
CompactRangeOptions comp_opts;
|
||||
comp_opts.full_history_ts_low = &ts_low;
|
||||
comp_opts.bottommost_level_compaction = BottommostLevelCompaction::kForce;
|
||||
|
||||
ASSERT_OK(db_->CompactRange(comp_opts, nullptr, nullptr));
|
||||
|
||||
auto* cfd =
|
||||
static_cast_with_check<ColumnFamilyHandleImpl>(db_->DefaultColumnFamily())
|
||||
->cfd();
|
||||
auto result_ts_low = cfd->GetFullHistoryTsLow();
|
||||
|
||||
ASSERT_TRUE(test_cmp.CompareTimestamp(ts_low, result_ts_low) == 0);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
WriteOptions write_opts;
|
||||
std::string ts_str = Timestamp(i, 0);
|
||||
Slice ts = ts_str;
|
||||
write_opts.timestamp = &ts;
|
||||
ASSERT_OK(db_->Put(write_opts, kKey, Key(i)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ReadOptions read_opts;
|
||||
std::string ts_str = Timestamp(i, 0);
|
||||
Slice ts = ts_str;
|
||||
read_opts.timestamp = &ts;
|
||||
std::string value;
|
||||
Status status = db_->Get(read_opts, kKey, &value);
|
||||
if (i < current_ts_low) {
|
||||
ASSERT_TRUE(status.IsNotFound());
|
||||
} else {
|
||||
ASSERT_OK(status);
|
||||
ASSERT_TRUE(value.compare(Key(i)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Test set ts_low and then trigger compaction
|
||||
for (int i = 10; i < 20; i++) {
|
||||
WriteOptions write_opts;
|
||||
std::string ts_str = Timestamp(i, 0);
|
||||
Slice ts = ts_str;
|
||||
write_opts.timestamp = &ts;
|
||||
ASSERT_OK(db_->Put(write_opts, kKey, Key(i)));
|
||||
}
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
current_ts_low = 15;
|
||||
ts_low_str = Timestamp(current_ts_low, 0);
|
||||
ts_low = ts_low_str;
|
||||
comp_opts.full_history_ts_low = &ts_low;
|
||||
ASSERT_OK(db_->CompactRange(comp_opts, nullptr, nullptr));
|
||||
result_ts_low = cfd->GetFullHistoryTsLow();
|
||||
ASSERT_TRUE(test_cmp.CompareTimestamp(ts_low, result_ts_low) == 0);
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
ReadOptions read_opts;
|
||||
std::string ts_str = Timestamp(i, 0);
|
||||
Slice ts = ts_str;
|
||||
read_opts.timestamp = &ts;
|
||||
std::string value;
|
||||
Status status = db_->Get(read_opts, kKey, &value);
|
||||
if (i < current_ts_low) {
|
||||
ASSERT_TRUE(status.IsNotFound());
|
||||
} else {
|
||||
ASSERT_OK(status);
|
||||
ASSERT_TRUE(value.compare(Key(i)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Test invalid compaction with range
|
||||
Slice start(kKey), end(kKey);
|
||||
Status s = db_->CompactRange(comp_opts, &start, &end);
|
||||
ASSERT_TRUE(s.IsInvalidArgument());
|
||||
s = db_->CompactRange(comp_opts, &start, nullptr);
|
||||
ASSERT_TRUE(s.IsInvalidArgument());
|
||||
s = db_->CompactRange(comp_opts, nullptr, &end);
|
||||
ASSERT_TRUE(s.IsInvalidArgument());
|
||||
|
||||
// Test invalid compaction with the decreasing ts_low
|
||||
ts_low_str = Timestamp(current_ts_low - 1, 0);
|
||||
ts_low = ts_low_str;
|
||||
comp_opts.full_history_ts_low = &ts_low;
|
||||
s = db_->CompactRange(comp_opts, nullptr, nullptr);
|
||||
ASSERT_TRUE(s.IsInvalidArgument());
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTestWithTimestamp, GetApproximateSizes) {
|
||||
Options options = CurrentOptions();
|
||||
options.write_buffer_size = 100000000; // Large write buffer
|
||||
@@ -270,7 +375,7 @@ TEST_F(DBBasicTestWithTimestamp, GetApproximateSizes) {
|
||||
ASSERT_EQ(range_sizes[1], size);
|
||||
|
||||
// Zero if not including mem table
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(500);
|
||||
|
||||
+37
-27
@@ -60,14 +60,15 @@ TEST_P(DBWriteTest, WriteStallRemoveNoSlowdownWrite) {
|
||||
std::string key = "foo" + std::to_string(a);
|
||||
WriteOptions wo;
|
||||
wo.no_slowdown = false;
|
||||
dbfull()->Put(wo, key, "bar");
|
||||
ASSERT_OK(dbfull()->Put(wo, key, "bar"));
|
||||
};
|
||||
std::function<void()> write_no_slowdown_func = [&]() {
|
||||
int a = thread_num.fetch_add(1);
|
||||
std::string key = "foo" + std::to_string(a);
|
||||
WriteOptions wo;
|
||||
wo.no_slowdown = true;
|
||||
dbfull()->Put(wo, key, "bar");
|
||||
Status s = dbfull()->Put(wo, key, "bar");
|
||||
ASSERT_TRUE(s.ok() || s.IsIncomplete());
|
||||
};
|
||||
std::function<void(void*)> unblock_main_thread_func = [&](void*) {
|
||||
mutex.Lock();
|
||||
@@ -77,13 +78,13 @@ TEST_P(DBWriteTest, WriteStallRemoveNoSlowdownWrite) {
|
||||
};
|
||||
|
||||
// Create 3 L0 files and schedule 4th without waiting
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteThread::JoinBatchGroup:Start", unblock_main_thread_func);
|
||||
@@ -104,7 +105,7 @@ TEST_P(DBWriteTest, WriteStallRemoveNoSlowdownWrite) {
|
||||
// write_thread
|
||||
FlushOptions fopt;
|
||||
fopt.wait = false;
|
||||
dbfull()->Flush(fopt);
|
||||
ASSERT_OK(dbfull()->Flush(fopt));
|
||||
|
||||
// Create a mix of slowdown/no_slowdown write threads
|
||||
mutex.Lock();
|
||||
@@ -145,7 +146,7 @@ TEST_P(DBWriteTest, WriteStallRemoveNoSlowdownWrite) {
|
||||
mutex.Unlock();
|
||||
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteStallRemoveNoSlowdownWrite:1");
|
||||
dbfull()->TEST_WaitForFlushMemTable(nullptr);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(nullptr));
|
||||
// This would have triggered a write stall. Unblock the write group leader
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteStallRemoveNoSlowdownWrite:2");
|
||||
// The leader is going to create missing newer links. When the leader
|
||||
@@ -178,14 +179,15 @@ TEST_P(DBWriteTest, WriteThreadHangOnWriteStall) {
|
||||
std::string key = "foo" + std::to_string(a);
|
||||
WriteOptions wo;
|
||||
wo.no_slowdown = false;
|
||||
dbfull()->Put(wo, key, "bar");
|
||||
ASSERT_OK(dbfull()->Put(wo, key, "bar"));
|
||||
};
|
||||
std::function<void()> write_no_slowdown_func = [&]() {
|
||||
int a = thread_num.fetch_add(1);
|
||||
std::string key = "foo" + std::to_string(a);
|
||||
WriteOptions wo;
|
||||
wo.no_slowdown = true;
|
||||
dbfull()->Put(wo, key, "bar");
|
||||
Status s = dbfull()->Put(wo, key, "bar");
|
||||
ASSERT_TRUE(s.ok() || s.IsIncomplete());
|
||||
};
|
||||
std::function<void(void *)> unblock_main_thread_func = [&](void *) {
|
||||
mutex.Lock();
|
||||
@@ -195,13 +197,13 @@ TEST_P(DBWriteTest, WriteThreadHangOnWriteStall) {
|
||||
};
|
||||
|
||||
// Create 3 L0 files and schedule 4th without waiting
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
Flush();
|
||||
Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar");
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("foo" + std::to_string(thread_num.fetch_add(1)), "bar"));
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteThread::JoinBatchGroup:Start", unblock_main_thread_func);
|
||||
@@ -222,7 +224,7 @@ TEST_P(DBWriteTest, WriteThreadHangOnWriteStall) {
|
||||
// write_thread
|
||||
FlushOptions fopt;
|
||||
fopt.wait = false;
|
||||
dbfull()->Flush(fopt);
|
||||
ASSERT_OK(dbfull()->Flush(fopt));
|
||||
|
||||
// Create a mix of slowdown/no_slowdown write threads
|
||||
mutex.Lock();
|
||||
@@ -243,7 +245,7 @@ TEST_P(DBWriteTest, WriteThreadHangOnWriteStall) {
|
||||
mutex.Unlock();
|
||||
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteThreadHangOnWriteStall:1");
|
||||
dbfull()->TEST_WaitForFlushMemTable(nullptr);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(nullptr));
|
||||
// This would have triggered a write stall. Unblock the write group leader
|
||||
TEST_SYNC_POINT("DBWriteTest::WriteThreadHangOnWriteStall:2");
|
||||
// The leader is going to create missing newer links. When the leader finishes,
|
||||
@@ -307,6 +309,11 @@ TEST_P(DBWriteTest, IOErrorOnWALWritePropagateToWriteThreadFollower) {
|
||||
threads[i].join();
|
||||
}
|
||||
ASSERT_EQ(1, leader_count);
|
||||
|
||||
// The Failed PUT operations can cause a BG error to be set.
|
||||
// Mark it as Checked for the ASSERT_STATUS_CHECKED
|
||||
dbfull()->Resume().PermitUncheckedError();
|
||||
|
||||
// Close before mock_env destruct.
|
||||
Close();
|
||||
}
|
||||
@@ -351,7 +358,9 @@ TEST_P(DBWriteTest, IOErrorOnWALWriteTriggersReadOnlyMode) {
|
||||
}
|
||||
*/
|
||||
if (!options.manual_wal_flush) {
|
||||
ASSERT_FALSE(res.ok());
|
||||
ASSERT_NOK(res);
|
||||
} else {
|
||||
ASSERT_OK(res);
|
||||
}
|
||||
}
|
||||
// Close before mock_env destruct.
|
||||
@@ -423,13 +432,14 @@ TEST_P(DBWriteTest, ConcurrentlyDisabledWAL) {
|
||||
ROCKSDB_NAMESPACE::WriteOptions write_option_default;
|
||||
std::string no_wal_key = no_wal_key_prefix + std::to_string(t) +
|
||||
"_" + std::to_string(i);
|
||||
this->Put(no_wal_key, no_wal_value, write_option_disable);
|
||||
ASSERT_OK(
|
||||
this->Put(no_wal_key, no_wal_value, write_option_disable));
|
||||
std::string wal_key =
|
||||
wal_key_prefix + std::to_string(i) + "_" + std::to_string(i);
|
||||
this->Put(wal_key, wal_value, write_option_default);
|
||||
dbfull()->SyncWAL();
|
||||
ASSERT_OK(this->Put(wal_key, wal_value, write_option_default));
|
||||
ASSERT_OK(dbfull()->SyncWAL());
|
||||
}
|
||||
return 0;
|
||||
return;
|
||||
});
|
||||
}
|
||||
for (auto& t: threads) {
|
||||
|
||||
+4
-2
@@ -146,8 +146,10 @@ inline void UnPackSequenceAndType(uint64_t packed, uint64_t* seq,
|
||||
*seq = packed >> 8;
|
||||
*t = static_cast<ValueType>(packed & 0xff);
|
||||
|
||||
assert(*seq <= kMaxSequenceNumber);
|
||||
assert(IsExtendedValueType(*t));
|
||||
// Commented the following two assertions in order to test key-value checksum
|
||||
// on corrupted keys without crashing ("DbKvChecksumTest").
|
||||
// assert(*seq <= kMaxSequenceNumber);
|
||||
// assert(IsExtendedValueType(*t));
|
||||
}
|
||||
|
||||
EntryType GetEntryType(ValueType value_type);
|
||||
|
||||
+25
-16
@@ -40,7 +40,7 @@ class DeleteFileTest : public DBTestBase {
|
||||
wal_dir_(dbname_ + "/wal_files") {}
|
||||
|
||||
void SetOptions(Options* options) {
|
||||
assert(options);
|
||||
ASSERT_NE(options, nullptr);
|
||||
options->delete_obsolete_files_period_micros = 0; // always do full purge
|
||||
options->enable_thread_tracking = true;
|
||||
options->write_buffer_size = 1024 * 1024 * 1000;
|
||||
@@ -105,7 +105,7 @@ class DeleteFileTest : public DBTestBase {
|
||||
void CheckFileTypeCounts(const std::string& dir, int required_log,
|
||||
int required_sst, int required_manifest) {
|
||||
std::vector<std::string> filenames;
|
||||
env_->GetChildren(dir, &filenames);
|
||||
ASSERT_OK(env_->GetChildren(dir, &filenames));
|
||||
|
||||
int log_cnt = 0, sst_cnt = 0, manifest_cnt = 0;
|
||||
for (auto file : filenames) {
|
||||
@@ -180,7 +180,8 @@ TEST_F(DeleteFileTest, AddKeysAndQueryLevels) {
|
||||
ASSERT_TRUE(status.IsInvalidArgument());
|
||||
|
||||
// Lowest level file deletion should succeed.
|
||||
ASSERT_OK(db_->DeleteFile(level2file));
|
||||
status = db_->DeleteFile(level2file);
|
||||
ASSERT_OK(status);
|
||||
}
|
||||
|
||||
TEST_F(DeleteFileTest, PurgeObsoleteFilesTest) {
|
||||
@@ -201,7 +202,7 @@ TEST_F(DeleteFileTest, PurgeObsoleteFilesTest) {
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = 2;
|
||||
Slice first_slice(first), last_slice(last);
|
||||
db_->CompactRange(compact_options, &first_slice, &last_slice);
|
||||
ASSERT_OK(db_->CompactRange(compact_options, &first_slice, &last_slice));
|
||||
// 1 sst after compaction
|
||||
CheckFileTypeCounts(dbname_, 0, 1, 1);
|
||||
|
||||
@@ -210,7 +211,9 @@ TEST_F(DeleteFileTest, PurgeObsoleteFilesTest) {
|
||||
Iterator *itr = nullptr;
|
||||
CreateTwoLevels();
|
||||
itr = db_->NewIterator(ReadOptions());
|
||||
db_->CompactRange(compact_options, &first_slice, &last_slice);
|
||||
ASSERT_OK(itr->status());
|
||||
ASSERT_OK(db_->CompactRange(compact_options, &first_slice, &last_slice));
|
||||
ASSERT_OK(itr->status());
|
||||
// 3 sst after compaction with live iterator
|
||||
CheckFileTypeCounts(dbname_, 0, 3, 1);
|
||||
delete itr;
|
||||
@@ -237,7 +240,8 @@ TEST_F(DeleteFileTest, BackgroundPurgeIteratorTest) {
|
||||
ReadOptions read_options;
|
||||
read_options.background_purge_on_iterator_cleanup = true;
|
||||
itr = db_->NewIterator(read_options);
|
||||
db_->CompactRange(compact_options, &first_slice, &last_slice);
|
||||
ASSERT_OK(itr->status());
|
||||
ASSERT_OK(db_->CompactRange(compact_options, &first_slice, &last_slice));
|
||||
// 3 sst after compaction with live iterator
|
||||
CheckFileTypeCounts(dbname_, 0, 3, 1);
|
||||
test::SleepingBackgroundTask sleeping_task_before;
|
||||
@@ -344,11 +348,12 @@ TEST_F(DeleteFileTest, BackgroundPurgeCopyOptions) {
|
||||
ReadOptions read_options;
|
||||
read_options.background_purge_on_iterator_cleanup = true;
|
||||
itr = db_->NewIterator(read_options);
|
||||
ASSERT_OK(itr->status());
|
||||
// ReadOptions is deleted, but iterator cleanup function should not be
|
||||
// affected
|
||||
}
|
||||
|
||||
db_->CompactRange(compact_options, &first_slice, &last_slice);
|
||||
ASSERT_OK(db_->CompactRange(compact_options, &first_slice, &last_slice));
|
||||
// 3 sst after compaction with live iterator
|
||||
CheckFileTypeCounts(dbname_, 0, 3, 1);
|
||||
delete itr;
|
||||
@@ -382,9 +387,11 @@ TEST_F(DeleteFileTest, BackgroundPurgeTestMultipleJobs) {
|
||||
ReadOptions read_options;
|
||||
read_options.background_purge_on_iterator_cleanup = true;
|
||||
Iterator* itr1 = db_->NewIterator(read_options);
|
||||
ASSERT_OK(itr1->status());
|
||||
CreateTwoLevels();
|
||||
Iterator* itr2 = db_->NewIterator(read_options);
|
||||
db_->CompactRange(compact_options, &first_slice, &last_slice);
|
||||
ASSERT_OK(itr2->status());
|
||||
ASSERT_OK(db_->CompactRange(compact_options, &first_slice, &last_slice));
|
||||
// 5 sst files after 2 compactions with 2 live iterators
|
||||
CheckFileTypeCounts(dbname_, 0, 5, 1);
|
||||
|
||||
@@ -417,6 +424,7 @@ TEST_F(DeleteFileTest, DeleteFileWithIterator) {
|
||||
CreateTwoLevels();
|
||||
ReadOptions read_options;
|
||||
Iterator* it = db_->NewIterator(read_options);
|
||||
ASSERT_OK(it->status());
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
db_->GetLiveFilesMetaData(&metadata);
|
||||
|
||||
@@ -432,7 +440,7 @@ TEST_F(DeleteFileTest, DeleteFileWithIterator) {
|
||||
Status status = db_->DeleteFile(level2file);
|
||||
fprintf(stdout, "Deletion status %s: %s\n",
|
||||
level2file.c_str(), status.ToString().c_str());
|
||||
ASSERT_TRUE(status.ok());
|
||||
ASSERT_OK(status);
|
||||
it->SeekToFirst();
|
||||
int numKeysIterated = 0;
|
||||
while(it->Valid()) {
|
||||
@@ -452,7 +460,7 @@ TEST_F(DeleteFileTest, DeleteLogFiles) {
|
||||
|
||||
AddKeys(10, 0);
|
||||
VectorLogPtr logfiles;
|
||||
db_->GetSortedWalFiles(logfiles);
|
||||
ASSERT_OK(db_->GetSortedWalFiles(logfiles));
|
||||
ASSERT_GT(logfiles.size(), 0UL);
|
||||
// Take the last log file which is expected to be alive and try to delete it
|
||||
// Should not succeed because live logs are not allowed to be deleted
|
||||
@@ -461,7 +469,7 @@ TEST_F(DeleteFileTest, DeleteLogFiles) {
|
||||
ASSERT_OK(env_->FileExists(wal_dir_ + "/" + alive_log->PathName()));
|
||||
fprintf(stdout, "Deleting alive log file %s\n",
|
||||
alive_log->PathName().c_str());
|
||||
ASSERT_TRUE(!db_->DeleteFile(alive_log->PathName()).ok());
|
||||
ASSERT_NOK(db_->DeleteFile(alive_log->PathName()));
|
||||
ASSERT_OK(env_->FileExists(wal_dir_ + "/" + alive_log->PathName()));
|
||||
logfiles.clear();
|
||||
|
||||
@@ -469,10 +477,10 @@ TEST_F(DeleteFileTest, DeleteLogFiles) {
|
||||
// Call Flush again to flush out memtable and move alive log to archived log
|
||||
// and try to delete the archived log file
|
||||
FlushOptions fopts;
|
||||
db_->Flush(fopts);
|
||||
ASSERT_OK(db_->Flush(fopts));
|
||||
AddKeys(10, 0);
|
||||
db_->Flush(fopts);
|
||||
db_->GetSortedWalFiles(logfiles);
|
||||
ASSERT_OK(db_->Flush(fopts));
|
||||
ASSERT_OK(db_->GetSortedWalFiles(logfiles));
|
||||
ASSERT_GT(logfiles.size(), 0UL);
|
||||
std::unique_ptr<LogFile> archived_log = std::move(logfiles.front());
|
||||
ASSERT_EQ(archived_log->Type(), kArchivedLogFile);
|
||||
@@ -480,8 +488,8 @@ TEST_F(DeleteFileTest, DeleteLogFiles) {
|
||||
fprintf(stdout, "Deleting archived log file %s\n",
|
||||
archived_log->PathName().c_str());
|
||||
ASSERT_OK(db_->DeleteFile(archived_log->PathName()));
|
||||
ASSERT_EQ(Status::NotFound(),
|
||||
env_->FileExists(wal_dir_ + "/" + archived_log->PathName()));
|
||||
ASSERT_TRUE(
|
||||
env_->FileExists(wal_dir_ + "/" + archived_log->PathName()).IsNotFound());
|
||||
}
|
||||
|
||||
TEST_F(DeleteFileTest, DeleteNonDefaultColumnFamily) {
|
||||
@@ -520,6 +528,7 @@ TEST_F(DeleteFileTest, DeleteNonDefaultColumnFamily) {
|
||||
|
||||
{
|
||||
std::unique_ptr<Iterator> itr(db_->NewIterator(ReadOptions(), handles_[1]));
|
||||
ASSERT_OK(itr->status());
|
||||
int count = 0;
|
||||
for (itr->SeekToFirst(); itr->Valid(); itr->Next()) {
|
||||
ASSERT_OK(itr->status());
|
||||
|
||||
+27
-19
@@ -350,12 +350,17 @@ const Status& ErrorHandler::SetBGError(const Status& bg_err,
|
||||
|
||||
// This is the main function for looking at IO related error during the
|
||||
// background operations. The main logic is:
|
||||
// 1) File scope IO error is treated as retryable IO error in the write
|
||||
// path. In RocksDB, If a file has write IO error and it is at file scope,
|
||||
// RocksDB never write to the same file again. RocksDB will create a new
|
||||
// file and rewrite the whole content. Thus, it is retryable.
|
||||
// 1) if the error is caused by data loss, the error is mapped to
|
||||
// unrecoverable error. Application/user must take action to handle
|
||||
// this situation.
|
||||
// 2) if the error is a Retryable IO error, auto resume will be called and the
|
||||
// auto resume can be controlled by resume count and resume interval
|
||||
// options. There are three sub-cases:
|
||||
// this situation (File scope case is excluded).
|
||||
// 2) if the error is a Retryable IO error (i.e., it is a file scope IO error,
|
||||
// or its retryable flag is set and not a data loss error), auto resume
|
||||
// will be called and the auto resume can be controlled by resume count
|
||||
// and resume interval options. There are three sub-cases:
|
||||
// a) if the error happens during compaction, it is mapped to a soft error.
|
||||
// the compaction thread will reschedule a new compaction.
|
||||
// b) if the error happens during flush and also WAL is empty, it is mapped
|
||||
@@ -384,9 +389,10 @@ const Status& ErrorHandler::SetBGError(const IOStatus& bg_io_err,
|
||||
|
||||
Status new_bg_io_err = bg_io_err;
|
||||
DBRecoverContext context;
|
||||
if (bg_io_err.GetDataLoss()) {
|
||||
// First, data loss is treated as unrecoverable error. So it can directly
|
||||
// overwrite any existing bg_error_.
|
||||
if (bg_io_err.GetScope() != IOStatus::IOErrorScope::kIOErrorScopeFile &&
|
||||
bg_io_err.GetDataLoss()) {
|
||||
// First, data loss (non file scope) is treated as unrecoverable error. So
|
||||
// it can directly overwrite any existing bg_error_.
|
||||
bool auto_recovery = false;
|
||||
Status bg_err(new_bg_io_err, Status::Severity::kUnrecoverableError);
|
||||
bg_error_ = bg_err;
|
||||
@@ -397,23 +403,25 @@ const Status& ErrorHandler::SetBGError(const IOStatus& bg_io_err,
|
||||
&bg_err, db_mutex_, &auto_recovery);
|
||||
recover_context_ = context;
|
||||
return bg_error_;
|
||||
} else if (bg_io_err.GetRetryable()) {
|
||||
// Second, check if the error is a retryable IO error or not. if it is
|
||||
// retryable error and its severity is higher than bg_error_, overwrite
|
||||
// the bg_error_ with new error.
|
||||
// In current stage, for retryable IO error of compaction, treat it as
|
||||
// soft error. In other cases, treat the retryable IO error as hard
|
||||
// error.
|
||||
} else if (bg_io_err.GetScope() ==
|
||||
IOStatus::IOErrorScope::kIOErrorScopeFile ||
|
||||
bg_io_err.GetRetryable()) {
|
||||
// Second, check if the error is a retryable IO error (file scope IO error
|
||||
// is also treated as retryable IO error in RocksDB write path). if it is
|
||||
// retryable error and its severity is higher than bg_error_, overwrite the
|
||||
// bg_error_ with new error. In current stage, for retryable IO error of
|
||||
// compaction, treat it as soft error. In other cases, treat the retryable
|
||||
// IO error as hard error.
|
||||
bool auto_recovery = false;
|
||||
EventHelpers::NotifyOnBackgroundError(db_options_.listeners, reason,
|
||||
&new_bg_io_err, db_mutex_,
|
||||
&auto_recovery);
|
||||
if (BackgroundErrorReason::kCompaction == reason) {
|
||||
Status bg_err(new_bg_io_err, Status::Severity::kSoftError);
|
||||
if (bg_err.severity() > bg_error_.severity()) {
|
||||
bg_error_ = bg_err;
|
||||
}
|
||||
recover_context_ = context;
|
||||
// We map the retryable IO error during compaction to soft error. Since
|
||||
// compaction can reschedule by itself. We will not set the BG error in
|
||||
// this case
|
||||
// TODO: a better way to set or clean the retryable IO error which
|
||||
// happens during compaction SST file write.
|
||||
return bg_error_;
|
||||
} else if (BackgroundErrorReason::kFlushNoWAL == reason ||
|
||||
BackgroundErrorReason::kManifestWriteNoWAL == reason) {
|
||||
|
||||
+276
-100
@@ -9,9 +9,9 @@
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "file/sst_file_manager_impl.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/io_status.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "rocksdb/sst_file_manager.h"
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "test_util/sync_point.h"
|
||||
@@ -173,7 +173,7 @@ TEST_F(DBErrorHandlingFSTest, FLushWriteError) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val", Get(Key(0)));
|
||||
@@ -241,6 +241,90 @@ TEST_F(DBErrorHandlingFSTest, FLushWritRetryableError) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, FLushWritFileScopeError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_env_.get();
|
||||
options.create_if_missing = true;
|
||||
options.listeners.emplace_back(listener);
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
|
||||
listener->EnableAutoRecovery(false);
|
||||
DestroyAndReopen(options);
|
||||
|
||||
IOStatus error_msg = IOStatus::IOError("File Scope Data Loss Error");
|
||||
error_msg.SetDataLoss(true);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFile);
|
||||
error_msg.SetRetryable(false);
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val1"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeFinishBuildTable",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeSyncTable",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
ASSERT_OK(Put(Key(3), "val3"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeCloseTableFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val3", Get(Key(3)));
|
||||
|
||||
// not file scope, but retyrable set
|
||||
error_msg.SetDataLoss(false);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFileSystem);
|
||||
error_msg.SetRetryable(true);
|
||||
|
||||
ASSERT_OK(Put(Key(3), "val3"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeCloseTableFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val3", Get(Key(3)));
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, FLushWritNoWALRetryableError1) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
@@ -271,7 +355,7 @@ TEST_F(DBErrorHandlingFSTest, FLushWritNoWALRetryableError1) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
ASSERT_OK(Put(Key(3), "val3", wo));
|
||||
@@ -314,7 +398,7 @@ TEST_F(DBErrorHandlingFSTest, FLushWritNoWALRetryableError2) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
ASSERT_OK(Put(Key(3), "val3", wo));
|
||||
@@ -357,7 +441,7 @@ TEST_F(DBErrorHandlingFSTest, FLushWritNoWALRetryableError3) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
ASSERT_OK(Put(Key(3), "val3", wo));
|
||||
@@ -399,7 +483,7 @@ TEST_F(DBErrorHandlingFSTest, ManifestWriteError) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
@@ -442,7 +526,53 @@ TEST_F(DBErrorHandlingFSTest, ManifestWriteRetryableError) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val", Get(Key(0)));
|
||||
ASSERT_EQ("val", Get(Key(1)));
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, ManifestWriteFileScopeError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_env_.get();
|
||||
options.create_if_missing = true;
|
||||
options.listeners.emplace_back(listener);
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
std::string old_manifest;
|
||||
std::string new_manifest;
|
||||
|
||||
listener->EnableAutoRecovery(false);
|
||||
DestroyAndReopen(options);
|
||||
old_manifest = GetManifestNameFromLiveFiles();
|
||||
|
||||
IOStatus error_msg = IOStatus::IOError("File Scope Data Loss Error");
|
||||
error_msg.SetDataLoss(true);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFile);
|
||||
error_msg.SetRetryable(false);
|
||||
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionSet::LogAndApply:WriteManifest",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
@@ -487,7 +617,7 @@ TEST_F(DBErrorHandlingFSTest, ManifestWriteNoWALRetryableError) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
@@ -535,7 +665,7 @@ TEST_F(DBErrorHandlingFSTest, DoubleManifestWriteError) {
|
||||
|
||||
// A successful Resume() will create a new manifest file
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
@@ -568,7 +698,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionManifestWriteError) {
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Put(Key(2), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
// Wait for flush of 2nd L0 file before starting compaction
|
||||
@@ -598,7 +728,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionManifestWriteError) {
|
||||
// This Flush will trigger a compaction, which will fail when appending to
|
||||
// the manifest
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
TEST_SYNC_POINT("CompactionManifestWriteError:0");
|
||||
// Clear all errors so when the compaction is retried, it will succeed
|
||||
@@ -609,7 +739,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionManifestWriteError) {
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
@@ -642,7 +772,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionManifestWriteRetryableError) {
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Put(Key(2), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->OverrideBGError(Status(error_msg, Status::Severity::kHardError));
|
||||
listener->EnableAutoRecovery(false);
|
||||
@@ -668,7 +798,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionManifestWriteRetryableError) {
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
TEST_SYNC_POINT("CompactionManifestWriteError:0");
|
||||
TEST_SYNC_POINT("CompactionManifestWriteError:1");
|
||||
@@ -680,7 +810,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionManifestWriteRetryableError) {
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
@@ -706,7 +836,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteError) {
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->OverrideBGError(
|
||||
Status(Status::NoSpace(), Status::Severity::kHardError));
|
||||
@@ -723,18 +853,18 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteError) {
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableError) {
|
||||
TEST_F(DBErrorHandlingFSTest, DISABLED_CompactionWriteRetryableError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
@@ -752,7 +882,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableError) {
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->OverrideBGError(Status(error_msg, Status::Severity::kHardError));
|
||||
listener->EnableAutoRecovery(false);
|
||||
@@ -762,20 +892,73 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableError) {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"CompactionJob::OpenCompactionOutputFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:Finish",
|
||||
[&](void*) { CancelAllBackgroundWork(dbfull()); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kSoftError);
|
||||
s = dbfull()->TEST_GetBGError();
|
||||
ASSERT_OK(s);
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, DISABLED_CompactionWriteFileScopeError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_env_.get();
|
||||
options.create_if_missing = true;
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.listeners.emplace_back(listener);
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
IOStatus error_msg = IOStatus::IOError("File Scope Data Loss Error");
|
||||
error_msg.SetDataLoss(true);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFile);
|
||||
error_msg.SetRetryable(false);
|
||||
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->OverrideBGError(Status(error_msg, Status::Severity::kHardError));
|
||||
listener->EnableAutoRecovery(false);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::FlushMemTable:FlushMemTableFinished",
|
||||
"BackgroundCallCompaction:0"}});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"CompactionJob::OpenCompactionOutputFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:Finish",
|
||||
[&](void*) { CancelAllBackgroundWork(dbfull()); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_GetBGError();
|
||||
ASSERT_OK(s);
|
||||
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
@@ -790,7 +973,7 @@ TEST_F(DBErrorHandlingFSTest, CorruptionError) {
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::FlushMemTable:FlushMemTableFinished",
|
||||
@@ -804,7 +987,7 @@ TEST_F(DBErrorHandlingFSTest, CorruptionError) {
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(),
|
||||
@@ -812,7 +995,7 @@ TEST_F(DBErrorHandlingFSTest, CorruptionError) {
|
||||
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_NE(s, Status::OK());
|
||||
ASSERT_NOK(s);
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
@@ -844,7 +1027,7 @@ TEST_F(DBErrorHandlingFSTest, AutoRecoverFlushError) {
|
||||
ASSERT_EQ(listener->WaitForRecovery(5000000), true);
|
||||
|
||||
s = Put(Key(1), "val");
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val", Get(Key(0)));
|
||||
@@ -874,7 +1057,7 @@ TEST_F(DBErrorHandlingFSTest, FailRecoverFlushError) {
|
||||
// We should be able to shutdown the database while auto recovery is going
|
||||
// on in the background
|
||||
Close();
|
||||
DestroyDB(dbname_, options);
|
||||
DestroyDB(dbname_, options).PermitUncheckedError();
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, WALWriteError) {
|
||||
@@ -904,7 +1087,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteError) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
{
|
||||
@@ -960,7 +1143,6 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableError) {
|
||||
options.listeners.emplace_back(listener);
|
||||
options.paranoid_checks = true;
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
Random rnd(301);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
@@ -978,7 +1160,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableError) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
// For the second batch, the first 2 file Append are successful, then the
|
||||
@@ -1001,8 +1183,8 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableError) {
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
s = dbfull()->Write(wopts, &batch);
|
||||
ASSERT_EQ(true, s.IsIOError());
|
||||
Status s = dbfull()->Write(wopts, &batch);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
}
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
@@ -1018,8 +1200,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableError) {
|
||||
}
|
||||
|
||||
// Resume and write a new batch, should be in the WAL
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(dbfull()->Resume());
|
||||
{
|
||||
WriteBatch batch;
|
||||
|
||||
@@ -1029,7 +1210,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableError) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
Reopen(options);
|
||||
@@ -1055,7 +1236,6 @@ TEST_F(DBErrorHandlingFSTest, MultiCFWALWriteError) {
|
||||
options.create_if_missing = true;
|
||||
options.writable_file_max_buffer_size = 32768;
|
||||
options.listeners.emplace_back(listener);
|
||||
Status s;
|
||||
Random rnd(301);
|
||||
|
||||
listener->EnableAutoRecovery();
|
||||
@@ -1072,7 +1252,7 @@ TEST_F(DBErrorHandlingFSTest, MultiCFWALWriteError) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
{
|
||||
@@ -1095,8 +1275,8 @@ TEST_F(DBErrorHandlingFSTest, MultiCFWALWriteError) {
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
s = dbfull()->Write(wopts, &batch);
|
||||
ASSERT_EQ(s, s.NoSpace());
|
||||
Status s = dbfull()->Write(wopts, &batch);
|
||||
ASSERT_TRUE(s.IsNoSpace());
|
||||
}
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
@@ -1164,9 +1344,8 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
listener[i]->InjectFileCreationError(fault_fs[i], 3,
|
||||
IOStatus::NoSpace("Out of space"));
|
||||
snprintf(buf, sizeof(buf), "_%d", i);
|
||||
DestroyDB(dbname_ + std::string(buf), options[i]);
|
||||
ASSERT_EQ(DB::Open(options[i], dbname_ + std::string(buf), &dbptr),
|
||||
Status::OK());
|
||||
ASSERT_OK(DestroyDB(dbname_ + std::string(buf), options[i]));
|
||||
ASSERT_OK(DB::Open(options[i], dbname_ + std::string(buf), &dbptr));
|
||||
db.emplace_back(dbptr);
|
||||
}
|
||||
|
||||
@@ -1179,8 +1358,8 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(db[i]->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_EQ(db[i]->Flush(FlushOptions()), Status::OK());
|
||||
ASSERT_OK(db[i]->Write(wopts, &batch));
|
||||
ASSERT_OK(db[i]->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
def_env->SetFilesystemActive(false, Status::NoSpace("Out of space"));
|
||||
@@ -1194,8 +1373,8 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(db[i]->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_EQ(db[i]->Flush(FlushOptions()), Status::OK());
|
||||
ASSERT_OK(db[i]->Write(wopts, &batch));
|
||||
ASSERT_OK(db[i]->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
for (auto i = 0; i < kNumDbInstances; ++i) {
|
||||
@@ -1208,8 +1387,7 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
for (auto i = 0; i < kNumDbInstances; ++i) {
|
||||
std::string prop;
|
||||
ASSERT_EQ(listener[i]->WaitForRecovery(5000000), true);
|
||||
ASSERT_EQ(static_cast<DBImpl*>(db[i])->TEST_WaitForCompact(true),
|
||||
Status::OK());
|
||||
ASSERT_OK(static_cast<DBImpl*>(db[i])->TEST_WaitForCompact(true));
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(0), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 0);
|
||||
@@ -1218,6 +1396,10 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
EXPECT_EQ(atoi(prop.c_str()), 1);
|
||||
}
|
||||
|
||||
SstFileManagerImpl* sfmImpl =
|
||||
static_cast_with_check<SstFileManagerImpl>(sfm.get());
|
||||
sfmImpl->Close();
|
||||
|
||||
for (auto i = 0; i < kNumDbInstances; ++i) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "_%d", i);
|
||||
@@ -1226,7 +1408,7 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
if (getenv("KEEP_DB")) {
|
||||
printf("DB is still at %s%s\n", dbname_.c_str(), buf);
|
||||
} else {
|
||||
Status s = DestroyDB(dbname_ + std::string(buf), options[i]);
|
||||
ASSERT_OK(DestroyDB(dbname_ + std::string(buf), options[i]));
|
||||
}
|
||||
}
|
||||
options.clear();
|
||||
@@ -1281,9 +1463,8 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
break;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "_%d", i);
|
||||
DestroyDB(dbname_ + std::string(buf), options[i]);
|
||||
ASSERT_EQ(DB::Open(options[i], dbname_ + std::string(buf), &dbptr),
|
||||
Status::OK());
|
||||
ASSERT_OK(DestroyDB(dbname_ + std::string(buf), options[i]));
|
||||
ASSERT_OK(DB::Open(options[i], dbname_ + std::string(buf), &dbptr));
|
||||
db.emplace_back(dbptr);
|
||||
}
|
||||
|
||||
@@ -1296,8 +1477,8 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(db[i]->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_EQ(db[i]->Flush(FlushOptions()), Status::OK());
|
||||
ASSERT_OK(db[i]->Write(wopts, &batch));
|
||||
ASSERT_OK(db[i]->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
def_env->SetFilesystemActive(false, Status::NoSpace("Out of space"));
|
||||
@@ -1311,11 +1492,11 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(db[i]->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(db[i]->Write(wopts, &batch));
|
||||
if (i != 1) {
|
||||
ASSERT_EQ(db[i]->Flush(FlushOptions()), Status::OK());
|
||||
ASSERT_OK(db[i]->Flush(FlushOptions()));
|
||||
} else {
|
||||
ASSERT_EQ(db[i]->Flush(FlushOptions()), Status::NoSpace());
|
||||
ASSERT_TRUE(db[i]->Flush(FlushOptions()).IsNoSpace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1329,7 +1510,7 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
ASSERT_EQ(s.severity(), Status::Severity::kHardError);
|
||||
break;
|
||||
case 2:
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
break;
|
||||
}
|
||||
fault_fs[i]->SetFilesystemActive(true);
|
||||
@@ -1342,8 +1523,7 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
ASSERT_EQ(listener[i]->WaitForRecovery(5000000), true);
|
||||
}
|
||||
if (i == 1) {
|
||||
ASSERT_EQ(static_cast<DBImpl*>(db[i])->TEST_WaitForCompact(true),
|
||||
Status::OK());
|
||||
ASSERT_OK(static_cast<DBImpl*>(db[i])->TEST_WaitForCompact(true));
|
||||
}
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(0), &prop));
|
||||
@@ -1353,6 +1533,10 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
EXPECT_EQ(atoi(prop.c_str()), 1);
|
||||
}
|
||||
|
||||
SstFileManagerImpl* sfmImpl =
|
||||
static_cast_with_check<SstFileManagerImpl>(sfm.get());
|
||||
sfmImpl->Close();
|
||||
|
||||
for (auto i = 0; i < kNumDbInstances; ++i) {
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "_%d", i);
|
||||
@@ -1361,7 +1545,7 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
if (getenv("KEEP_DB")) {
|
||||
printf("DB is still at %s%s\n", dbname_.c_str(), buf);
|
||||
} else {
|
||||
DestroyDB(dbname_ + std::string(buf), options[i]);
|
||||
EXPECT_OK(DestroyDB(dbname_ + std::string(buf), options[i]));
|
||||
}
|
||||
}
|
||||
options.clear();
|
||||
@@ -1418,12 +1602,10 @@ TEST_F(DBErrorHandlingFSTest, FLushWritNoWALRetryableeErrorAutoRecover1) {
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
// call auto resume
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(dbfull()->Resume());
|
||||
ASSERT_OK(Put(Key(3), "val3", wo));
|
||||
s = Flush();
|
||||
// After resume is successful, the flush should be ok.
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("val3", Get(Key(3)));
|
||||
Destroy(options);
|
||||
}
|
||||
@@ -1513,8 +1695,7 @@ TEST_F(DBErrorHandlingFSTest, DISABLED_FLushWritRetryableeErrorAutoRecover1) {
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
Destroy(options);
|
||||
@@ -1554,8 +1735,7 @@ TEST_F(DBErrorHandlingFSTest, FLushWritRetryableeErrorAutoRecover2) {
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
Destroy(options);
|
||||
@@ -1602,10 +1782,9 @@ TEST_F(DBErrorHandlingFSTest, FLushWritRetryableeErrorAutoRecover3) {
|
||||
// resume manually here.
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
Destroy(options);
|
||||
@@ -1656,19 +1835,16 @@ TEST_F(DBErrorHandlingFSTest, DISABLED_FLushWritRetryableeErrorAutoRecover4) {
|
||||
// Even the FS is recoverd, due to the Fatal Error in bg_error_ the resume
|
||||
// and flush will all fail.
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_NE(s, Status::OK());
|
||||
ASSERT_NOK(dbfull()->Resume());
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_NE(s, Status::OK());
|
||||
ASSERT_NOK(Flush());
|
||||
ASSERT_EQ("NOT_FOUND", Get(Key(2)));
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
Destroy(options);
|
||||
@@ -1708,7 +1884,7 @@ TEST_F(DBErrorHandlingFSTest, DISABLED_FLushWritRetryableeErrorAutoRecover5) {
|
||||
// The first resume will cause recovery_error and its severity is the
|
||||
// Fatal error
|
||||
s = dbfull()->Close();
|
||||
ASSERT_NE(s, Status::OK());
|
||||
ASSERT_NOK(s);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
@@ -1717,7 +1893,7 @@ TEST_F(DBErrorHandlingFSTest, DISABLED_FLushWritRetryableeErrorAutoRecover5) {
|
||||
ASSERT_NE("val1", Get(Key(1)));
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
Destroy(options);
|
||||
@@ -1768,14 +1944,14 @@ TEST_F(DBErrorHandlingFSTest, FLushWritRetryableeErrorAutoRecover6) {
|
||||
// The first resume will cause recovery_error and its severity is the
|
||||
// Fatal error
|
||||
s = dbfull()->Close();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
Destroy(options);
|
||||
@@ -1912,8 +2088,7 @@ TEST_F(DBErrorHandlingFSTest,
|
||||
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Put(Key(2), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
listener->OverrideBGError(Status(error_msg, Status::Severity::kHardError));
|
||||
listener->EnableAutoRecovery(false);
|
||||
@@ -1950,7 +2125,7 @@ TEST_F(DBErrorHandlingFSTest,
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
TEST_SYNC_POINT("CompactionManifestWriteErrorAR:0");
|
||||
TEST_SYNC_POINT("CompactionManifestWriteErrorAR:1");
|
||||
@@ -2000,7 +2175,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableErrorAutoRecover) {
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->OverrideBGError(Status(error_msg, Status::Severity::kHardError));
|
||||
listener->EnableAutoRecovery(false);
|
||||
@@ -2025,11 +2200,10 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableErrorAutoRecover) {
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kSoftError);
|
||||
|
||||
ASSERT_OK(s);
|
||||
TEST_SYNC_POINT("CompactionWriteRetryableErrorAutoRecover0");
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
@@ -2065,7 +2239,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableErrorAutoRecover1) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
// For the second batch, the first 2 file Append are successful, then the
|
||||
@@ -2078,7 +2252,8 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableErrorAutoRecover1) {
|
||||
ASSERT_OK(batch.Put(Key(i), rnd.RandomString(1024)));
|
||||
}
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"RecoverFromRetryableBGIOError:BeforeResume0", "WALWriteError1:0"},
|
||||
{{"WALWriteErrorDone", "RecoverFromRetryableBGIOError:BeforeStart"},
|
||||
{"RecoverFromRetryableBGIOError:BeforeResume0", "WALWriteError1:0"},
|
||||
{"WALWriteError1:1", "RecoverFromRetryableBGIOError:BeforeResume1"},
|
||||
{"RecoverFromRetryableBGIOError:RecoverSuccess", "WALWriteError1:2"}});
|
||||
|
||||
@@ -2094,6 +2269,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableErrorAutoRecover1) {
|
||||
wopts.sync = true;
|
||||
s = dbfull()->Write(wopts, &batch);
|
||||
ASSERT_EQ(true, s.IsIOError());
|
||||
TEST_SYNC_POINT("WALWriteErrorDone");
|
||||
|
||||
TEST_SYNC_POINT("WALWriteError1:0");
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
@@ -2122,7 +2298,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableErrorAutoRecover1) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
Reopen(options);
|
||||
@@ -2166,7 +2342,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableErrorAutoRecover2) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
// For the second batch, the first 2 file Append are successful, then the
|
||||
@@ -2223,7 +2399,7 @@ TEST_F(DBErrorHandlingFSTest, WALWriteRetryableErrorAutoRecover2) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
Reopen(options);
|
||||
@@ -2285,7 +2461,7 @@ TEST_P(DBErrorHandlingFencingTest, ManifestWriteFenced) {
|
||||
old_manifest = GetManifestNameFromLiveFiles();
|
||||
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionSet::LogAndApply:WriteManifest", [&](void*) {
|
||||
@@ -2318,7 +2494,7 @@ TEST_P(DBErrorHandlingFencingTest, CompactionWriteFenced) {
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->EnableAutoRecovery(true);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
@@ -2332,7 +2508,7 @@ TEST_P(DBErrorHandlingFencingTest, CompactionWriteFenced) {
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kFatalError);
|
||||
@@ -2368,7 +2544,7 @@ TEST_P(DBErrorHandlingFencingTest, WALWriteFenced) {
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
ASSERT_EQ(dbfull()->Write(wopts, &batch), Status::OK());
|
||||
ASSERT_OK(dbfull()->Write(wopts, &batch));
|
||||
};
|
||||
|
||||
{
|
||||
|
||||
+8
-9
@@ -213,17 +213,16 @@ void EventHelpers::NotifyOnErrorRecoveryCompleted(
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
Status old_bg_error, InstrumentedMutex* db_mutex) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.size() == 0U) {
|
||||
return;
|
||||
}
|
||||
db_mutex->AssertHeld();
|
||||
// release lock while notifying events
|
||||
db_mutex->Unlock();
|
||||
for (auto& listener : listeners) {
|
||||
listener->OnErrorRecoveryCompleted(old_bg_error);
|
||||
if (listeners.size() > 0) {
|
||||
db_mutex->AssertHeld();
|
||||
// release lock while notifying events
|
||||
db_mutex->Unlock();
|
||||
for (auto& listener : listeners) {
|
||||
listener->OnErrorRecoveryCompleted(old_bg_error);
|
||||
}
|
||||
db_mutex->Lock();
|
||||
}
|
||||
old_bg_error.PermitUncheckedError();
|
||||
db_mutex->Lock();
|
||||
#else
|
||||
(void)listeners;
|
||||
(void)old_bg_error;
|
||||
|
||||
@@ -201,7 +201,8 @@ Status ExternalSstFileIngestionJob::Prepare(
|
||||
requested_checksum_func_name, &generated_checksum,
|
||||
&generated_checksum_func_name,
|
||||
ingestion_options_.verify_checksums_readahead_size,
|
||||
db_options_.allow_mmap_reads, io_tracer_);
|
||||
db_options_.allow_mmap_reads, io_tracer_,
|
||||
db_options_.rate_limiter.get());
|
||||
if (!io_s.ok()) {
|
||||
status = io_s;
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
@@ -809,7 +810,8 @@ Status ExternalSstFileIngestionJob::AssignGlobalSeqnoForIngestedFile(
|
||||
fs_->NewRandomRWFile(file_to_ingest->internal_file_path, env_options_,
|
||||
&rwfile, nullptr);
|
||||
if (status.ok()) {
|
||||
FSRandomRWFilePtr fsptr(std::move(rwfile), io_tracer_);
|
||||
FSRandomRWFilePtr fsptr(std::move(rwfile), io_tracer_,
|
||||
file_to_ingest->internal_file_path);
|
||||
std::string seqno_val;
|
||||
PutFixed64(&seqno_val, seqno);
|
||||
status = fsptr->Write(file_to_ingest->global_seqno_offset, seqno_val,
|
||||
@@ -856,7 +858,7 @@ IOStatus ExternalSstFileIngestionJob::GenerateChecksumForIngestedFile(
|
||||
db_options_.file_checksum_gen_factory.get(), requested_checksum_func_name,
|
||||
&file_checksum, &file_checksum_func_name,
|
||||
ingestion_options_.verify_checksums_readahead_size,
|
||||
db_options_.allow_mmap_reads, io_tracer_);
|
||||
db_options_.allow_mmap_reads, io_tracer_, db_options_.rate_limiter.get());
|
||||
if (!io_s.ok()) {
|
||||
return io_s;
|
||||
}
|
||||
|
||||
+92
-135
@@ -47,8 +47,8 @@ class ExternSSTFileLinkFailFallbackTest
|
||||
: DBTestBase("/external_sst_file_test", /*env_do_fsync=*/true),
|
||||
test_env_(new ExternalSSTTestEnv(env_, true)) {
|
||||
sst_files_dir_ = dbname_ + "/sst_files/";
|
||||
DestroyDir(env_, sst_files_dir_);
|
||||
env_->CreateDir(sst_files_dir_);
|
||||
EXPECT_EQ(DestroyDir(env_, sst_files_dir_), Status::OK());
|
||||
EXPECT_EQ(env_->CreateDir(sst_files_dir_), Status::OK());
|
||||
options_ = CurrentOptions();
|
||||
options_.disable_auto_compactions = true;
|
||||
options_.env = test_env_;
|
||||
@@ -79,8 +79,8 @@ class ExternalSSTFileTest
|
||||
}
|
||||
|
||||
void DestroyAndRecreateExternalSSTFilesDir() {
|
||||
DestroyDir(env_, sst_files_dir_);
|
||||
env_->CreateDir(sst_files_dir_);
|
||||
ASSERT_OK(DestroyDir(env_, sst_files_dir_));
|
||||
ASSERT_OK(env_->CreateDir(sst_files_dir_));
|
||||
}
|
||||
|
||||
Status GenerateOneExternalFile(
|
||||
@@ -116,7 +116,7 @@ class ExternalSSTFileTest
|
||||
for (const auto& entry : data) {
|
||||
s = sst_file_writer.Put(entry.first, entry.second);
|
||||
if (!s.ok()) {
|
||||
sst_file_writer.Finish();
|
||||
sst_file_writer.Finish().PermitUncheckedError();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ class ExternalSSTFileTest
|
||||
for (auto& entry : data) {
|
||||
s = sst_file_writer.Put(entry.first, entry.second);
|
||||
if (!s.ok()) {
|
||||
sst_file_writer.Finish();
|
||||
sst_file_writer.Finish().PermitUncheckedError();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -213,11 +213,10 @@ class ExternalSSTFileTest
|
||||
size_t num_cfs = column_families.size();
|
||||
assert(ifos.size() == num_cfs);
|
||||
assert(data.size() == num_cfs);
|
||||
Status s;
|
||||
std::vector<IngestExternalFileArg> args(num_cfs);
|
||||
for (size_t i = 0; i != num_cfs; ++i) {
|
||||
std::string external_file_path;
|
||||
s = GenerateOneExternalFile(
|
||||
Status s = GenerateOneExternalFile(
|
||||
options, column_families[i], data[i], file_id, sort_data,
|
||||
&external_file_path,
|
||||
true_data.size() == num_cfs ? &true_data[i] : nullptr);
|
||||
@@ -230,8 +229,7 @@ class ExternalSSTFileTest
|
||||
args[i].external_files.push_back(external_file_path);
|
||||
args[i].options = ifos[i];
|
||||
}
|
||||
s = db_->IngestExternalFiles(args);
|
||||
return s;
|
||||
return db_->IngestExternalFiles(args);
|
||||
}
|
||||
|
||||
Status GenerateAndAddExternalFile(
|
||||
@@ -282,7 +280,9 @@ class ExternalSSTFileTest
|
||||
return db_->IngestExternalFile(files, opts);
|
||||
}
|
||||
|
||||
~ExternalSSTFileTest() override { DestroyDir(env_, sst_files_dir_); }
|
||||
~ExternalSSTFileTest() override {
|
||||
DestroyDir(env_, sst_files_dir_).PermitUncheckedError();
|
||||
}
|
||||
|
||||
protected:
|
||||
int last_file_id_ = 0;
|
||||
@@ -305,8 +305,7 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file1_info;
|
||||
Status s = sst_file_writer.Finish(&file1_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file1_info));
|
||||
|
||||
// Current file size should be non-zero after success write.
|
||||
ASSERT_GT(sst_file_writer.FileSize(), 0);
|
||||
@@ -319,8 +318,7 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_EQ(file1_info.smallest_range_del_key, "");
|
||||
ASSERT_EQ(file1_info.largest_range_del_key, "");
|
||||
// sst_file_writer already finished, cannot add this value
|
||||
s = sst_file_writer.Put(Key(100), "bad_val");
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(sst_file_writer.Put(Key(100), "bad_val"));
|
||||
|
||||
// file2.sst (100 => 199)
|
||||
std::string file2 = sst_files_dir_ + "file2.sst";
|
||||
@@ -329,11 +327,9 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
// Cannot add this key because it's not after last added key
|
||||
s = sst_file_writer.Put(Key(99), "bad_val");
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(sst_file_writer.Put(Key(99), "bad_val"));
|
||||
ExternalSstFileInfo file2_info;
|
||||
s = sst_file_writer.Finish(&file2_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file2_info));
|
||||
ASSERT_EQ(file2_info.file_path, file2);
|
||||
ASSERT_EQ(file2_info.num_entries, 100);
|
||||
ASSERT_EQ(file2_info.smallest_key, Key(100));
|
||||
@@ -347,9 +343,8 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val_overlap"));
|
||||
}
|
||||
ExternalSstFileInfo file3_info;
|
||||
s = sst_file_writer.Finish(&file3_info);
|
||||
ASSERT_OK(sst_file_writer.Finish(&file3_info));
|
||||
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
// Current file size should be non-zero after success finish.
|
||||
ASSERT_GT(sst_file_writer.FileSize(), 0);
|
||||
ASSERT_EQ(file3_info.file_path, file3);
|
||||
@@ -365,8 +360,7 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val_overlap"));
|
||||
}
|
||||
ExternalSstFileInfo file4_info;
|
||||
s = sst_file_writer.Finish(&file4_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file4_info));
|
||||
ASSERT_EQ(file4_info.file_path, file4);
|
||||
ASSERT_EQ(file4_info.num_entries, 10);
|
||||
ASSERT_EQ(file4_info.smallest_key, Key(30));
|
||||
@@ -379,8 +373,7 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file5_info;
|
||||
s = sst_file_writer.Finish(&file5_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file5_info));
|
||||
ASSERT_EQ(file5_info.file_path, file5);
|
||||
ASSERT_EQ(file5_info.num_entries, 100);
|
||||
ASSERT_EQ(file5_info.smallest_key, Key(400));
|
||||
@@ -389,10 +382,9 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
// file6.sst (delete 400 => 500)
|
||||
std::string file6 = sst_files_dir_ + "file6.sst";
|
||||
ASSERT_OK(sst_file_writer.Open(file6));
|
||||
sst_file_writer.DeleteRange(Key(400), Key(500));
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(400), Key(500)));
|
||||
ExternalSstFileInfo file6_info;
|
||||
s = sst_file_writer.Finish(&file6_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file6_info));
|
||||
ASSERT_EQ(file6_info.file_path, file6);
|
||||
ASSERT_EQ(file6_info.num_entries, 0);
|
||||
ASSERT_EQ(file6_info.smallest_key, "");
|
||||
@@ -404,17 +396,16 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
// file7.sst (delete 500 => 570, put 520 => 599 divisible by 2)
|
||||
std::string file7 = sst_files_dir_ + "file7.sst";
|
||||
ASSERT_OK(sst_file_writer.Open(file7));
|
||||
sst_file_writer.DeleteRange(Key(500), Key(550));
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(500), Key(550)));
|
||||
for (int k = 520; k < 560; k += 2) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
sst_file_writer.DeleteRange(Key(525), Key(575));
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(525), Key(575)));
|
||||
for (int k = 560; k < 600; k += 2) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file7_info;
|
||||
s = sst_file_writer.Finish(&file7_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file7_info));
|
||||
ASSERT_EQ(file7_info.file_path, file7);
|
||||
ASSERT_EQ(file7_info.num_entries, 40);
|
||||
ASSERT_EQ(file7_info.smallest_key, Key(520));
|
||||
@@ -426,10 +417,9 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
// file8.sst (delete 600 => 700)
|
||||
std::string file8 = sst_files_dir_ + "file8.sst";
|
||||
ASSERT_OK(sst_file_writer.Open(file8));
|
||||
sst_file_writer.DeleteRange(Key(600), Key(700));
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(600), Key(700)));
|
||||
ExternalSstFileInfo file8_info;
|
||||
s = sst_file_writer.Finish(&file8_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file8_info));
|
||||
ASSERT_EQ(file8_info.file_path, file8);
|
||||
ASSERT_EQ(file8_info.num_entries, 0);
|
||||
ASSERT_EQ(file8_info.smallest_key, "");
|
||||
@@ -441,13 +431,11 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
// Cannot create an empty sst file
|
||||
std::string file_empty = sst_files_dir_ + "file_empty.sst";
|
||||
ExternalSstFileInfo file_empty_info;
|
||||
s = sst_file_writer.Finish(&file_empty_info);
|
||||
ASSERT_NOK(s);
|
||||
ASSERT_NOK(sst_file_writer.Finish(&file_empty_info));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
// Add file using file path
|
||||
s = DeprecatedAddFile({file1});
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(DeprecatedAddFile({file1}));
|
||||
ASSERT_EQ(db_->GetLatestSequenceNumber(), 0U);
|
||||
for (int k = 0; k < 100; k++) {
|
||||
ASSERT_EQ(Get(Key(k)), Key(k) + "_val");
|
||||
@@ -468,12 +456,10 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
}
|
||||
|
||||
// This file has overlapping values with the existing data
|
||||
s = DeprecatedAddFile({file3});
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile({file3}));
|
||||
|
||||
// This file has overlapping values with the existing data
|
||||
s = DeprecatedAddFile({file4});
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile({file4}));
|
||||
|
||||
// Overwrite values of keys divisible by 5
|
||||
for (int k = 0; k < 200; k += 5) {
|
||||
@@ -485,8 +471,7 @@ TEST_F(ExternalSSTFileTest, Basic) {
|
||||
ASSERT_OK(DeprecatedAddFile({file5}));
|
||||
|
||||
// This file has overlapping values with the existing data
|
||||
s = DeprecatedAddFile({file6});
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile({file6}));
|
||||
|
||||
// Key range of file7 (500 => 598) don't overlap with any keys in DB
|
||||
ASSERT_OK(DeprecatedAddFile({file7}));
|
||||
@@ -614,15 +599,13 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file1_info;
|
||||
Status s = sst_file_writer.Finish(&file1_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file1_info));
|
||||
ASSERT_EQ(file1_info.file_path, file1);
|
||||
ASSERT_EQ(file1_info.num_entries, 100);
|
||||
ASSERT_EQ(file1_info.smallest_key, Key(0));
|
||||
ASSERT_EQ(file1_info.largest_key, Key(99));
|
||||
// sst_file_writer already finished, cannot add this value
|
||||
s = sst_file_writer.Put(Key(100), "bad_val");
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(sst_file_writer.Put(Key(100), "bad_val"));
|
||||
|
||||
// file2.sst (100 => 199)
|
||||
std::string file2 = sst_files_dir_ + "file2.sst";
|
||||
@@ -631,11 +614,9 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
// Cannot add this key because it's not after last added key
|
||||
s = sst_file_writer.Put(Key(99), "bad_val");
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(sst_file_writer.Put(Key(99), "bad_val"));
|
||||
ExternalSstFileInfo file2_info;
|
||||
s = sst_file_writer.Finish(&file2_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file2_info));
|
||||
ASSERT_EQ(file2_info.file_path, file2);
|
||||
ASSERT_EQ(file2_info.num_entries, 100);
|
||||
ASSERT_EQ(file2_info.smallest_key, Key(100));
|
||||
@@ -649,8 +630,7 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val_overlap"));
|
||||
}
|
||||
ExternalSstFileInfo file3_info;
|
||||
s = sst_file_writer.Finish(&file3_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file3_info));
|
||||
ASSERT_EQ(file3_info.file_path, file3);
|
||||
ASSERT_EQ(file3_info.num_entries, 5);
|
||||
ASSERT_EQ(file3_info.smallest_key, Key(195));
|
||||
@@ -664,8 +644,7 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val_overlap"));
|
||||
}
|
||||
ExternalSstFileInfo file4_info;
|
||||
s = sst_file_writer.Finish(&file4_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file4_info));
|
||||
ASSERT_EQ(file4_info.file_path, file4);
|
||||
ASSERT_EQ(file4_info.num_entries, 10);
|
||||
ASSERT_EQ(file4_info.smallest_key, Key(30));
|
||||
@@ -678,8 +657,7 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file5_info;
|
||||
s = sst_file_writer.Finish(&file5_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file5_info));
|
||||
ASSERT_EQ(file5_info.file_path, file5);
|
||||
ASSERT_EQ(file5_info.num_entries, 100);
|
||||
ASSERT_EQ(file5_info.smallest_key, Key(200));
|
||||
@@ -691,8 +669,7 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(0), Key(75)));
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(25), Key(100)));
|
||||
ExternalSstFileInfo file6_info;
|
||||
s = sst_file_writer.Finish(&file6_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file6_info));
|
||||
ASSERT_EQ(file6_info.file_path, file6);
|
||||
ASSERT_EQ(file6_info.num_entries, 0);
|
||||
ASSERT_EQ(file6_info.smallest_key, "");
|
||||
@@ -706,8 +683,7 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
ASSERT_OK(sst_file_writer.Open(file7));
|
||||
ASSERT_OK(sst_file_writer.DeleteRange(Key(99), Key(201)));
|
||||
ExternalSstFileInfo file7_info;
|
||||
s = sst_file_writer.Finish(&file7_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file7_info));
|
||||
ASSERT_EQ(file7_info.file_path, file7);
|
||||
ASSERT_EQ(file7_info.num_entries, 0);
|
||||
ASSERT_EQ(file7_info.smallest_key, "");
|
||||
@@ -727,17 +703,13 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// These lists of files have key ranges that overlap with each other
|
||||
s = DeprecatedAddFile(file_list1);
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile(file_list1));
|
||||
// Both of the following overlap on the range deletion tombstone.
|
||||
s = DeprecatedAddFile(file_list4);
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
s = DeprecatedAddFile(file_list5);
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile(file_list4));
|
||||
ASSERT_NOK(DeprecatedAddFile(file_list5));
|
||||
|
||||
// Add files using file path list
|
||||
s = DeprecatedAddFile(file_list0);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(DeprecatedAddFile(file_list0));
|
||||
ASSERT_EQ(db_->GetLatestSequenceNumber(), 0U);
|
||||
for (int k = 0; k < 200; k++) {
|
||||
ASSERT_EQ(Get(Key(k)), Key(k) + "_val");
|
||||
@@ -778,8 +750,7 @@ TEST_F(ExternalSSTFileTest, AddList) {
|
||||
}
|
||||
|
||||
// This file list has overlapping values with the existing data
|
||||
s = DeprecatedAddFile(file_list3);
|
||||
ASSERT_FALSE(s.ok()) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile(file_list3));
|
||||
|
||||
// Overwrite values of keys divisible by 5
|
||||
for (int k = 0; k < 200; k += 5) {
|
||||
@@ -847,16 +818,14 @@ TEST_F(ExternalSSTFileTest, AddListAtomicity) {
|
||||
for (int k = i * 100; k < (i + 1) * 100; k++) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
Status s = sst_file_writer.Finish(&files_info[i]);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&files_info[i]));
|
||||
ASSERT_EQ(files_info[i].file_path, files[i]);
|
||||
ASSERT_EQ(files_info[i].num_entries, 100);
|
||||
ASSERT_EQ(files_info[i].smallest_key, Key(i * 100));
|
||||
ASSERT_EQ(files_info[i].largest_key, Key((i + 1) * 100 - 1));
|
||||
}
|
||||
files.push_back(sst_files_dir_ + "file" + std::to_string(n) + ".sst");
|
||||
auto s = DeprecatedAddFile(files);
|
||||
ASSERT_NOK(s) << s.ToString();
|
||||
ASSERT_NOK(DeprecatedAddFile(files));
|
||||
for (int k = 0; k < n * 100; k++) {
|
||||
ASSERT_EQ("NOT_FOUND", Get(Key(k)));
|
||||
}
|
||||
@@ -878,17 +847,14 @@ TEST_F(ExternalSSTFileTest, PurgeObsoleteFilesBug) {
|
||||
|
||||
// file1.sst (0 => 500)
|
||||
std::string sst_file_path = sst_files_dir_ + "file1.sst";
|
||||
Status s = sst_file_writer.Open(sst_file_path);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(sst_file_writer.Open(sst_file_path));
|
||||
for (int i = 0; i < 500; i++) {
|
||||
std::string k = Key(i);
|
||||
s = sst_file_writer.Put(k, k + "_val");
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(sst_file_writer.Put(k, k + "_val"));
|
||||
}
|
||||
|
||||
ExternalSstFileInfo sst_file_info;
|
||||
s = sst_file_writer.Finish(&sst_file_info);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(sst_file_writer.Finish(&sst_file_info));
|
||||
|
||||
options.delete_obsolete_files_period_micros = 0;
|
||||
options.disable_auto_compactions = true;
|
||||
@@ -900,12 +866,11 @@ TEST_F(ExternalSSTFileTest, PurgeObsoleteFilesBug) {
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("aaa", "xxx"));
|
||||
ASSERT_OK(Flush());
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
s = DeprecatedAddFile({sst_file_path});
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(DeprecatedAddFile({sst_file_path}));
|
||||
|
||||
for (int i = 0; i < 500; i++) {
|
||||
std::string k = Key(i);
|
||||
@@ -928,8 +893,7 @@ TEST_F(ExternalSSTFileTest, SkipSnapshot) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file1_info;
|
||||
Status s = sst_file_writer.Finish(&file1_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file1_info));
|
||||
ASSERT_EQ(file1_info.file_path, file1);
|
||||
ASSERT_EQ(file1_info.num_entries, 100);
|
||||
ASSERT_EQ(file1_info.smallest_key, Key(0));
|
||||
@@ -942,8 +906,7 @@ TEST_F(ExternalSSTFileTest, SkipSnapshot) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file2_info;
|
||||
s = sst_file_writer.Finish(&file2_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file2_info));
|
||||
ASSERT_EQ(file2_info.file_path, file2);
|
||||
ASSERT_EQ(file2_info.num_entries, 200);
|
||||
ASSERT_EQ(file2_info.smallest_key, Key(100));
|
||||
@@ -972,8 +935,7 @@ TEST_F(ExternalSSTFileTest, SkipSnapshot) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k) + "_val"));
|
||||
}
|
||||
ExternalSstFileInfo file3_info;
|
||||
s = sst_file_writer.Finish(&file3_info);
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish(&file3_info));
|
||||
ASSERT_EQ(file3_info.file_path, file3);
|
||||
ASSERT_EQ(file3_info.num_entries, 100);
|
||||
ASSERT_EQ(file3_info.smallest_key, Key(300));
|
||||
@@ -1019,8 +981,7 @@ TEST_F(ExternalSSTFileTest, MultiThreaded) {
|
||||
ASSERT_OK(sst_file_writer.Put(Key(k), Key(k)));
|
||||
}
|
||||
|
||||
Status s = sst_file_writer.Finish();
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
};
|
||||
// Write num_files files in parallel
|
||||
std::vector<port::Thread> sst_writer_threads;
|
||||
@@ -1082,8 +1043,7 @@ TEST_F(ExternalSSTFileTest, MultiThreaded) {
|
||||
// Overwrite values of keys divisible by 100
|
||||
for (int k = 0; k < num_files * keys_per_file; k += 100) {
|
||||
std::string key = Key(k);
|
||||
Status s = Put(key, key + "_new");
|
||||
ASSERT_TRUE(s.ok());
|
||||
ASSERT_OK(Put(key, key + "_new"));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@@ -1167,7 +1127,8 @@ TEST_F(ExternalSSTFileTest, OverlappingRanges) {
|
||||
|
||||
// Generate the file containing the range
|
||||
std::string file_name = sst_files_dir_ + env_->GenerateUniqueId();
|
||||
ASSERT_OK(sst_file_writer.Open(file_name));
|
||||
s = sst_file_writer.Open(file_name);
|
||||
ASSERT_OK(s);
|
||||
for (int k = range_start; k <= range_end; k++) {
|
||||
s = sst_file_writer.Put(Key(k), range_val);
|
||||
ASSERT_OK(s);
|
||||
@@ -1212,10 +1173,10 @@ TEST_F(ExternalSSTFileTest, OverlappingRanges) {
|
||||
|
||||
// Flush / Compact the DB
|
||||
if (i && i % 50 == 0) {
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
if (i && i % 75 == 0) {
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1293,7 +1254,7 @@ TEST_P(ExternalSSTFileTest, PickedLevel) {
|
||||
// Hold compaction from finishing
|
||||
TEST_SYNC_POINT("ExternalSSTFileTest::PickedLevel:2");
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
EXPECT_EQ(FilesPerLevel(), "1,1,1,2");
|
||||
|
||||
size_t kcnt = 0;
|
||||
@@ -1380,7 +1341,7 @@ TEST_F(ExternalSSTFileTest, PickedLevelBug) {
|
||||
ASSERT_OK(bg_addfile_status);
|
||||
ASSERT_OK(bg_compact_status);
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
int total_keys = 0;
|
||||
Iterator* iter = db_->NewIterator(ReadOptions());
|
||||
@@ -1417,7 +1378,7 @@ TEST_F(ExternalSSTFileTest, IngestNonExistingFile) {
|
||||
|
||||
// After full compaction, there should be only 1 file.
|
||||
std::vector<std::string> files;
|
||||
env_->GetChildren(dbname_, &files);
|
||||
ASSERT_OK(env_->GetChildren(dbname_, &files));
|
||||
int num_sst_files = 0;
|
||||
for (auto& f : files) {
|
||||
uint64_t number;
|
||||
@@ -1539,7 +1500,7 @@ TEST_F(ExternalSSTFileTest, PickedLevelDynamic) {
|
||||
TEST_SYNC_POINT("ExternalSSTFileTest::PickedLevelDynamic:2");
|
||||
|
||||
// Output of the compaction will go to L3
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
EXPECT_EQ(FilesPerLevel(), "1,0,0,2");
|
||||
|
||||
Close();
|
||||
@@ -1681,7 +1642,7 @@ TEST_F(ExternalSSTFileTest, AddFileTrivialMoveBug) {
|
||||
cro.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
@@ -1733,9 +1694,9 @@ TEST_F(ExternalSSTFileTest, WithUnorderedWrite) {
|
||||
Options options = CurrentOptions();
|
||||
options.unordered_write = true;
|
||||
DestroyAndReopen(options);
|
||||
Put("foo", "v1");
|
||||
ASSERT_OK(Put("foo", "v1"));
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
port::Thread writer([&]() { Put("bar", "v2"); });
|
||||
port::Thread writer([&]() { ASSERT_OK(Put("bar", "v2")); });
|
||||
|
||||
TEST_SYNC_POINT("ExternalSSTFileTest::WithUnorderedWrite:WaitWriteWAL");
|
||||
ASSERT_OK(GenerateAndAddExternalFile(options, {{"bar", "v3"}}, -1,
|
||||
@@ -1784,7 +1745,7 @@ TEST_P(ExternalSSTFileTest, IngestFileWithGlobalSeqnoRandomized) {
|
||||
}
|
||||
size_t kcnt = 0;
|
||||
VerifyDBFromMap(true_data, &kcnt, false);
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
VerifyDBFromMap(true_data, &kcnt, false);
|
||||
}
|
||||
}
|
||||
@@ -1868,8 +1829,8 @@ TEST_P(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) {
|
||||
ASSERT_OK(Put(Key(k), "memtable"));
|
||||
true_data[Key(k)] = "memtable";
|
||||
}
|
||||
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable);
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable));
|
||||
ASSERT_GE(entries_in_memtable, 1);
|
||||
|
||||
bool write_global_seqno = std::get<0>(GetParam());
|
||||
@@ -1878,40 +1839,40 @@ TEST_P(ExternalSSTFileTest, IngestFileWithGlobalSeqnoMemtableFlush) {
|
||||
ASSERT_OK(GenerateAndAddExternalFile(
|
||||
options, {90, 100, 110}, -1, true, write_global_seqno,
|
||||
verify_checksums_before_ingest, false, false, &true_data));
|
||||
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable);
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable));
|
||||
ASSERT_GE(entries_in_memtable, 1);
|
||||
|
||||
// This file will flush the memtable
|
||||
ASSERT_OK(GenerateAndAddExternalFile(
|
||||
options, {19, 20, 21}, -1, true, write_global_seqno,
|
||||
verify_checksums_before_ingest, false, false, &true_data));
|
||||
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable);
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable));
|
||||
ASSERT_EQ(entries_in_memtable, 0);
|
||||
|
||||
for (int k : {200, 201, 205, 206}) {
|
||||
ASSERT_OK(Put(Key(k), "memtable"));
|
||||
true_data[Key(k)] = "memtable";
|
||||
}
|
||||
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable);
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable));
|
||||
ASSERT_GE(entries_in_memtable, 1);
|
||||
|
||||
// No need for flush, this file keys fit between the memtable keys
|
||||
ASSERT_OK(GenerateAndAddExternalFile(
|
||||
options, {202, 203, 204}, -1, true, write_global_seqno,
|
||||
verify_checksums_before_ingest, false, false, &true_data));
|
||||
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable);
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable));
|
||||
ASSERT_GE(entries_in_memtable, 1);
|
||||
|
||||
// This file will flush the memtable
|
||||
ASSERT_OK(GenerateAndAddExternalFile(
|
||||
options, {206, 207}, -1, true, write_global_seqno,
|
||||
verify_checksums_before_ingest, false, false, &true_data));
|
||||
db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable);
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&entries_in_memtable));
|
||||
ASSERT_EQ(entries_in_memtable, 0);
|
||||
|
||||
size_t kcnt = 0;
|
||||
@@ -2309,7 +2270,7 @@ TEST_P(ExternalSSTFileTest, IngestBehind) {
|
||||
ASSERT_OK(Put(Key(i), "memtable"));
|
||||
true_data[Key(i)] = "memtable";
|
||||
}
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
// Universal picker should go at second from the bottom level
|
||||
ASSERT_EQ("0,1", FilesPerLevel());
|
||||
ASSERT_OK(GenerateAndAddExternalFile(
|
||||
@@ -2323,7 +2284,7 @@ TEST_P(ExternalSSTFileTest, IngestBehind) {
|
||||
verify_checksums_before_ingest, true /*ingest_behind*/,
|
||||
false /*sort_data*/, &true_data));
|
||||
ASSERT_EQ("0,1,1", FilesPerLevel());
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
// bottom level should be empty
|
||||
ASSERT_EQ("0,1", FilesPerLevel());
|
||||
|
||||
@@ -2471,9 +2432,8 @@ TEST_P(ExternalSSTFileTest, IngestFilesIntoMultipleColumnFamilies_Success) {
|
||||
// Resize the true_data vector upon construction to avoid re-alloc
|
||||
std::vector<std::map<std::string, std::string>> true_data(
|
||||
column_families.size());
|
||||
Status s = GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data));
|
||||
Close();
|
||||
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "pikachu", "eevee"},
|
||||
options);
|
||||
@@ -2654,9 +2614,8 @@ TEST_P(ExternalSSTFileTest, IngestFilesIntoMultipleColumnFamilies_PrepareFail) {
|
||||
std::vector<std::map<std::string, std::string>> true_data(
|
||||
column_families.size());
|
||||
port::Thread ingest_thread([&]() {
|
||||
Status s = GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data);
|
||||
ASSERT_NOK(s);
|
||||
ASSERT_NOK(GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data));
|
||||
});
|
||||
TEST_SYNC_POINT(
|
||||
"ExternalSSTFileTest::IngestFilesIntoMultipleColumnFamilies_PrepareFail:"
|
||||
@@ -2724,9 +2683,8 @@ TEST_P(ExternalSSTFileTest, IngestFilesIntoMultipleColumnFamilies_CommitFail) {
|
||||
std::vector<std::map<std::string, std::string>> true_data(
|
||||
column_families.size());
|
||||
port::Thread ingest_thread([&]() {
|
||||
Status s = GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data);
|
||||
ASSERT_NOK(s);
|
||||
ASSERT_NOK(GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data));
|
||||
});
|
||||
TEST_SYNC_POINT(
|
||||
"ExternalSSTFileTest::IngestFilesIntoMultipleColumnFamilies_CommitFail:"
|
||||
@@ -2799,9 +2757,8 @@ TEST_P(ExternalSSTFileTest,
|
||||
std::vector<std::map<std::string, std::string>> true_data(
|
||||
column_families.size());
|
||||
port::Thread ingest_thread([&]() {
|
||||
Status s = GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data);
|
||||
ASSERT_NOK(s);
|
||||
ASSERT_NOK(GenerateAndAddExternalFiles(options, column_families, ifos, data,
|
||||
-1, true, true_data));
|
||||
});
|
||||
TEST_SYNC_POINT(
|
||||
"ExternalSSTFileTest::IngestFilesIntoMultipleColumnFamilies_"
|
||||
@@ -2812,7 +2769,7 @@ TEST_P(ExternalSSTFileTest,
|
||||
"PartialManifestWriteFail:1");
|
||||
ingest_thread.join();
|
||||
|
||||
fault_injection_env->DropUnsyncedFileData();
|
||||
ASSERT_OK(fault_injection_env->DropUnsyncedFileData());
|
||||
fault_injection_env->SetFilesystemActive(true);
|
||||
Close();
|
||||
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "pikachu", "eevee"},
|
||||
@@ -2847,7 +2804,7 @@ TEST_P(ExternalSSTFileTest, IngestFilesTriggerFlushingWithTwoWriteQueue) {
|
||||
// sure that it won't enter the 2nd writer queue for the second time.
|
||||
std::vector<std::pair<std::string, std::string>> data;
|
||||
data.push_back(std::make_pair("1001", "v2"));
|
||||
GenerateAndAddExternalFile(options, data);
|
||||
ASSERT_OK(GenerateAndAddExternalFile(options, data, -1, true));
|
||||
}
|
||||
|
||||
TEST_P(ExternalSSTFileTest, DeltaEncodingWhileGlobalSeqnoPresent) {
|
||||
|
||||
@@ -192,7 +192,7 @@ class FaultInjectionTest
|
||||
for (int i = start_idx; i < start_idx + num_vals; i++) {
|
||||
Slice key = Key(i, &key_space);
|
||||
batch.Clear();
|
||||
batch.Put(key, Value(i, &value_space));
|
||||
ASSERT_OK(batch.Put(key, Value(i, &value_space)));
|
||||
ASSERT_OK(db_->Write(write_options, &batch));
|
||||
}
|
||||
}
|
||||
@@ -272,12 +272,12 @@ class FaultInjectionTest
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
ASSERT_OK(db_->Delete(WriteOptions(), iter->key()));
|
||||
}
|
||||
|
||||
ASSERT_OK(iter->status());
|
||||
delete iter;
|
||||
|
||||
FlushOptions flush_options;
|
||||
flush_options.wait = true;
|
||||
db_->Flush(flush_options);
|
||||
ASSERT_OK(db_->Flush(flush_options));
|
||||
}
|
||||
|
||||
// rnd cannot be null for kResetDropRandomUnsyncedData
|
||||
@@ -310,7 +310,7 @@ class FaultInjectionTest
|
||||
|
||||
Build(write_options, 0, num_pre_sync);
|
||||
if (sync_use_compact_) {
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
}
|
||||
write_options.sync = false;
|
||||
Build(write_options, num_pre_sync, num_post_sync);
|
||||
@@ -342,7 +342,7 @@ class FaultInjectionTest
|
||||
}
|
||||
|
||||
void WaitCompactionFinish() {
|
||||
static_cast<DBImpl*>(db_->GetRootDB())->TEST_WaitForCompact();
|
||||
ASSERT_OK(static_cast<DBImpl*>(db_->GetRootDB())->TEST_WaitForCompact());
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "", ""));
|
||||
}
|
||||
};
|
||||
@@ -409,7 +409,7 @@ TEST_P(FaultInjectionTest, WriteOptionSyncTest) {
|
||||
write_options.sync = true;
|
||||
ASSERT_OK(
|
||||
db_->Put(write_options, Key(2, &key_space), Value(2, &value_space)));
|
||||
db_->FlushWAL(false);
|
||||
ASSERT_OK(db_->FlushWAL(false));
|
||||
|
||||
env_->SetFilesystemActive(false);
|
||||
NoWriteTestReopenWithFault(kResetDropAndDeleteUnsynced);
|
||||
@@ -450,7 +450,7 @@ TEST_P(FaultInjectionTest, UninstalledCompaction) {
|
||||
Build(WriteOptions(), 0, kNumKeys);
|
||||
FlushOptions flush_options;
|
||||
flush_options.wait = true;
|
||||
db_->Flush(flush_options);
|
||||
ASSERT_OK(db_->Flush(flush_options));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "", ""));
|
||||
TEST_SYNC_POINT("FaultInjectionTest::FaultTest:0");
|
||||
TEST_SYNC_POINT("FaultInjectionTest::FaultTest:1");
|
||||
@@ -521,9 +521,9 @@ TEST_P(FaultInjectionTest, WriteBatchWalTerminationTest) {
|
||||
wo.sync = true;
|
||||
wo.disableWAL = false;
|
||||
WriteBatch batch;
|
||||
batch.Put("cats", "dogs");
|
||||
ASSERT_OK(batch.Put("cats", "dogs"));
|
||||
batch.MarkWalTerminationPoint();
|
||||
batch.Put("boys", "girls");
|
||||
ASSERT_OK(batch.Put("boys", "girls"));
|
||||
ASSERT_OK(db_->Write(wo, &batch));
|
||||
|
||||
env_->SetFilesystemActive(false);
|
||||
|
||||
+15
-9
@@ -32,7 +32,7 @@ class FlushJobTestBase : public testing::Test {
|
||||
protected:
|
||||
FlushJobTestBase(std::string dbname, const Comparator* ucmp)
|
||||
: env_(Env::Default()),
|
||||
fs_(std::make_shared<LegacyFileSystemWrapper>(env_)),
|
||||
fs_(env_->GetFileSystem()),
|
||||
dbname_(std::move(dbname)),
|
||||
ucmp_(ucmp),
|
||||
options_(),
|
||||
@@ -52,7 +52,7 @@ class FlushJobTestBase : public testing::Test {
|
||||
}
|
||||
|
||||
void NewDB() {
|
||||
SetIdentityFile(env_, dbname_);
|
||||
ASSERT_OK(SetIdentityFile(env_, dbname_));
|
||||
VersionEdit new_db;
|
||||
|
||||
new_db.SetLogNumber(0);
|
||||
@@ -85,6 +85,7 @@ class FlushJobTestBase : public testing::Test {
|
||||
std::string record;
|
||||
new_db.EncodeTo(&record);
|
||||
s = log.AddRecord(record);
|
||||
ASSERT_OK(s);
|
||||
|
||||
for (const auto& e : new_cfs) {
|
||||
record.clear();
|
||||
@@ -187,7 +188,8 @@ TEST_F(FlushJobTest, NonEmpty) {
|
||||
for (int i = 1; i < 10000; ++i) {
|
||||
std::string key(ToString((i + 1000) % 10000));
|
||||
std::string value("value" + key);
|
||||
ASSERT_OK(new_mem->Add(SequenceNumber(i), kTypeValue, key, value));
|
||||
ASSERT_OK(new_mem->Add(SequenceNumber(i), kTypeValue, key, value,
|
||||
nullptr /* kv_prot_info */));
|
||||
if ((i + 1000) % 10000 < 9995) {
|
||||
InternalKey internal_key(key, SequenceNumber(i), kTypeValue);
|
||||
inserted_keys.push_back({internal_key.Encode().ToString(), value});
|
||||
@@ -196,7 +198,7 @@ TEST_F(FlushJobTest, NonEmpty) {
|
||||
|
||||
{
|
||||
ASSERT_OK(new_mem->Add(SequenceNumber(10000), kTypeRangeDeletion, "9995",
|
||||
"9999a"));
|
||||
"9999a", nullptr /* kv_prot_info */));
|
||||
InternalKey internal_key("9995", SequenceNumber(10000), kTypeRangeDeletion);
|
||||
inserted_keys.push_back({internal_key.Encode().ToString(), "9999a"});
|
||||
}
|
||||
@@ -223,7 +225,8 @@ TEST_F(FlushJobTest, NonEmpty) {
|
||||
}
|
||||
|
||||
const SequenceNumber seq(i + 10001);
|
||||
ASSERT_OK(new_mem->Add(seq, kTypeBlobIndex, key, blob_index));
|
||||
ASSERT_OK(new_mem->Add(seq, kTypeBlobIndex, key, blob_index,
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
InternalKey internal_key(key, seq, kTypeBlobIndex);
|
||||
inserted_keys.push_back({internal_key.Encode().ToString(), blob_index});
|
||||
@@ -285,7 +288,7 @@ TEST_F(FlushJobTest, FlushMemTablesSingleColumnFamily) {
|
||||
std::string key(ToString(j + i * num_keys_per_table));
|
||||
std::string value("value" + key);
|
||||
ASSERT_OK(mem->Add(SequenceNumber(j + i * num_keys_per_table), kTypeValue,
|
||||
key, value));
|
||||
key, value, nullptr /* kv_prot_info */));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +360,8 @@ TEST_F(FlushJobTest, FlushMemtablesMultipleColumnFamilies) {
|
||||
for (size_t j = 0; j != num_keys_per_memtable; ++j) {
|
||||
std::string key(ToString(j + i * num_keys_per_memtable));
|
||||
std::string value("value" + key);
|
||||
ASSERT_OK(mem->Add(curr_seqno++, kTypeValue, key, value));
|
||||
ASSERT_OK(mem->Add(curr_seqno++, kTypeValue, key, value,
|
||||
nullptr /* kv_prot_info */));
|
||||
}
|
||||
|
||||
cfd->imm()->Add(mem, &to_delete);
|
||||
@@ -468,7 +472,8 @@ TEST_F(FlushJobTest, Snapshots) {
|
||||
for (int j = 0; j < insertions; ++j) {
|
||||
std::string value(rnd.HumanReadableString(10));
|
||||
auto seqno = ++current_seqno;
|
||||
ASSERT_OK(new_mem->Add(SequenceNumber(seqno), kTypeValue, key, value));
|
||||
ASSERT_OK(new_mem->Add(SequenceNumber(seqno), kTypeValue, key, value,
|
||||
nullptr /* kv_prot_info */));
|
||||
// a key is visible only if:
|
||||
// 1. it's the last one written (j == insertions - 1)
|
||||
// 2. there's a snapshot pointing at it
|
||||
@@ -520,7 +525,8 @@ class FlushJobTimestampTest : public FlushJobTestBase {
|
||||
Slice value) {
|
||||
std::string key_str(std::move(key));
|
||||
PutFixed64(&key_str, ts);
|
||||
ASSERT_OK(memtable->Add(seq, value_type, key_str, value));
|
||||
ASSERT_OK(memtable->Add(seq, value_type, key_str, value,
|
||||
nullptr /* kv_prot_info */));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -47,11 +47,7 @@ class ForwardLevelIterator : public InternalIterator {
|
||||
pinned_iters_mgr_(nullptr),
|
||||
prefix_extractor_(prefix_extractor),
|
||||
allow_unprepared_value_(allow_unprepared_value) {
|
||||
/*
|
||||
NOTE needed for ASSERT_STATUS_CHECKED
|
||||
in MergeOperatorPinningTest/MergeOperatorPinningTest.TailingIterator
|
||||
*/
|
||||
status_.PermitUncheckedError();
|
||||
status_.PermitUncheckedError(); // Allow uninitialized status through
|
||||
}
|
||||
|
||||
~ForwardLevelIterator() override {
|
||||
@@ -244,6 +240,12 @@ ForwardIterator::ForwardIterator(DBImpl* db, const ReadOptions& read_options,
|
||||
if (sv_) {
|
||||
RebuildIterators(false);
|
||||
}
|
||||
|
||||
// immutable_status_ is a local aggregation of the
|
||||
// status of the immutable Iterators.
|
||||
// We have to PermitUncheckedError in case it is never
|
||||
// used, otherwise it will fail ASSERT_STATUS_CHECKED.
|
||||
immutable_status_.PermitUncheckedError();
|
||||
}
|
||||
|
||||
ForwardIterator::~ForwardIterator() {
|
||||
|
||||
@@ -104,9 +104,9 @@ TEST_F(ImportColumnFamilyTest, ImportSSTFileWriterFiles) {
|
||||
ASSERT_NE(import_cfh_, nullptr);
|
||||
|
||||
std::string value;
|
||||
db_->Get(ReadOptions(), import_cfh_, "K1", &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, "K1", &value));
|
||||
ASSERT_EQ(value, "V1");
|
||||
db_->Get(ReadOptions(), import_cfh_, "K2", &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, "K2", &value));
|
||||
ASSERT_EQ(value, "V2");
|
||||
ASSERT_OK(db_->DropColumnFamily(import_cfh_));
|
||||
ASSERT_OK(db_->DestroyColumnFamilyHandle(import_cfh_));
|
||||
@@ -125,9 +125,9 @@ TEST_F(ImportColumnFamilyTest, ImportSSTFileWriterFiles) {
|
||||
ASSERT_NE(import_cfh_, nullptr);
|
||||
|
||||
std::string value;
|
||||
db_->Get(ReadOptions(), import_cfh_, "K3", &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, "K3", &value));
|
||||
ASSERT_EQ(value, "V1");
|
||||
db_->Get(ReadOptions(), import_cfh_, "K4", &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, "K4", &value));
|
||||
ASSERT_EQ(value, "V2");
|
||||
}
|
||||
}
|
||||
@@ -214,7 +214,7 @@ TEST_F(ImportColumnFamilyTest, ImportSSTFileWriterFilesWithOverlap) {
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string value;
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value));
|
||||
if (i % 16 == 0) {
|
||||
ASSERT_EQ(value, Key(i) + "_overwrite4");
|
||||
} else if (i % 4 == 0) {
|
||||
@@ -235,7 +235,7 @@ TEST_F(ImportColumnFamilyTest, ImportSSTFileWriterFilesWithOverlap) {
|
||||
ASSERT_OK(db_->Flush(FlushOptions(), import_cfh_));
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string value;
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value));
|
||||
if (i % 5 == 0) {
|
||||
ASSERT_EQ(value, Key(i) + "_overwrite5");
|
||||
} else if (i % 16 == 0) {
|
||||
@@ -254,7 +254,7 @@ TEST_F(ImportColumnFamilyTest, ImportSSTFileWriterFilesWithOverlap) {
|
||||
db_->CompactRange(CompactRangeOptions(), import_cfh_, nullptr, nullptr));
|
||||
for (int i = 0; i < 100; i++) {
|
||||
std::string value;
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value));
|
||||
if (i % 5 == 0) {
|
||||
ASSERT_EQ(value, Key(i) + "_overwrite5");
|
||||
} else if (i % 16 == 0) {
|
||||
@@ -318,12 +318,12 @@ TEST_F(ImportColumnFamilyTest, ImportExportedSSTFromAnotherCF) {
|
||||
std::string value1, value2;
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value1));
|
||||
ASSERT_EQ(Get(1, Key(i)), value1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh2_, Key(i), &value2);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh2_, Key(i), &value2));
|
||||
ASSERT_EQ(Get(1, Key(i)), value2);
|
||||
}
|
||||
|
||||
@@ -340,16 +340,16 @@ TEST_F(ImportColumnFamilyTest, ImportExportedSSTFromAnotherCF) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1).IsNotFound());
|
||||
}
|
||||
for (int i = 25; i < 50; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value1));
|
||||
ASSERT_EQ(Key(i) + "_overwrite3", value1);
|
||||
}
|
||||
for (int i = 50; i < 100; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value1));
|
||||
ASSERT_EQ(Key(i) + "_overwrite2", value1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh2_, Key(i), &value2);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh2_, Key(i), &value2));
|
||||
ASSERT_EQ(Get(1, Key(i)), value2);
|
||||
}
|
||||
|
||||
@@ -363,16 +363,16 @@ TEST_F(ImportColumnFamilyTest, ImportExportedSSTFromAnotherCF) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1).IsNotFound());
|
||||
}
|
||||
for (int i = 25; i < 50; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value1));
|
||||
ASSERT_EQ(Key(i) + "_overwrite3", value1);
|
||||
}
|
||||
for (int i = 50; i < 100; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh_, Key(i), &value1);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh_, Key(i), &value1));
|
||||
ASSERT_EQ(Key(i) + "_overwrite2", value1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
db_->Get(ReadOptions(), import_cfh2_, Key(i), &value2);
|
||||
ASSERT_OK(db_->Get(ReadOptions(), import_cfh2_, Key(i), &value2));
|
||||
ASSERT_EQ(Get(1, Key(i)), value2);
|
||||
}
|
||||
}
|
||||
@@ -424,7 +424,7 @@ TEST_F(ImportColumnFamilyTest, ImportExportedSSTFromAnotherDB) {
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
std::string value;
|
||||
db_copy->Get(ReadOptions(), cfh, Key(i), &value);
|
||||
ASSERT_OK(db_copy->Get(ReadOptions(), cfh, Key(i), &value));
|
||||
ASSERT_EQ(Get(1, Key(i)), value);
|
||||
}
|
||||
ASSERT_OK(db_copy->DropColumnFamily(cfh));
|
||||
|
||||
@@ -0,0 +1,424 @@
|
||||
// Copyright (c) 2020-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// This file contains classes containing fields to protect individual entries.
|
||||
// The classes are named "ProtectionInfo<suffix>", where <suffix> indicates the
|
||||
// combination of fields that are covered. Each field has a single letter
|
||||
// abbreviation as follows.
|
||||
//
|
||||
// K = key
|
||||
// V = value
|
||||
// O = optype aka value type
|
||||
// T = timestamp
|
||||
// S = seqno
|
||||
// C = CF ID
|
||||
//
|
||||
// Then, for example, a class that protects an entry consisting of key, value,
|
||||
// optype, timestamp, and CF ID (i.e., a `WriteBatch` entry) would be named
|
||||
// `ProtectionInfoKVOTC`.
|
||||
//
|
||||
// The `ProtectionInfo.*` classes are templated on the integer type used to hold
|
||||
// the XOR of hashes for each field. Only unsigned integer types are supported,
|
||||
// and the maximum supported integer width is 64 bits. When the integer type is
|
||||
// narrower than the hash values, we lop off the most significant bits to make
|
||||
// them fit.
|
||||
//
|
||||
// The `ProtectionInfo.*` classes are all intended to be non-persistent. We do
|
||||
// not currently make the byte order consistent for integer fields before
|
||||
// hashing them, so the resulting values are endianness-dependent.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "db/dbformat.h"
|
||||
#include "rocksdb/types.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfo;
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOT;
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOTC;
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOTS;
|
||||
|
||||
// Aliases for 64-bit protection infos.
|
||||
typedef ProtectionInfo<uint64_t> ProtectionInfo64;
|
||||
typedef ProtectionInfoKVOT<uint64_t> ProtectionInfoKVOT64;
|
||||
typedef ProtectionInfoKVOTC<uint64_t> ProtectionInfoKVOTC64;
|
||||
typedef ProtectionInfoKVOTS<uint64_t> ProtectionInfoKVOTS64;
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfo {
|
||||
public:
|
||||
ProtectionInfo<T>() = default;
|
||||
|
||||
Status GetStatus() const;
|
||||
ProtectionInfoKVOT<T> ProtectKVOT(const Slice& key, const Slice& value,
|
||||
ValueType op_type,
|
||||
const Slice& timestamp) const;
|
||||
ProtectionInfoKVOT<T> ProtectKVOT(const SliceParts& key,
|
||||
const SliceParts& value, ValueType op_type,
|
||||
const Slice& timestamp) const;
|
||||
|
||||
private:
|
||||
friend class ProtectionInfoKVOT<T>;
|
||||
friend class ProtectionInfoKVOTS<T>;
|
||||
friend class ProtectionInfoKVOTC<T>;
|
||||
|
||||
// Each field is hashed with an independent value so we can catch fields being
|
||||
// swapped. Per the `NPHash64()` docs, using consecutive seeds is a pitfall,
|
||||
// and we should instead vary our seeds by a large odd number. This value by
|
||||
// which we increment (0xD28AAD72F49BD50B) was taken from
|
||||
// `head -c8 /dev/urandom | hexdump`, run repeatedly until it yielded an odd
|
||||
// number. The values are computed manually since the Windows C++ compiler
|
||||
// complains about the overflow when adding constants.
|
||||
static const uint64_t kSeedK = 0;
|
||||
static const uint64_t kSeedV = 0xD28AAD72F49BD50B;
|
||||
static const uint64_t kSeedO = 0xA5155AE5E937AA16;
|
||||
static const uint64_t kSeedT = 0x77A00858DDD37F21;
|
||||
static const uint64_t kSeedS = 0x4A2AB5CBD26F542C;
|
||||
static const uint64_t kSeedC = 0x1CB5633EC70B2937;
|
||||
|
||||
ProtectionInfo<T>(T val) : val_(val) {
|
||||
static_assert(sizeof(ProtectionInfo<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return val_; }
|
||||
void SetVal(T val) { val_ = val; }
|
||||
|
||||
T val_ = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOT {
|
||||
public:
|
||||
ProtectionInfoKVOT<T>() = default;
|
||||
|
||||
ProtectionInfo<T> StripKVOT(const Slice& key, const Slice& value,
|
||||
ValueType op_type, const Slice& timestamp) const;
|
||||
ProtectionInfo<T> StripKVOT(const SliceParts& key, const SliceParts& value,
|
||||
ValueType op_type, const Slice& timestamp) const;
|
||||
|
||||
ProtectionInfoKVOTC<T> ProtectC(ColumnFamilyId column_family_id) const;
|
||||
ProtectionInfoKVOTS<T> ProtectS(SequenceNumber sequence_number) const;
|
||||
|
||||
void UpdateK(const Slice& old_key, const Slice& new_key);
|
||||
void UpdateK(const SliceParts& old_key, const SliceParts& new_key);
|
||||
void UpdateV(const Slice& old_value, const Slice& new_value);
|
||||
void UpdateV(const SliceParts& old_value, const SliceParts& new_value);
|
||||
void UpdateO(ValueType old_op_type, ValueType new_op_type);
|
||||
void UpdateT(const Slice& old_timestamp, const Slice& new_timestamp);
|
||||
|
||||
private:
|
||||
friend class ProtectionInfo<T>;
|
||||
friend class ProtectionInfoKVOTS<T>;
|
||||
friend class ProtectionInfoKVOTC<T>;
|
||||
|
||||
ProtectionInfoKVOT<T>(T val) : info_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOT<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return info_.GetVal(); }
|
||||
void SetVal(T val) { info_.SetVal(val); }
|
||||
|
||||
ProtectionInfo<T> info_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOTC {
|
||||
public:
|
||||
ProtectionInfoKVOTC<T>() = default;
|
||||
|
||||
ProtectionInfoKVOT<T> StripC(ColumnFamilyId column_family_id) const;
|
||||
|
||||
void UpdateK(const Slice& old_key, const Slice& new_key) {
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateV(const Slice& old_value, const Slice& new_value) {
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateO(ValueType old_op_type, ValueType new_op_type) {
|
||||
kvot_.UpdateO(old_op_type, new_op_type);
|
||||
}
|
||||
void UpdateT(const Slice& old_timestamp, const Slice& new_timestamp) {
|
||||
kvot_.UpdateT(old_timestamp, new_timestamp);
|
||||
}
|
||||
void UpdateC(ColumnFamilyId old_column_family_id,
|
||||
ColumnFamilyId new_column_family_id);
|
||||
|
||||
private:
|
||||
friend class ProtectionInfoKVOT<T>;
|
||||
|
||||
ProtectionInfoKVOTC<T>(T val) : kvot_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOTC<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return kvot_.GetVal(); }
|
||||
void SetVal(T val) { kvot_.SetVal(val); }
|
||||
|
||||
ProtectionInfoKVOT<T> kvot_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOTS {
|
||||
public:
|
||||
ProtectionInfoKVOTS<T>() = default;
|
||||
|
||||
ProtectionInfoKVOT<T> StripS(SequenceNumber sequence_number) const;
|
||||
|
||||
void UpdateK(const Slice& old_key, const Slice& new_key) {
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateV(const Slice& old_value, const Slice& new_value) {
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateO(ValueType old_op_type, ValueType new_op_type) {
|
||||
kvot_.UpdateO(old_op_type, new_op_type);
|
||||
}
|
||||
void UpdateT(const Slice& old_timestamp, const Slice& new_timestamp) {
|
||||
kvot_.UpdateT(old_timestamp, new_timestamp);
|
||||
}
|
||||
void UpdateS(SequenceNumber old_sequence_number,
|
||||
SequenceNumber new_sequence_number);
|
||||
|
||||
private:
|
||||
friend class ProtectionInfoKVOT<T>;
|
||||
|
||||
ProtectionInfoKVOTS<T>(T val) : kvot_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOTS<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return kvot_.GetVal(); }
|
||||
void SetVal(T val) { kvot_.SetVal(val); }
|
||||
|
||||
ProtectionInfoKVOT<T> kvot_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Status ProtectionInfo<T>::GetStatus() const {
|
||||
if (val_ != 0) {
|
||||
return Status::Corruption("ProtectionInfo mismatch");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOT<T> ProtectionInfo<T>::ProtectKVOT(
|
||||
const Slice& key, const Slice& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
val =
|
||||
val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOT<T> ProtectionInfo<T>::ProtectKVOT(
|
||||
const SliceParts& key, const SliceParts& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
val = val ^
|
||||
static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOT<T>::UpdateK(const Slice& old_key,
|
||||
const Slice& new_key) {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(old_key, ProtectionInfo<T>::kSeedK));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(new_key, ProtectionInfo<T>::kSeedK));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOT<T>::UpdateK(const SliceParts& old_key,
|
||||
const SliceParts& new_key) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(
|
||||
GetSlicePartsNPHash64(old_key, ProtectionInfo<T>::kSeedK));
|
||||
val = val ^ static_cast<T>(
|
||||
GetSlicePartsNPHash64(new_key, ProtectionInfo<T>::kSeedK));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOT<T>::UpdateV(const Slice& old_value,
|
||||
const Slice& new_value) {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(old_value, ProtectionInfo<T>::kSeedV));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(new_value, ProtectionInfo<T>::kSeedV));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOT<T>::UpdateV(const SliceParts& old_value,
|
||||
const SliceParts& new_value) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(
|
||||
GetSlicePartsNPHash64(old_value, ProtectionInfo<T>::kSeedV));
|
||||
val = val ^ static_cast<T>(
|
||||
GetSlicePartsNPHash64(new_value, ProtectionInfo<T>::kSeedV));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOT<T>::UpdateO(ValueType old_op_type,
|
||||
ValueType new_op_type) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&old_op_type),
|
||||
sizeof(old_op_type),
|
||||
ProtectionInfo<T>::kSeedO));
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&new_op_type),
|
||||
sizeof(new_op_type),
|
||||
ProtectionInfo<T>::kSeedO));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOT<T>::UpdateT(const Slice& old_timestamp,
|
||||
const Slice& new_timestamp) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(
|
||||
GetSliceNPHash64(old_timestamp, ProtectionInfo<T>::kSeedT));
|
||||
val = val ^ static_cast<T>(
|
||||
GetSliceNPHash64(new_timestamp, ProtectionInfo<T>::kSeedT));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfo<T> ProtectionInfoKVOT<T>::StripKVOT(
|
||||
const Slice& key, const Slice& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
val =
|
||||
val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfo<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfo<T> ProtectionInfoKVOT<T>::StripKVOT(
|
||||
const SliceParts& key, const SliceParts& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
val = val ^
|
||||
static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfo<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOTC<T> ProtectionInfoKVOT<T>::ProtectC(
|
||||
ColumnFamilyId column_family_id) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&column_family_id),
|
||||
sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
|
||||
return ProtectionInfoKVOTC<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOT<T> ProtectionInfoKVOTC<T>::StripC(
|
||||
ColumnFamilyId column_family_id) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&column_family_id),
|
||||
sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOTC<T>::UpdateC(ColumnFamilyId old_column_family_id,
|
||||
ColumnFamilyId new_column_family_id) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&old_column_family_id),
|
||||
sizeof(old_column_family_id), ProtectionInfo<T>::kSeedC));
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&new_column_family_id),
|
||||
sizeof(new_column_family_id), ProtectionInfo<T>::kSeedC));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOTS<T> ProtectionInfoKVOT<T>::ProtectS(
|
||||
SequenceNumber sequence_number) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
|
||||
sizeof(sequence_number),
|
||||
ProtectionInfo<T>::kSeedS));
|
||||
return ProtectionInfoKVOTS<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOT<T> ProtectionInfoKVOTS<T>::StripS(
|
||||
SequenceNumber sequence_number) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
|
||||
sizeof(sequence_number),
|
||||
ProtectionInfo<T>::kSeedS));
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOTS<T>::UpdateS(SequenceNumber old_sequence_number,
|
||||
SequenceNumber new_sequence_number) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&old_sequence_number),
|
||||
sizeof(old_sequence_number), ProtectionInfo<T>::kSeedS));
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&new_sequence_number),
|
||||
sizeof(new_sequence_number), ProtectionInfo<T>::kSeedS));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+30
-23
@@ -192,10 +192,10 @@ TEST_F(EventListenerTest, OnSingleDBCompactionTest) {
|
||||
ASSERT_OK(Put(7, "popovich", std::string(90000, 'p')));
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
ASSERT_OK(Flush(i));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), handles_[i],
|
||||
nullptr, nullptr));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
|
||||
ASSERT_EQ(listener->compacted_dbs_.size(), cf_names.size());
|
||||
@@ -211,6 +211,10 @@ class TestFlushListener : public EventListener {
|
||||
: slowdown_count(0), stop_count(0), db_closed(), env_(env), test_(test) {
|
||||
db_closed = false;
|
||||
}
|
||||
|
||||
virtual ~TestFlushListener() {
|
||||
prev_fc_info_.status.PermitUncheckedError(); // Ignore the status
|
||||
}
|
||||
void OnTableFileCreated(
|
||||
const TableFileCreationInfo& info) override {
|
||||
// remember the info for later checking the FlushJobInfo.
|
||||
@@ -333,7 +337,7 @@ TEST_F(EventListenerTest, OnSingleDBFlushTest) {
|
||||
ASSERT_OK(Put(7, "popovich", std::string(90000, 'p')));
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
ASSERT_OK(Flush(i));
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ(listener->flushed_dbs_.size(), i);
|
||||
ASSERT_EQ(listener->flushed_column_family_names_.size(), i);
|
||||
}
|
||||
@@ -417,7 +421,7 @@ TEST_F(EventListenerTest, MultiDBMultiListeners) {
|
||||
ASSERT_OK(DB::Open(options, dbname_ + ToString(d), &db));
|
||||
for (size_t c = 0; c < cf_names.size(); ++c) {
|
||||
ColumnFamilyHandle* handle;
|
||||
db->CreateColumnFamily(cf_opts, cf_names[c], &handle);
|
||||
ASSERT_OK(db->CreateColumnFamily(cf_opts, cf_names[c], &handle));
|
||||
handles.push_back(handle);
|
||||
}
|
||||
|
||||
@@ -435,7 +439,8 @@ TEST_F(EventListenerTest, MultiDBMultiListeners) {
|
||||
for (size_t c = 0; c < cf_names.size(); ++c) {
|
||||
for (int d = 0; d < kNumDBs; ++d) {
|
||||
ASSERT_OK(dbs[d]->Flush(FlushOptions(), vec_handles[d][c]));
|
||||
static_cast_with_check<DBImpl>(dbs[d])->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(
|
||||
static_cast_with_check<DBImpl>(dbs[d])->TEST_WaitForFlushMemTable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,10 +499,10 @@ TEST_F(EventListenerTest, DisableBGCompaction) {
|
||||
// keep writing until writes are forced to stop.
|
||||
for (int i = 0; static_cast<int>(cf_meta.file_count) < kSlowdownTrigger * 10;
|
||||
++i) {
|
||||
Put(1, ToString(i), std::string(10000, 'x'), WriteOptions());
|
||||
ASSERT_OK(Put(1, ToString(i), std::string(10000, 'x'), WriteOptions()));
|
||||
FlushOptions fo;
|
||||
fo.allow_write_stall = true;
|
||||
db_->Flush(fo, handles_[1]);
|
||||
ASSERT_OK(db_->Flush(fo, handles_[1]));
|
||||
db_->GetColumnFamilyMetaData(handles_[1], &cf_meta);
|
||||
}
|
||||
ASSERT_GE(listener->slowdown_count, kSlowdownTrigger * 9);
|
||||
@@ -534,7 +539,7 @@ TEST_F(EventListenerTest, CompactionReasonLevel) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GenerateNewRandomFile(&rnd);
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_EQ(listener->compaction_reasons_.size(), 1);
|
||||
ASSERT_EQ(listener->compaction_reasons_[0],
|
||||
@@ -551,14 +556,14 @@ TEST_F(EventListenerTest, CompactionReasonLevel) {
|
||||
}
|
||||
|
||||
// Do a trivial move from L0 -> L1
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
options.max_bytes_for_level_base = 1;
|
||||
Close();
|
||||
listener->compaction_reasons_.clear();
|
||||
Reopen(options);
|
||||
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_GT(listener->compaction_reasons_.size(), 1);
|
||||
|
||||
for (auto compaction_reason : listener->compaction_reasons_) {
|
||||
@@ -570,7 +575,7 @@ TEST_F(EventListenerTest, CompactionReasonLevel) {
|
||||
listener->compaction_reasons_.clear();
|
||||
Reopen(options);
|
||||
|
||||
Put("key", "value");
|
||||
ASSERT_OK(Put("key", "value"));
|
||||
CompactRangeOptions cro;
|
||||
cro.bottommost_level_compaction = BottommostLevelCompaction::kForceOptimized;
|
||||
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
||||
@@ -604,7 +609,7 @@ TEST_F(EventListenerTest, CompactionReasonUniversal) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
GenerateNewRandomFile(&rnd);
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_GT(listener->compaction_reasons_.size(), 0);
|
||||
for (auto compaction_reason : listener->compaction_reasons_) {
|
||||
@@ -622,7 +627,7 @@ TEST_F(EventListenerTest, CompactionReasonUniversal) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
GenerateNewRandomFile(&rnd);
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_GT(listener->compaction_reasons_.size(), 0);
|
||||
for (auto compaction_reason : listener->compaction_reasons_) {
|
||||
@@ -634,7 +639,7 @@ TEST_F(EventListenerTest, CompactionReasonUniversal) {
|
||||
listener->compaction_reasons_.clear();
|
||||
Reopen(options);
|
||||
|
||||
db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
ASSERT_GT(listener->compaction_reasons_.size(), 0);
|
||||
for (auto compaction_reason : listener->compaction_reasons_) {
|
||||
@@ -663,7 +668,7 @@ TEST_F(EventListenerTest, CompactionReasonFIFO) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GenerateNewRandomFile(&rnd);
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_GT(listener->compaction_reasons_.size(), 0);
|
||||
for (auto compaction_reason : listener->compaction_reasons_) {
|
||||
@@ -783,7 +788,7 @@ TEST_F(EventListenerTest, TableFileCreationListenersTest) {
|
||||
ASSERT_OK(Put("foo", "aaa"));
|
||||
ASSERT_OK(Put("bar", "bbb"));
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
listener->CheckAndResetCounters(1, 1, 0, 0, 0, 0);
|
||||
ASSERT_OK(Put("foo", "aaa1"));
|
||||
ASSERT_OK(Put("bar", "bbb1"));
|
||||
@@ -796,21 +801,23 @@ TEST_F(EventListenerTest, TableFileCreationListenersTest) {
|
||||
ASSERT_OK(Put("foo", "aaa2"));
|
||||
ASSERT_OK(Put("bar", "bbb2"));
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
listener->CheckAndResetCounters(1, 1, 0, 0, 0, 0);
|
||||
|
||||
const Slice kRangeStart = "a";
|
||||
const Slice kRangeEnd = "z";
|
||||
dbfull()->CompactRange(CompactRangeOptions(), &kRangeStart, &kRangeEnd);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(
|
||||
dbfull()->CompactRange(CompactRangeOptions(), &kRangeStart, &kRangeEnd));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
listener->CheckAndResetCounters(0, 0, 0, 1, 1, 0);
|
||||
|
||||
ASSERT_OK(Put("foo", "aaa3"));
|
||||
ASSERT_OK(Put("bar", "bbb3"));
|
||||
ASSERT_OK(Flush());
|
||||
test_env->SetStatus(Status::NotSupported("not supported"));
|
||||
dbfull()->CompactRange(CompactRangeOptions(), &kRangeStart, &kRangeEnd);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_NOK(
|
||||
dbfull()->CompactRange(CompactRangeOptions(), &kRangeStart, &kRangeEnd));
|
||||
ASSERT_NOK(dbfull()->TEST_WaitForCompact());
|
||||
listener->CheckAndResetCounters(1, 1, 0, 1, 1, 1);
|
||||
Close();
|
||||
}
|
||||
@@ -1076,8 +1083,8 @@ TEST_F(EventListenerTest, OnFileOperationTest) {
|
||||
}
|
||||
DestroyAndReopen(options);
|
||||
ASSERT_OK(Put("foo", "aaa"));
|
||||
dbfull()->Flush(FlushOptions());
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
ASSERT_OK(dbfull()->Flush(FlushOptions()));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_GE(listener->file_writes_.load(),
|
||||
listener->file_writes_success_.load());
|
||||
ASSERT_GT(listener->file_writes_.load(), 0);
|
||||
|
||||
+68
-93
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "db/log_reader.h"
|
||||
#include "db/log_writer.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/sequence_file_reader.h"
|
||||
#include "file/writable_file_writer.h"
|
||||
#include "rocksdb/env.h"
|
||||
@@ -50,7 +49,7 @@ static std::string RandomSkewedString(int i, Random* rnd) {
|
||||
// get<1>(tuple): true if allow retry after read EOF, false otherwise
|
||||
class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
private:
|
||||
class StringSource : public SequentialFile {
|
||||
class StringSource : public FSSequentialFile {
|
||||
public:
|
||||
Slice& contents_;
|
||||
bool force_error_;
|
||||
@@ -68,7 +67,8 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
returned_partial_(false),
|
||||
fail_after_read_partial_(fail_after_read_partial) {}
|
||||
|
||||
Status Read(size_t n, Slice* result, char* scratch) override {
|
||||
IOStatus Read(size_t n, const IOOptions& /*opts*/, Slice* result,
|
||||
char* scratch, IODebugContext* /*dbg*/) override {
|
||||
if (fail_after_read_partial_) {
|
||||
EXPECT_TRUE(!returned_partial_) << "must not Read() after eof/error";
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
contents_.remove_prefix(force_error_position_);
|
||||
force_error_ = false;
|
||||
returned_partial_ = true;
|
||||
return Status::Corruption("read error");
|
||||
return IOStatus::Corruption("read error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,28 +106,21 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
*result = Slice(scratch, n);
|
||||
|
||||
contents_.remove_prefix(n);
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
|
||||
Status Skip(uint64_t n) override {
|
||||
IOStatus Skip(uint64_t n) override {
|
||||
if (n > contents_.size()) {
|
||||
contents_.clear();
|
||||
return Status::NotFound("in-memory file skipepd past end");
|
||||
return IOStatus::NotFound("in-memory file skipepd past end");
|
||||
}
|
||||
|
||||
contents_.remove_prefix(n);
|
||||
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
};
|
||||
|
||||
inline StringSource* GetStringSourceFromLegacyReader(
|
||||
SequentialFileReader* reader) {
|
||||
LegacySequentialFileWrapper* file =
|
||||
static_cast<LegacySequentialFileWrapper*>(reader->file());
|
||||
return static_cast<StringSource*>(file->target());
|
||||
}
|
||||
|
||||
class ReportCollector : public Reader::Reporter {
|
||||
public:
|
||||
size_t dropped_bytes_;
|
||||
@@ -140,29 +133,17 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
}
|
||||
};
|
||||
|
||||
std::string& dest_contents() {
|
||||
auto dest = test::GetStringSinkFromLegacyWriter(writer_.file());
|
||||
assert(dest);
|
||||
return dest->contents_;
|
||||
}
|
||||
std::string& dest_contents() { return sink_->contents_; }
|
||||
|
||||
const std::string& dest_contents() const {
|
||||
auto dest = test::GetStringSinkFromLegacyWriter(writer_.file());
|
||||
assert(dest);
|
||||
return dest->contents_;
|
||||
}
|
||||
const std::string& dest_contents() const { return sink_->contents_; }
|
||||
|
||||
void reset_source_contents() {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
assert(src);
|
||||
src->contents_ = dest_contents();
|
||||
}
|
||||
void reset_source_contents() { source_->contents_ = dest_contents(); }
|
||||
|
||||
Slice reader_contents_;
|
||||
std::unique_ptr<WritableFileWriter> dest_holder_;
|
||||
std::unique_ptr<SequentialFileReader> source_holder_;
|
||||
test::StringSink* sink_;
|
||||
StringSource* source_;
|
||||
ReportCollector report_;
|
||||
Writer writer_;
|
||||
std::unique_ptr<Writer> writer_;
|
||||
std::unique_ptr<Reader> reader_;
|
||||
|
||||
protected:
|
||||
@@ -171,19 +152,23 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
public:
|
||||
LogTest()
|
||||
: reader_contents_(),
|
||||
dest_holder_(test::GetWritableFileWriter(
|
||||
new test::StringSink(&reader_contents_), "" /* don't care */)),
|
||||
source_holder_(test::GetSequentialFileReader(
|
||||
new StringSource(reader_contents_, !std::get<1>(GetParam())),
|
||||
"" /* file name */)),
|
||||
writer_(std::move(dest_holder_), 123, std::get<0>(GetParam())),
|
||||
sink_(new test::StringSink(&reader_contents_)),
|
||||
source_(new StringSource(reader_contents_, !std::get<1>(GetParam()))),
|
||||
allow_retry_read_(std::get<1>(GetParam())) {
|
||||
std::unique_ptr<FSWritableFile> sink_holder(sink_);
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(sink_holder), "" /* don't care */, FileOptions()));
|
||||
writer_.reset(
|
||||
new Writer(std::move(file_writer), 123, std::get<0>(GetParam())));
|
||||
std::unique_ptr<FSSequentialFile> source_holder(source_);
|
||||
std::unique_ptr<SequentialFileReader> file_reader(
|
||||
new SequentialFileReader(std::move(source_holder), "" /* file name */));
|
||||
if (allow_retry_read_) {
|
||||
reader_.reset(new FragmentBufferedReader(
|
||||
nullptr, std::move(source_holder_), &report_, true /* checksum */,
|
||||
123 /* log_number */));
|
||||
reader_.reset(new FragmentBufferedReader(nullptr, std::move(file_reader),
|
||||
&report_, true /* checksum */,
|
||||
123 /* log_number */));
|
||||
} else {
|
||||
reader_.reset(new Reader(nullptr, std::move(source_holder_), &report_,
|
||||
reader_.reset(new Reader(nullptr, std::move(file_reader), &report_,
|
||||
true /* checksum */, 123 /* log_number */));
|
||||
}
|
||||
}
|
||||
@@ -191,7 +176,7 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
Slice* get_reader_contents() { return &reader_contents_; }
|
||||
|
||||
void Write(const std::string& msg) {
|
||||
writer_.AddRecord(Slice(msg));
|
||||
ASSERT_OK(writer_->AddRecord(Slice(msg)));
|
||||
}
|
||||
|
||||
size_t WrittenBytes() const {
|
||||
@@ -219,11 +204,7 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
dest_contents()[offset] = new_byte;
|
||||
}
|
||||
|
||||
void ShrinkSize(int bytes) {
|
||||
auto dest = test::GetStringSinkFromLegacyWriter(writer_.file());
|
||||
assert(dest);
|
||||
dest->Drop(bytes);
|
||||
}
|
||||
void ShrinkSize(int bytes) { sink_->Drop(bytes); }
|
||||
|
||||
void FixChecksum(int header_offset, int len, bool recyclable) {
|
||||
// Compute crc of type/len/data
|
||||
@@ -235,9 +216,8 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
}
|
||||
|
||||
void ForceError(size_t position = 0) {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
src->force_error_ = true;
|
||||
src->force_error_position_ = position;
|
||||
source_->force_error_ = true;
|
||||
source_->force_error_position_ = position;
|
||||
}
|
||||
|
||||
size_t DroppedBytes() const {
|
||||
@@ -249,14 +229,12 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
}
|
||||
|
||||
void ForceEOF(size_t position = 0) {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
src->force_eof_ = true;
|
||||
src->force_eof_position_ = position;
|
||||
source_->force_eof_ = true;
|
||||
source_->force_eof_position_ = position;
|
||||
}
|
||||
|
||||
void UnmarkEOF() {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
src->returned_partial_ = false;
|
||||
source_->returned_partial_ = false;
|
||||
reader_->UnmarkEOF();
|
||||
}
|
||||
|
||||
@@ -685,12 +663,13 @@ TEST_P(LogTest, Recycle) {
|
||||
while (get_reader_contents()->size() < log::kBlockSize * 2) {
|
||||
Write("xxxxxxxxxxxxxxxx");
|
||||
}
|
||||
std::unique_ptr<WritableFileWriter> dest_holder(test::GetWritableFileWriter(
|
||||
new test::OverwritingStringSink(get_reader_contents()),
|
||||
"" /* don't care */));
|
||||
std::unique_ptr<FSWritableFile> sink(
|
||||
new test::OverwritingStringSink(get_reader_contents()));
|
||||
std::unique_ptr<WritableFileWriter> dest_holder(new WritableFileWriter(
|
||||
std::move(sink), "" /* don't care */, FileOptions()));
|
||||
Writer recycle_writer(std::move(dest_holder), 123, true);
|
||||
recycle_writer.AddRecord(Slice("foooo"));
|
||||
recycle_writer.AddRecord(Slice("bar"));
|
||||
ASSERT_OK(recycle_writer.AddRecord(Slice("foooo")));
|
||||
ASSERT_OK(recycle_writer.AddRecord(Slice("bar")));
|
||||
ASSERT_GE(get_reader_contents()->size(), log::kBlockSize * 2);
|
||||
ASSERT_EQ("foooo", Read());
|
||||
ASSERT_EQ("bar", Read());
|
||||
@@ -718,10 +697,9 @@ class RetriableLogTest : public ::testing::TestWithParam<int> {
|
||||
};
|
||||
|
||||
Slice contents_;
|
||||
std::unique_ptr<WritableFileWriter> dest_holder_;
|
||||
test::StringSink* sink_;
|
||||
std::unique_ptr<Writer> log_writer_;
|
||||
Env* env_;
|
||||
EnvOptions env_options_;
|
||||
const std::string test_dir_;
|
||||
const std::string log_file_;
|
||||
std::unique_ptr<WritableFileWriter> writer_;
|
||||
@@ -732,61 +710,58 @@ class RetriableLogTest : public ::testing::TestWithParam<int> {
|
||||
public:
|
||||
RetriableLogTest()
|
||||
: contents_(),
|
||||
dest_holder_(nullptr),
|
||||
sink_(new test::StringSink(&contents_)),
|
||||
log_writer_(nullptr),
|
||||
env_(Env::Default()),
|
||||
test_dir_(test::PerThreadDBPath("retriable_log_test")),
|
||||
log_file_(test_dir_ + "/log"),
|
||||
writer_(nullptr),
|
||||
reader_(nullptr),
|
||||
log_reader_(nullptr) {}
|
||||
log_reader_(nullptr) {
|
||||
std::unique_ptr<FSWritableFile> sink_holder(sink_);
|
||||
std::unique_ptr<WritableFileWriter> wfw(new WritableFileWriter(
|
||||
std::move(sink_holder), "" /* file name */, FileOptions()));
|
||||
log_writer_.reset(new Writer(std::move(wfw), 123, GetParam()));
|
||||
}
|
||||
|
||||
Status SetupTestEnv() {
|
||||
dest_holder_.reset(test::GetWritableFileWriter(
|
||||
new test::StringSink(&contents_), "" /* file name */));
|
||||
assert(dest_holder_ != nullptr);
|
||||
log_writer_.reset(new Writer(std::move(dest_holder_), 123, GetParam()));
|
||||
assert(log_writer_ != nullptr);
|
||||
|
||||
Status s;
|
||||
s = env_->CreateDirIfMissing(test_dir_);
|
||||
std::unique_ptr<WritableFile> writable_file;
|
||||
FileOptions fopts;
|
||||
auto fs = env_->GetFileSystem();
|
||||
s = fs->CreateDirIfMissing(test_dir_, IOOptions(), nullptr);
|
||||
std::unique_ptr<FSWritableFile> writable_file;
|
||||
if (s.ok()) {
|
||||
s = env_->NewWritableFile(log_file_, &writable_file, env_options_);
|
||||
s = fs->NewWritableFile(log_file_, fopts, &writable_file, nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
writer_.reset(new WritableFileWriter(
|
||||
NewLegacyWritableFileWrapper(std::move(writable_file)), log_file_,
|
||||
env_options_));
|
||||
assert(writer_ != nullptr);
|
||||
writer_.reset(
|
||||
new WritableFileWriter(std::move(writable_file), log_file_, fopts));
|
||||
EXPECT_NE(writer_, nullptr);
|
||||
}
|
||||
std::unique_ptr<SequentialFile> seq_file;
|
||||
std::unique_ptr<FSSequentialFile> seq_file;
|
||||
if (s.ok()) {
|
||||
s = env_->NewSequentialFile(log_file_, &seq_file, env_options_);
|
||||
s = fs->NewSequentialFile(log_file_, fopts, &seq_file, nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
reader_.reset(new SequentialFileReader(
|
||||
NewLegacySequentialFileWrapper(seq_file), log_file_));
|
||||
assert(reader_ != nullptr);
|
||||
reader_.reset(new SequentialFileReader(std::move(seq_file), log_file_));
|
||||
EXPECT_NE(reader_, nullptr);
|
||||
log_reader_.reset(new FragmentBufferedReader(
|
||||
nullptr, std::move(reader_), &report_, true /* checksum */,
|
||||
123 /* log_number */));
|
||||
assert(log_reader_ != nullptr);
|
||||
EXPECT_NE(log_reader_, nullptr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string contents() {
|
||||
auto file = test::GetStringSinkFromLegacyWriter(log_writer_->file());
|
||||
assert(file != nullptr);
|
||||
return file->contents_;
|
||||
std::string contents() { return sink_->contents_; }
|
||||
|
||||
void Encode(const std::string& msg) {
|
||||
ASSERT_OK(log_writer_->AddRecord(Slice(msg)));
|
||||
}
|
||||
|
||||
void Encode(const std::string& msg) { log_writer_->AddRecord(Slice(msg)); }
|
||||
|
||||
void Write(const Slice& data) {
|
||||
writer_->Append(data);
|
||||
writer_->Sync(true);
|
||||
ASSERT_OK(writer_->Append(data));
|
||||
ASSERT_OK(writer_->Sync(true));
|
||||
}
|
||||
|
||||
bool TryRead(std::string* result) {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ Writer::Writer(std::unique_ptr<WritableFileWriter>&& dest, uint64_t log_number,
|
||||
|
||||
Writer::~Writer() {
|
||||
if (dest_) {
|
||||
WriteBuffer();
|
||||
WriteBuffer().PermitUncheckedError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,13 +100,13 @@ TEST_F(ManualCompactionTest, CompactTouchesAllKeys) {
|
||||
options.compaction_filter = new DestroyAllCompactionFilter();
|
||||
ASSERT_OK(DB::Open(options, dbname_, &db));
|
||||
|
||||
db->Put(WriteOptions(), Slice("key1"), Slice("destroy"));
|
||||
db->Put(WriteOptions(), Slice("key2"), Slice("destroy"));
|
||||
db->Put(WriteOptions(), Slice("key3"), Slice("value3"));
|
||||
db->Put(WriteOptions(), Slice("key4"), Slice("destroy"));
|
||||
ASSERT_OK(db->Put(WriteOptions(), Slice("key1"), Slice("destroy")));
|
||||
ASSERT_OK(db->Put(WriteOptions(), Slice("key2"), Slice("destroy")));
|
||||
ASSERT_OK(db->Put(WriteOptions(), Slice("key3"), Slice("value3")));
|
||||
ASSERT_OK(db->Put(WriteOptions(), Slice("key4"), Slice("destroy")));
|
||||
|
||||
Slice key4("key4");
|
||||
db->CompactRange(CompactRangeOptions(), nullptr, &key4);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), nullptr, &key4));
|
||||
Iterator* itr = db->NewIterator(ReadOptions());
|
||||
itr->SeekToFirst();
|
||||
ASSERT_TRUE(itr->Valid());
|
||||
@@ -135,21 +135,21 @@ TEST_F(ManualCompactionTest, Test) {
|
||||
// create first key range
|
||||
WriteBatch batch;
|
||||
for (int i = 0; i < kNumKeys; i++) {
|
||||
batch.Put(Key1(i), "value for range 1 key");
|
||||
ASSERT_OK(batch.Put(Key1(i), "value for range 1 key"));
|
||||
}
|
||||
ASSERT_OK(db->Write(WriteOptions(), &batch));
|
||||
|
||||
// create second key range
|
||||
batch.Clear();
|
||||
for (int i = 0; i < kNumKeys; i++) {
|
||||
batch.Put(Key2(i), "value for range 2 key");
|
||||
ASSERT_OK(batch.Put(Key2(i), "value for range 2 key"));
|
||||
}
|
||||
ASSERT_OK(db->Write(WriteOptions(), &batch));
|
||||
|
||||
// delete second key range
|
||||
batch.Clear();
|
||||
for (int i = 0; i < kNumKeys; i++) {
|
||||
batch.Delete(Key2(i));
|
||||
ASSERT_OK(batch.Delete(Key2(i)));
|
||||
}
|
||||
ASSERT_OK(db->Write(WriteOptions(), &batch));
|
||||
|
||||
@@ -160,7 +160,7 @@ TEST_F(ManualCompactionTest, Test) {
|
||||
Slice greatest(end_key.data(), end_key.size());
|
||||
|
||||
// commenting out the line below causes the example to work correctly
|
||||
db->CompactRange(CompactRangeOptions(), &least, &greatest);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &least, &greatest));
|
||||
|
||||
// count the keys
|
||||
Iterator* iter = db->NewIterator(ReadOptions());
|
||||
@@ -205,7 +205,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
Slice start("5");
|
||||
Slice end("7");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), &start, &end);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &start, &end));
|
||||
ASSERT_EQ(0, filter->NumKeys());
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
Slice start("3");
|
||||
Slice end("7");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), &start, &end);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &start, &end));
|
||||
ASSERT_EQ(2, filter->NumKeys());
|
||||
ASSERT_EQ(0, filter->KeyLevel("4"));
|
||||
ASSERT_EQ(0, filter->KeyLevel("8"));
|
||||
@@ -227,7 +227,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
// no file has keys in range (-inf, 0]
|
||||
Slice end("0");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), nullptr, &end);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), nullptr, &end));
|
||||
ASSERT_EQ(0, filter->NumKeys());
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
// no file has keys in range [9, inf)
|
||||
Slice start("9");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), &start, nullptr);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &start, nullptr));
|
||||
ASSERT_EQ(0, filter->NumKeys());
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
Slice start("2");
|
||||
Slice end("2");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), &start, &end);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &start, &end));
|
||||
ASSERT_EQ(1, filter->NumKeys());
|
||||
ASSERT_EQ(0, filter->KeyLevel("2"));
|
||||
}
|
||||
@@ -260,7 +260,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
Slice start("2");
|
||||
Slice end("5");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), &start, &end);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &start, &end));
|
||||
ASSERT_EQ(3, filter->NumKeys());
|
||||
ASSERT_EQ(1, filter->KeyLevel("2"));
|
||||
ASSERT_EQ(1, filter->KeyLevel("4"));
|
||||
@@ -273,7 +273,7 @@ TEST_F(ManualCompactionTest, SkipLevel) {
|
||||
// [0, inf) overlaps all files
|
||||
Slice start("0");
|
||||
filter->Reset();
|
||||
db->CompactRange(CompactRangeOptions(), &start, nullptr);
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), &start, nullptr));
|
||||
ASSERT_EQ(4, filter->NumKeys());
|
||||
// 1 is first compacted to L1 and then further compacted into [2, 4, 8],
|
||||
// so finally the logged level for 1 is L1.
|
||||
|
||||
+90
-7
@@ -13,7 +13,9 @@
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include "db/dbformat.h"
|
||||
#include "db/kv_checksum.h"
|
||||
#include "db/merge_context.h"
|
||||
#include "db/merge_helper.h"
|
||||
#include "db/pinned_iterators_manager.h"
|
||||
@@ -484,9 +486,54 @@ MemTable::MemTableStats MemTable::ApproximateStats(const Slice& start_ikey,
|
||||
return {entry_count * (data_size / n), entry_count};
|
||||
}
|
||||
|
||||
Status MemTable::VerifyEncodedEntry(Slice encoded,
|
||||
const ProtectionInfoKVOTS64& kv_prot_info) {
|
||||
uint32_t ikey_len = 0;
|
||||
if (!GetVarint32(&encoded, &ikey_len)) {
|
||||
return Status::Corruption("Unable to parse internal key length");
|
||||
}
|
||||
size_t ts_sz = GetInternalKeyComparator().user_comparator()->timestamp_size();
|
||||
if (ikey_len < 8 + ts_sz) {
|
||||
return Status::Corruption("Internal key length too short");
|
||||
}
|
||||
if (ikey_len > encoded.size()) {
|
||||
return Status::Corruption("Internal key length too long");
|
||||
}
|
||||
uint32_t value_len = 0;
|
||||
const size_t key_without_ts_len = ikey_len - ts_sz - 8;
|
||||
Slice key(encoded.data(), key_without_ts_len);
|
||||
encoded.remove_prefix(key_without_ts_len);
|
||||
|
||||
Slice timestamp(encoded.data(), ts_sz);
|
||||
encoded.remove_prefix(ts_sz);
|
||||
|
||||
uint64_t packed = DecodeFixed64(encoded.data());
|
||||
ValueType value_type = kMaxValue;
|
||||
SequenceNumber sequence_number = kMaxSequenceNumber;
|
||||
UnPackSequenceAndType(packed, &sequence_number, &value_type);
|
||||
encoded.remove_prefix(8);
|
||||
|
||||
if (!GetVarint32(&encoded, &value_len)) {
|
||||
return Status::Corruption("Unable to parse value length");
|
||||
}
|
||||
if (value_len < encoded.size()) {
|
||||
return Status::Corruption("Value length too short");
|
||||
}
|
||||
if (value_len > encoded.size()) {
|
||||
return Status::Corruption("Value length too long");
|
||||
}
|
||||
Slice value(encoded.data(), value_len);
|
||||
|
||||
return kv_prot_info.StripS(sequence_number)
|
||||
.StripKVOT(key, value, value_type, timestamp)
|
||||
.GetStatus();
|
||||
}
|
||||
|
||||
Status MemTable::Add(SequenceNumber s, ValueType type,
|
||||
const Slice& key, /* user key */
|
||||
const Slice& value, bool allow_concurrent,
|
||||
const Slice& value,
|
||||
const ProtectionInfoKVOTS64* kv_prot_info,
|
||||
bool allow_concurrent,
|
||||
MemTablePostProcessInfo* post_process_info, void** hint) {
|
||||
// Format of an entry is concatenation of:
|
||||
// key_size : varint32 of internal_key.size()
|
||||
@@ -514,6 +561,15 @@ Status MemTable::Add(SequenceNumber s, ValueType type,
|
||||
p = EncodeVarint32(p, val_size);
|
||||
memcpy(p, value.data(), val_size);
|
||||
assert((unsigned)(p + val_size - buf) == (unsigned)encoded_len);
|
||||
if (kv_prot_info != nullptr) {
|
||||
Slice encoded(buf, encoded_len);
|
||||
TEST_SYNC_POINT_CALLBACK("MemTable::Add:Encoded", &encoded);
|
||||
Status status = VerifyEncodedEntry(encoded, *kv_prot_info);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ts_sz = GetInternalKeyComparator().user_comparator()->timestamp_size();
|
||||
Slice key_without_ts = StripTimestampFromUserKey(key, ts_sz);
|
||||
|
||||
@@ -978,7 +1034,8 @@ void MemTable::MultiGet(const ReadOptions& read_options, MultiGetRange* range,
|
||||
}
|
||||
|
||||
Status MemTable::Update(SequenceNumber seq, const Slice& key,
|
||||
const Slice& value) {
|
||||
const Slice& value,
|
||||
const ProtectionInfoKVOTS64* kv_prot_info) {
|
||||
LookupKey lkey(key, seq);
|
||||
Slice mem_key = lkey.memtable_key();
|
||||
|
||||
@@ -1022,6 +1079,13 @@ Status MemTable::Update(SequenceNumber seq, const Slice& key,
|
||||
(unsigned)(VarintLength(key_length) + key_length +
|
||||
VarintLength(value.size()) + value.size()));
|
||||
RecordTick(moptions_.statistics, NUMBER_KEYS_UPDATED);
|
||||
if (kv_prot_info != nullptr) {
|
||||
ProtectionInfoKVOTS64 updated_kv_prot_info(*kv_prot_info);
|
||||
// `seq` is swallowed and `existing_seq` prevails.
|
||||
updated_kv_prot_info.UpdateS(seq, existing_seq);
|
||||
Slice encoded(entry, p + value.size() - entry);
|
||||
return VerifyEncodedEntry(encoded, updated_kv_prot_info);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
@@ -1029,11 +1093,12 @@ Status MemTable::Update(SequenceNumber seq, const Slice& key,
|
||||
}
|
||||
|
||||
// The latest value is not `kTypeValue` or key doesn't exist
|
||||
return Add(seq, kTypeValue, key, value);
|
||||
return Add(seq, kTypeValue, key, value, kv_prot_info);
|
||||
}
|
||||
|
||||
Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
const Slice& delta) {
|
||||
const Slice& delta,
|
||||
const ProtectionInfoKVOTS64* kv_prot_info) {
|
||||
LookupKey lkey(key, seq);
|
||||
Slice memkey = lkey.memtable_key();
|
||||
|
||||
@@ -1059,8 +1124,8 @@ Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
// Correct user key
|
||||
const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8);
|
||||
ValueType type;
|
||||
uint64_t unused;
|
||||
UnPackSequenceAndType(tag, &unused, &type);
|
||||
uint64_t existing_seq;
|
||||
UnPackSequenceAndType(tag, &existing_seq, &type);
|
||||
switch (type) {
|
||||
case kTypeValue: {
|
||||
Slice prev_value = GetLengthPrefixedSlice(key_ptr + key_length);
|
||||
@@ -1087,9 +1152,27 @@ Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
}
|
||||
RecordTick(moptions_.statistics, NUMBER_KEYS_UPDATED);
|
||||
UpdateFlushState();
|
||||
if (kv_prot_info != nullptr) {
|
||||
ProtectionInfoKVOTS64 updated_kv_prot_info(*kv_prot_info);
|
||||
// `seq` is swallowed and `existing_seq` prevails.
|
||||
updated_kv_prot_info.UpdateS(seq, existing_seq);
|
||||
updated_kv_prot_info.UpdateV(delta,
|
||||
Slice(prev_buffer, new_prev_size));
|
||||
Slice encoded(entry, prev_buffer + new_prev_size - entry);
|
||||
return VerifyEncodedEntry(encoded, updated_kv_prot_info);
|
||||
}
|
||||
return Status::OK();
|
||||
} else if (status == UpdateStatus::UPDATED) {
|
||||
Status s = Add(seq, kTypeValue, key, Slice(str_value));
|
||||
Status s;
|
||||
if (kv_prot_info != nullptr) {
|
||||
ProtectionInfoKVOTS64 updated_kv_prot_info(*kv_prot_info);
|
||||
updated_kv_prot_info.UpdateV(delta, str_value);
|
||||
s = Add(seq, kTypeValue, key, Slice(str_value),
|
||||
&updated_kv_prot_info);
|
||||
} else {
|
||||
s = Add(seq, kTypeValue, key, Slice(str_value),
|
||||
nullptr /* kv_prot_info */);
|
||||
}
|
||||
RecordTick(moptions_.statistics, NUMBER_KEYS_WRITTEN);
|
||||
UpdateFlushState();
|
||||
return s;
|
||||
|
||||
+11
-3
@@ -15,7 +15,9 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "db/dbformat.h"
|
||||
#include "db/kv_checksum.h"
|
||||
#include "db/range_tombstone_fragmenter.h"
|
||||
#include "db/read_callback.h"
|
||||
#include "db/version_edit.h"
|
||||
@@ -175,6 +177,9 @@ class MemTable {
|
||||
FragmentedRangeTombstoneIterator* NewRangeTombstoneIterator(
|
||||
const ReadOptions& read_options, SequenceNumber read_seq);
|
||||
|
||||
Status VerifyEncodedEntry(Slice encoded,
|
||||
const ProtectionInfoKVOTS64& kv_prot_info);
|
||||
|
||||
// Add an entry into memtable that maps key to value at the
|
||||
// specified sequence number and with the specified type.
|
||||
// Typically value will be empty if type==kTypeDeletion.
|
||||
@@ -186,7 +191,8 @@ class MemTable {
|
||||
// in the memtable and `MemTableRepFactory::CanHandleDuplicatedKey()` is true.
|
||||
// The next attempt should try a larger value for `seq`.
|
||||
Status Add(SequenceNumber seq, ValueType type, const Slice& key,
|
||||
const Slice& value, bool allow_concurrent = false,
|
||||
const Slice& value, const ProtectionInfoKVOTS64* kv_prot_info,
|
||||
bool allow_concurrent = false,
|
||||
MemTablePostProcessInfo* post_process_info = nullptr,
|
||||
void** hint = nullptr);
|
||||
|
||||
@@ -250,7 +256,8 @@ class MemTable {
|
||||
//
|
||||
// REQUIRES: external synchronization to prevent simultaneous
|
||||
// operations on the same MemTable.
|
||||
Status Update(SequenceNumber seq, const Slice& key, const Slice& value);
|
||||
Status Update(SequenceNumber seq, const Slice& key, const Slice& value,
|
||||
const ProtectionInfoKVOTS64* kv_prot_info);
|
||||
|
||||
// If `key` exists in current memtable with type `kTypeValue` and the existing
|
||||
// value is at least as large as the new value, updates it in-place. Otherwise
|
||||
@@ -267,7 +274,8 @@ class MemTable {
|
||||
// REQUIRES: external synchronization to prevent simultaneous
|
||||
// operations on the same MemTable.
|
||||
Status UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
const Slice& delta);
|
||||
const Slice& delta,
|
||||
const ProtectionInfoKVOTS64* kv_prot_info);
|
||||
|
||||
// Returns the number of successive merge entries starting from the newest
|
||||
// entry for the key up to the last non-merge entry or last entry for the
|
||||
|
||||
+45
-24
@@ -30,14 +30,14 @@ class MemTableListTest : public testing::Test {
|
||||
MemTableListTest() : db(nullptr), file_number(1) {
|
||||
dbname = test::PerThreadDBPath("memtable_list_test");
|
||||
options.create_if_missing = true;
|
||||
DestroyDB(dbname, options);
|
||||
EXPECT_OK(DestroyDB(dbname, options));
|
||||
}
|
||||
|
||||
// Create a test db if not yet created
|
||||
void CreateDB() {
|
||||
if (db == nullptr) {
|
||||
options.create_if_missing = true;
|
||||
DestroyDB(dbname, options);
|
||||
EXPECT_OK(DestroyDB(dbname, options));
|
||||
// Open DB only with default column family
|
||||
ColumnFamilyOptions cf_options;
|
||||
std::vector<ColumnFamilyDescriptor> cf_descs;
|
||||
@@ -78,7 +78,7 @@ class MemTableListTest : public testing::Test {
|
||||
handles.clear();
|
||||
delete db;
|
||||
db = nullptr;
|
||||
DestroyDB(dbname, options, cf_descs);
|
||||
EXPECT_OK(DestroyDB(dbname, options, cf_descs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,10 +243,14 @@ TEST_F(MemTableListTest, GetTest) {
|
||||
mem->Ref();
|
||||
|
||||
// Write some keys to this memtable.
|
||||
ASSERT_OK(mem->Add(++seq, kTypeDeletion, "key1", ""));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key1", "value1"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2.2"));
|
||||
ASSERT_OK(
|
||||
mem->Add(++seq, kTypeDeletion, "key1", "", nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key1", "value1",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2.2",
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
// Fetch the newly written keys
|
||||
merge_context.Clear();
|
||||
@@ -284,8 +288,10 @@ TEST_F(MemTableListTest, GetTest) {
|
||||
kMaxSequenceNumber, 0 /* column_family_id */);
|
||||
mem2->Ref();
|
||||
|
||||
ASSERT_OK(mem2->Add(++seq, kTypeDeletion, "key1", ""));
|
||||
ASSERT_OK(mem2->Add(++seq, kTypeValue, "key2", "value2.3"));
|
||||
ASSERT_OK(
|
||||
mem2->Add(++seq, kTypeDeletion, "key1", "", nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem2->Add(++seq, kTypeValue, "key2", "value2.3",
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
// Add second memtable to list
|
||||
list.Add(mem2, &to_delete);
|
||||
@@ -360,9 +366,12 @@ TEST_F(MemTableListTest, GetFromHistoryTest) {
|
||||
mem->Ref();
|
||||
|
||||
// Write some keys to this memtable.
|
||||
ASSERT_OK(mem->Add(++seq, kTypeDeletion, "key1", ""));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2.2"));
|
||||
ASSERT_OK(
|
||||
mem->Add(++seq, kTypeDeletion, "key1", "", nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key2", "value2.2",
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
// Fetch the newly written keys
|
||||
merge_context.Clear();
|
||||
@@ -444,8 +453,10 @@ TEST_F(MemTableListTest, GetFromHistoryTest) {
|
||||
kMaxSequenceNumber, 0 /* column_family_id */);
|
||||
mem2->Ref();
|
||||
|
||||
ASSERT_OK(mem2->Add(++seq, kTypeDeletion, "key1", ""));
|
||||
ASSERT_OK(mem2->Add(++seq, kTypeValue, "key3", "value3"));
|
||||
ASSERT_OK(
|
||||
mem2->Add(++seq, kTypeDeletion, "key1", "", nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem2->Add(++seq, kTypeValue, "key3", "value3",
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
// Add second memtable to list
|
||||
list.Add(mem2, &to_delete);
|
||||
@@ -555,11 +566,16 @@ TEST_F(MemTableListTest, FlushPendingTest) {
|
||||
std::string value;
|
||||
MergeContext merge_context;
|
||||
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key1", ToString(i)));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyN" + ToString(i), "valueN"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyX" + ToString(i), "value"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyM" + ToString(i), "valueM"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeDeletion, "keyX" + ToString(i), ""));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key1", ToString(i),
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyN" + ToString(i), "valueN",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyX" + ToString(i), "value",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyM" + ToString(i), "valueM",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeDeletion, "keyX" + ToString(i), "",
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
tables.push_back(mem);
|
||||
}
|
||||
@@ -824,11 +840,16 @@ TEST_F(MemTableListTest, AtomicFlusTest) {
|
||||
|
||||
std::string value;
|
||||
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key1", ToString(i)));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyN" + ToString(i), "valueN"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyX" + ToString(i), "value"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyM" + ToString(i), "valueM"));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeDeletion, "keyX" + ToString(i), ""));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "key1", ToString(i),
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyN" + ToString(i), "valueN",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyX" + ToString(i), "value",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeValue, "keyM" + ToString(i), "valueM",
|
||||
nullptr /* kv_prot_info */));
|
||||
ASSERT_OK(mem->Add(++seq, kTypeDeletion, "keyX" + ToString(i), "",
|
||||
nullptr /* kv_prot_info */));
|
||||
|
||||
elem.push_back(mem);
|
||||
}
|
||||
|
||||
Loaded 100 of 355 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user