mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-06 11:02:36 -05:00
Compare commits
432
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59852b5e71 | ||
|
|
093ff0b2ce | ||
|
|
e10553f2a6 | ||
|
|
442404558a | ||
|
|
217ce20021 | ||
|
|
8ad4b32c5d | ||
|
|
1df9b01680 | ||
|
|
712bc4b6a2 | ||
|
|
a8149aef1e | ||
|
|
66ed58083a | ||
|
|
098dce2d1a | ||
|
|
6c595f008a | ||
|
|
db02664f35 | ||
|
|
58918d4ccc | ||
|
|
488b1e6739 | ||
|
|
d66908091d | ||
|
|
402da454cb | ||
|
|
23eae14d24 | ||
|
|
a824727db4 | ||
|
|
85dbdf2586 | ||
|
|
5c30e6c088 | ||
|
|
674cf41732 | ||
|
|
dd7a4a8f03 | ||
|
|
a8851f2d05 | ||
|
|
2ccb794eb6 | ||
|
|
0d2c8e47e8 | ||
|
|
0772768d07 | ||
|
|
c15e85bdcb | ||
|
|
07a3f7f008 | ||
|
|
6dea7530b5 | ||
|
|
2d9efc9ab2 | ||
|
|
331e6199df | ||
|
|
37a635cfe6 | ||
|
|
8fc20ac468 | ||
|
|
65b60db9e1 | ||
|
|
00c4ab01b9 | ||
|
|
f5bc3b99d5 | ||
|
|
4028eba67b | ||
|
|
fd1da22111 | ||
|
|
d93812c9ae | ||
|
|
0a0151fb99 | ||
|
|
f6c2777d95 | ||
|
|
e171a219d5 | ||
|
|
afb97094ae | ||
|
|
e62fe50634 | ||
|
|
8bbd76edbf | ||
|
|
03dbd11ead | ||
|
|
48d8d076a3 | ||
|
|
17bef7d3a8 | ||
|
|
8d73137ae8 | ||
|
|
904a60ff63 | ||
|
|
8637bc1eea | ||
|
|
5f2f8cd97c | ||
|
|
9b3c9ef0e8 | ||
|
|
86f1ad7046 | ||
|
|
051696bf98 | ||
|
|
41535d0218 | ||
|
|
72ee067b90 | ||
|
|
741decfe37 | ||
|
|
f52db84650 | ||
|
|
69679e7375 | ||
|
|
d87c10c6ab | ||
|
|
eb367d45c0 | ||
|
|
b47a714051 | ||
|
|
43dde332cb | ||
|
|
942eaba091 | ||
|
|
890d87fadc | ||
|
|
ab65278b1f | ||
|
|
fcec56e86c | ||
|
|
d75ce0a8ae | ||
|
|
362b8d4393 | ||
|
|
fdf882ded2 | ||
|
|
4e33f1e1dc | ||
|
|
a993cc3a62 | ||
|
|
5a297516e1 | ||
|
|
c6abe30ee3 | ||
|
|
0f9dcb88b2 | ||
|
|
3a3457575d | ||
|
|
dc23c125c3 | ||
|
|
152f8a8ffe | ||
|
|
4034e289ad | ||
|
|
29e24434fe | ||
|
|
908b1ee64e | ||
|
|
fb571509a7 | ||
|
|
ac8e89a443 | ||
|
|
46516778dd | ||
|
|
acfee40af5 | ||
|
|
5138764eb5 | ||
|
|
df3f33dd05 | ||
|
|
a676001f95 | ||
|
|
6e97d4de00 | ||
|
|
e64508917b | ||
|
|
3e49249d30 | ||
|
|
e412a426d6 | ||
|
|
28aa09dcce | ||
|
|
35ed530d2c | ||
|
|
d3ba398bbd | ||
|
|
dafb568052 | ||
|
|
cbf5f3be43 | ||
|
|
4369f2c7bb | ||
|
|
594e815e32 | ||
|
|
b2bc1da561 | ||
|
|
2e0159ec9e | ||
|
|
debc4ef18b | ||
|
|
84b41a6969 | ||
|
|
d70011bccc | ||
|
|
4e457278fa | ||
|
|
876c2dbff4 | ||
|
|
b42fa1497f | ||
|
|
25fbdc5a31 | ||
|
|
752c87af78 | ||
|
|
5f478b9f75 | ||
|
|
1b4be4cac9 | ||
|
|
107a7ca930 | ||
|
|
0a74e1b958 | ||
|
|
f361cedf06 | ||
|
|
c6f75516b7 | ||
|
|
f5f79f01a2 | ||
|
|
24c9dce825 | ||
|
|
1ed7d9b1b5 | ||
|
|
3a073234da | ||
|
|
69c8614815 | ||
|
|
637e64b9ac | ||
|
|
7330ec0ff1 | ||
|
|
f195d8d523 | ||
|
|
36c504be17 | ||
|
|
eb4d6af5ae | ||
|
|
7242dae7fe | ||
|
|
800d24ddc5 | ||
|
|
01ab882ba3 | ||
|
|
ec496347bc | ||
|
|
2243030bc5 | ||
|
|
3316d29221 | ||
|
|
f2fbc5d668 | ||
|
|
c9a5e48762 | ||
|
|
90c71aa5d9 | ||
|
|
fb05b5a652 | ||
|
|
9e3ace42a4 | ||
|
|
71874c5aaf | ||
|
|
23dcf2759d | ||
|
|
02ac6c9a3c | ||
|
|
2f973ca96e | ||
|
|
a07a9dc904 | ||
|
|
8f2bee6747 | ||
|
|
431fb6c0ba | ||
|
|
4f6c86226c | ||
|
|
7aa66c704f | ||
|
|
5b33cfa1e3 | ||
|
|
f10f135938 | ||
|
|
986df37135 | ||
|
|
bd698e4f55 | ||
|
|
c4bc30e12d | ||
|
|
f34782a67d | ||
|
|
0672a6db64 | ||
|
|
967a2d953f | ||
|
|
cb1142e00d | ||
|
|
e6e8b9e871 | ||
|
|
d305f13e21 | ||
|
|
8e309b35bb | ||
|
|
8aa99fc71e | ||
|
|
4b86fe1123 | ||
|
|
931876e86e | ||
|
|
7e5b04d04f | ||
|
|
6b64aed4c0 | ||
|
|
d87cffaea4 | ||
|
|
73f65b457e | ||
|
|
86623a7153 | ||
|
|
f8b5ef85ec | ||
|
|
b7f1b3e51c | ||
|
|
d2b4d42d4b | ||
|
|
1dd7873e08 | ||
|
|
76c117b24b | ||
|
|
d4b7fbf0d5 | ||
|
|
894c6d21af | ||
|
|
6733be033e | ||
|
|
cfa585611d | ||
|
|
eff5e076f5 | ||
|
|
687119aeaf | ||
|
|
6a9989381f | ||
|
|
39410bcb3d | ||
|
|
cfd9732f65 | ||
|
|
e5b476f551 | ||
|
|
941bd15aed | ||
|
|
1244abef66 | ||
|
|
f4a378be3e | ||
|
|
6477075f2c | ||
|
|
5709e97a74 | ||
|
|
1ab1231acf | ||
|
|
2fdd8087ce | ||
|
|
a8b1085ae2 | ||
|
|
bce5189f4d | ||
|
|
3e26a94ba1 | ||
|
|
1aaa145877 | ||
|
|
946c43a026 | ||
|
|
edaaa1fff2 | ||
|
|
28e5a9a9fb | ||
|
|
83957dc510 | ||
|
|
7c98d71567 | ||
|
|
48a678b7c9 | ||
|
|
83108d23e8 | ||
|
|
faebc336da | ||
|
|
95d226d8f5 | ||
|
|
37fd2b9694 | ||
|
|
5f559897cf | ||
|
|
22fea0ba79 | ||
|
|
d4da412864 | ||
|
|
e0f9d11a05 | ||
|
|
9d36c066c6 | ||
|
|
79cc8dc29b | ||
|
|
3160edfdc7 | ||
|
|
338c149b92 | ||
|
|
e55c2b3f0b | ||
|
|
e697da0b18 | ||
|
|
4d3264e4ab | ||
|
|
f89dea4fec | ||
|
|
c4fd9cf461 | ||
|
|
1ebaa762e6 | ||
|
|
786c3d45ed | ||
|
|
670a916d01 | ||
|
|
7a7ca8eb5b | ||
|
|
1ba92b8582 | ||
|
|
f295b099f6 | ||
|
|
873331fe49 | ||
|
|
77d5ba7887 | ||
|
|
9ff569bdfc | ||
|
|
5b18729d7d | ||
|
|
54f9092b0c | ||
|
|
130e710056 | ||
|
|
ef91894798 | ||
|
|
7da8c067a2 | ||
|
|
f453bcb40d | ||
|
|
02193ce406 | ||
|
|
dfb259e48d | ||
|
|
c399704c7a | ||
|
|
2afea29762 | ||
|
|
ce63eda6f0 | ||
|
|
cbd58af9c3 | ||
|
|
9f250dd88e | ||
|
|
2d16709487 | ||
|
|
39fcaf8246 | ||
|
|
02aa22957a | ||
|
|
1be48cb895 | ||
|
|
7678cf2df7 | ||
|
|
68d5d82d1f | ||
|
|
cddd637997 | ||
|
|
bcc372c0c3 | ||
|
|
2d095b4dbc | ||
|
|
35126dd874 | ||
|
|
fbda25f57a | ||
|
|
db7c687523 | ||
|
|
a92bd0a183 | ||
|
|
ad34faba15 | ||
|
|
4b97812da8 | ||
|
|
bd8404feff | ||
|
|
349bd3ed82 | ||
|
|
edbf0e2d90 | ||
|
|
0d2172f128 | ||
|
|
afa2420c2b | ||
|
|
58d46d1915 | ||
|
|
6d54eb3dc2 | ||
|
|
ac304adf46 | ||
|
|
fec7302a9d | ||
|
|
583c6953d8 | ||
|
|
c2029f9716 | ||
|
|
4b74035e40 | ||
|
|
c4ce8e637f | ||
|
|
a844591201 | ||
|
|
814d4e7ce0 | ||
|
|
a796c06fef | ||
|
|
b433bbefe9 | ||
|
|
3b607610df | ||
|
|
8613ee2e94 | ||
|
|
e1dfe80fe0 | ||
|
|
1ad6fa9cc7 | ||
|
|
d0ad3c59d8 | ||
|
|
3717a88289 | ||
|
|
afdc58d478 | ||
|
|
05a86318a7 | ||
|
|
77565d7532 | ||
|
|
383f5071f0 | ||
|
|
7a99162a74 | ||
|
|
984b6e71d6 | ||
|
|
a653857178 | ||
|
|
2bb5fc1280 | ||
|
|
2b060c1498 | ||
|
|
14c38baca0 | ||
|
|
1dd3194f56 | ||
|
|
6380df5e10 | ||
|
|
a68dff5c35 | ||
|
|
a960287dee | ||
|
|
e43d2c4424 | ||
|
|
3c347821b7 | ||
|
|
7e2f831924 | ||
|
|
d1ae2c3faf | ||
|
|
3a6d9436e8 | ||
|
|
7d79b32618 | ||
|
|
bac38c992a | ||
|
|
e3a82bb934 | ||
|
|
6db57bc37f | ||
|
|
ad528fe5ca | ||
|
|
100b5e69f3 | ||
|
|
cdc431ec81 | ||
|
|
4edb4284e7 | ||
|
|
f32a311f0d | ||
|
|
fe1147db1c | ||
|
|
16fa6fd2a6 | ||
|
|
048472f620 | ||
|
|
e8f997ca59 | ||
|
|
09fcf4fb6b | ||
|
|
f19faf7814 | ||
|
|
a61ec9ae3b | ||
|
|
9befbe9b40 | ||
|
|
0695793283 | ||
|
|
c16b087427 | ||
|
|
aa1857e2df | ||
|
|
496a6ae895 | ||
|
|
ca3b6c28c9 | ||
|
|
6d58ea901d | ||
|
|
8ae149eba1 | ||
|
|
d9314a9214 | ||
|
|
57f3032285 | ||
|
|
72daa92d3a | ||
|
|
771e1723c7 | ||
|
|
1bf316e5b6 | ||
|
|
7f14519577 | ||
|
|
4f17d33db4 | ||
|
|
382b154be6 | ||
|
|
77eab5c85a | ||
|
|
fcd7e03832 | ||
|
|
0bc87442ae | ||
|
|
669ea77d9f | ||
|
|
75dfc7883d | ||
|
|
d8c28e692a | ||
|
|
adcf920f40 | ||
|
|
e50b64bdba | ||
|
|
0ce0edbe12 | ||
|
|
c0983d0691 | ||
|
|
3cd75736a7 | ||
|
|
27ec3b3466 | ||
|
|
0306e01233 | ||
|
|
ec3e3c3e02 | ||
|
|
019eb1f402 | ||
|
|
4e0dcd36df | ||
|
|
20b48c6478 | ||
|
|
38cc611297 | ||
|
|
ac498cdb86 | ||
|
|
279c488395 | ||
|
|
a150604e10 | ||
|
|
5b9233bfe8 | ||
|
|
f65ec09ef8 | ||
|
|
0058daef7b | ||
|
|
00d58a370e | ||
|
|
6123611c42 | ||
|
|
e8e7fb1dcf | ||
|
|
f059c7d9b9 | ||
|
|
f382f44e39 | ||
|
|
bb23bfe63c | ||
|
|
42b5494ec8 | ||
|
|
6c7b1a0cc7 | ||
|
|
a19de78da5 | ||
|
|
03ce7fb292 | ||
|
|
f29e6b3be2 | ||
|
|
c17384fea4 | ||
|
|
8e7aa62813 | ||
|
|
aa63abf698 | ||
|
|
72de842ac9 | ||
|
|
f80050fa8f | ||
|
|
07a0ad3c29 | ||
|
|
9836a1fa33 | ||
|
|
1da1f04231 | ||
|
|
982a7532a7 | ||
|
|
f0b469e563 | ||
|
|
7b3222e10a | ||
|
|
111ebf3161 | ||
|
|
8ea087ad16 | ||
|
|
50804656d2 | ||
|
|
834feaff05 | ||
|
|
67e735dbf9 | ||
|
|
230bcae7b6 | ||
|
|
52733b4498 | ||
|
|
0d91a981e9 | ||
|
|
e4e1d35cc2 | ||
|
|
a44670e71b | ||
|
|
5b656584af | ||
|
|
18f57f5ef8 | ||
|
|
685e895652 | ||
|
|
351e25401b | ||
|
|
aa6f7d0995 | ||
|
|
2a9e5caffe | ||
|
|
dccaf9f03c | ||
|
|
0337d87b42 | ||
|
|
15119f08e2 | ||
|
|
a3960fc875 | ||
|
|
f22aaf8b3f | ||
|
|
4c9aa30a62 | ||
|
|
26dc29633e | ||
|
|
79018ba51b | ||
|
|
1075c376ef | ||
|
|
3f891c40a0 | ||
|
|
b3dc2f3691 | ||
|
|
ec880436c1 | ||
|
|
013babc685 | ||
|
|
2309fd63bf | ||
|
|
ca7ccbe2ea | ||
|
|
ec11eff3bc | ||
|
|
f7e7b34ebe | ||
|
|
dd19014a7a | ||
|
|
2837008525 | ||
|
|
2509531123 | ||
|
|
9f1e5a0b87 | ||
|
|
6a32e3b562 | ||
|
|
b4ebda7a39 | ||
|
|
0933360644 | ||
|
|
c0abc6bbc1 | ||
|
|
925250f42f | ||
|
|
5677f4f775 | ||
|
|
27a124571f | ||
|
|
7245fb5f63 | ||
|
|
2ce6aa5f39 | ||
|
|
a0cd920026 | ||
|
|
30e2dc02f0 | ||
|
|
1a21afa789 | ||
|
|
29ccf2075c | ||
|
|
c53db172a1 | ||
|
|
5f8f2fda0e | ||
|
|
fe464bca5c | ||
|
|
526e3b9763 | ||
|
|
69bd8a2859 | ||
|
|
e60cc0925c | ||
|
|
fdc1cb43a6 | ||
|
|
1f9d7c0f54 | ||
|
|
2c9e9f2a59 |
No files matched your search
@@ -0,0 +1,56 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
win: circleci/windows@2.4.0
|
||||
|
||||
executors:
|
||||
windows-2xlarge:
|
||||
machine:
|
||||
image: 'windows-server-2019-vs2019:stable'
|
||||
resource_class: windows.2xlarge
|
||||
shell: bash.exe
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: windows-2xlarge
|
||||
|
||||
environment:
|
||||
THIRDPARTY_HOME: C:/Users/circleci/thirdparty
|
||||
CMAKE_HOME: C:/Users/circleci/thirdparty/cmake-3.16.4-win64-x64
|
||||
CMAKE_BIN: C:/Users/circleci/thirdparty/cmake-3.16.4-win64-x64/bin/cmake.exe
|
||||
CMAKE_GENERATOR: Visual Studio 16 2019
|
||||
SNAPPY_HOME: C:/Users/circleci/thirdparty/snappy-1.1.7
|
||||
SNAPPY_INCLUDE: C:/Users/circleci/thirdparty/snappy-1.1.7;C:/Users/circleci/thirdparty/snappy-1.1.7/build
|
||||
SNAPPY_LIB_DEBUG: C:/Users/circleci/thirdparty/snappy-1.1.7/build/Debug/snappy.lib
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Install thirdparty dependencies"
|
||||
command: |
|
||||
mkdir ${THIRDPARTY_HOME}
|
||||
cd ${THIRDPARTY_HOME}
|
||||
echo "Installing CMake..."
|
||||
curl --fail --silent --show-error --output cmake-3.16.4-win64-x64.zip --location https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-win64-x64.zip
|
||||
unzip -q cmake-3.16.4-win64-x64.zip
|
||||
echo "Building Snappy dependency..."
|
||||
curl --fail --silent --show-error --output snappy-1.1.7.zip --location https://github.com/google/snappy/archive/1.1.7.zip
|
||||
unzip -q snappy-1.1.7.zip
|
||||
cd snappy-1.1.7
|
||||
mkdir build
|
||||
cd build
|
||||
${CMAKE_BIN} -G "${CMAKE_GENERATOR}" ..
|
||||
msbuild.exe Snappy.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
|
||||
- run:
|
||||
name: "Build RocksDB"
|
||||
command: |
|
||||
mkdir build
|
||||
cd build
|
||||
${CMAKE_BIN} -G "${CMAKE_GENERATOR}" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE=1 -DSNAPPY=1 -DJNI=1 ..
|
||||
cd ..
|
||||
msbuild.exe build/rocksdb.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
|
||||
- run:
|
||||
name: "Test RocksDB"
|
||||
shell: powershell.exe
|
||||
command: |
|
||||
build_tools\run_ci_db_test.ps1 -SuiteRun db_basic_test,db_test,db_test2,env_basic_test,env_test,db_merge_operand_test -Concurrency 16
|
||||
@@ -34,6 +34,7 @@ manifest_dump
|
||||
sst_dump
|
||||
blob_dump
|
||||
block_cache_trace_analyzer
|
||||
db_with_timestamp_basic_test
|
||||
tools/block_cache_analyzer/*.pyc
|
||||
column_aware_encoding_exp
|
||||
util/build_version.cc
|
||||
@@ -52,6 +53,8 @@ trace_analyzer
|
||||
trace_analyzer_test
|
||||
block_cache_trace_analyzer
|
||||
.DS_Store
|
||||
.vs
|
||||
.vscode
|
||||
|
||||
java/out
|
||||
java/target
|
||||
@@ -79,3 +82,6 @@ tp2/
|
||||
fbcode/
|
||||
fbcode
|
||||
buckifier/*.pyc
|
||||
buckifier/__pycache__
|
||||
|
||||
compile_commands.json
|
||||
+140
-31
@@ -3,28 +3,39 @@ language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
osx_image: xcode8.3
|
||||
jdk:
|
||||
- openjdk7
|
||||
osx_image: xcode9.4
|
||||
cache:
|
||||
- ccache
|
||||
- apt
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- curl
|
||||
- g++-8
|
||||
- libbz2-dev
|
||||
- libgflags-dev
|
||||
- libbz2-dev
|
||||
- liblz4-dev
|
||||
- libsnappy-dev
|
||||
- mingw-w64
|
||||
- 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
|
||||
- TEST_GROUP=1 # 33-35 minutes
|
||||
@@ -43,37 +54,135 @@ env:
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: TEST_GROUP=1
|
||||
- os: osx
|
||||
env: TEST_GROUP=2
|
||||
- os: osx
|
||||
env: TEST_GROUP=3
|
||||
- os: osx
|
||||
env: TEST_GROUP=4
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- os : osx
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os : linux
|
||||
compiler: clang
|
||||
- os : osx
|
||||
- os: osx
|
||||
arch: ppc64le
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os: linux
|
||||
compiler: clang
|
||||
# Exclude most osx, arm64 and ppc64le tests for pull requests, but build in branches
|
||||
- if: type != pull_request
|
||||
os: osx
|
||||
env: TEST_GROUP=1
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: TEST_GROUP=1
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=1
|
||||
- if: type != pull_request
|
||||
os: osx
|
||||
env: TEST_GROUP=2
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: TEST_GROUP=2
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=2
|
||||
- if: type != pull_request
|
||||
os: osx
|
||||
env: TEST_GROUP=3
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: TEST_GROUP=3
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=3
|
||||
- if: type != pull_request
|
||||
os: osx
|
||||
env: TEST_GROUP=4
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: TEST_GROUP=4
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=4
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=java-test
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=java-test
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=lite-build
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=lite-build
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=examples
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=examples
|
||||
- if: type != pull_request
|
||||
os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- if: type != pull_request
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
|
||||
# https://docs.travis-ci.com/user/caching/#ccache-cache
|
||||
install:
|
||||
- if [ "${TRAVIS_OS_NAME}" == osx ]; then
|
||||
brew install ccache zstd lz4 snappy xz;
|
||||
PATH=$PATH:/usr/local/opt/ccache/libexec;
|
||||
fi
|
||||
- if [ "${JOB_NAME}" == cmake-gcc8 ]; then
|
||||
sudo apt-get install -y g++-8;
|
||||
CC=gcc-8 && CXX=g++-8;
|
||||
fi
|
||||
- if [[ "${JOB_NAME}" == cmake* ]] && [ "${TRAVIS_OS_NAME}" == linux ]; then
|
||||
mkdir cmake-dist && curl -sfSL https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz | tar --strip-components=1 -C cmake-dist -xz && export PATH=$PWD/cmake-dist/bin:$PATH;
|
||||
- if [ "${JOB_NAME}" == cmake-mingw ]; then
|
||||
sudo apt-get install -y mingw-w64 ;
|
||||
fi
|
||||
- if [[ "${JOB_NAME}" == java_test ]]; then
|
||||
java -version && echo "JAVA_HOME=${JAVA_HOME}";
|
||||
- if [[ "${JOB_NAME}" == cmake* ]] && [ "${TRAVIS_OS_NAME}" == linux ]; then
|
||||
CMAKE_DIST_URL="https://rocksdb-deps.s3-us-west-2.amazonaws.com/cmake/cmake-3.14.5-Linux-$(uname -m).tar.bz2";
|
||||
TAR_OPT="--strip-components=1 -xj";
|
||||
if [ "aarch64" == "$(uname -m)" ]; then
|
||||
sudo apt-get install -y libuv1 librhash0;
|
||||
sudo apt-get upgrade -y libstdc++6;
|
||||
fi;
|
||||
mkdir cmake-dist && curl --silent --fail --show-error --location "${CMAKE_DIST_URL}" | tar -C cmake-dist ${TAR_OPT} && export PATH=$PWD/cmake-dist/bin:$PATH;
|
||||
fi
|
||||
- |
|
||||
if [[ "${JOB_NAME}" == java_test || "${JOB_NAME}" == cmake* ]]; then
|
||||
# Ensure JDK 8
|
||||
if [ "${TRAVIS_OS_NAME}" == osx ]; then
|
||||
brew tap AdoptOpenJDK/openjdk
|
||||
brew cask install adoptopenjdk8
|
||||
export JAVA_HOME=$(/usr/libexec/java_home)
|
||||
else
|
||||
sudo apt-get install -y openjdk-8-jdk
|
||||
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
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
fi
|
||||
|
||||
before_script:
|
||||
@@ -82,20 +191,20 @@ before_script:
|
||||
- ulimit -n 8192
|
||||
|
||||
script:
|
||||
- ${CXX} --version
|
||||
- date; ${CXX} --version
|
||||
- if [ `command -v ccache` ]; then ccache -C; fi
|
||||
- case $TEST_GROUP in
|
||||
platform_dependent)
|
||||
OPT=-DTRAVIS V=1 ROCKSDBTESTS_END=db_block_cache_test make -j4 all_but_some_tests check_some
|
||||
;;
|
||||
1)
|
||||
OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=db_block_cache_test ROCKSDBTESTS_END=full_filter_block_test make -j4 check_some
|
||||
OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=db_block_cache_test ROCKSDBTESTS_END=db_iter_test make -j4 check_some
|
||||
;;
|
||||
2)
|
||||
OPT=-DTRAVIS V=1 make -j4 tools && OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=full_filter_block_test ROCKSDBTESTS_END=write_batch_with_index_test make -j4 check_some
|
||||
OPT="-DTRAVIS -DROCKSDB_NAMESPACE=alternative_rocksdb_ns" V=1 make -j4 tools && OPT="-DTRAVIS -DROCKSDB_NAMESPACE=alternative_rocksdb_ns" V=1 ROCKSDBTESTS_START=db_iter_test ROCKSDBTESTS_END=options_file_test make -j4 check_some
|
||||
;;
|
||||
3)
|
||||
OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=write_batch_with_index_test ROCKSDBTESTS_END=write_prepared_transaction_test make -j4 check_some
|
||||
OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=options_file_test ROCKSDBTESTS_END=write_prepared_transaction_test make -j4 check_some
|
||||
;;
|
||||
4)
|
||||
OPT=-DTRAVIS V=1 ROCKSDBTESTS_START=write_prepared_transaction_test make -j4 check_some
|
||||
@@ -113,7 +222,7 @@ script:
|
||||
;;
|
||||
cmake-mingw)
|
||||
sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix;
|
||||
mkdir build && cd build && cmake -DJNI=1 .. -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_SYSTEM_NAME=Windows && make -j4 rocksdb rocksdbjni
|
||||
mkdir build && cd build && cmake -DJNI=1 -DWITH_GFLAGS=OFF .. -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++ -DCMAKE_SYSTEM_NAME=Windows && make -j4 rocksdb rocksdbjni
|
||||
;;
|
||||
cmake*)
|
||||
mkdir build && cd build && cmake -DJNI=1 .. -DCMAKE_BUILD_TYPE=Release && make -j4 rocksdb rocksdbjni
|
||||
|
||||
+194
-104
@@ -14,7 +14,7 @@
|
||||
# cd build
|
||||
# 3. Run cmake to generate project files for Windows, add more options to enable required third-party libraries.
|
||||
# See thirdparty.inc for more information.
|
||||
# sample command: cmake -G "Visual Studio 15 Win64" -DWITH_GFLAGS=1 -DWITH_SNAPPY=1 -DWITH_JEMALLOC=1 -DWITH_JNI=1 ..
|
||||
# sample command: cmake -G "Visual Studio 15 Win64" -DCMAKE_BUILD_TYPE=Release -DWITH_GFLAGS=1 -DWITH_SNAPPY=1 -DWITH_JEMALLOC=1 -DWITH_JNI=1 ..
|
||||
# 4. Then build the project in debug mode (you may want to add /m[:<N>] flag to run msbuild in <N> parallel threads
|
||||
# or simply /m to use all avail cores)
|
||||
# msbuild rocksdb.sln
|
||||
@@ -45,6 +45,16 @@ if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
set(default_build_type "Debug")
|
||||
else()
|
||||
set(default_build_type "RelWithDebInfo")
|
||||
endif()
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
|
||||
"Default BUILD_TYPE is ${default_build_type}" FORCE)
|
||||
endif()
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
@@ -62,15 +72,22 @@ if (WITH_WINDOWS_UTF8_FILENAMES)
|
||||
endif()
|
||||
# third-party/folly is only validated to work on Linux and Windows for now.
|
||||
# So only turn it on there by default.
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
option(WITH_FOLLY_DISTRIBUTED_MUTEX "build with folly::DistributedMutex" ON)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux|Windows")
|
||||
if(MSVC AND MSVC_VERSION LESS 1910)
|
||||
# Folly does not compile with MSVC older than VS2017
|
||||
option(WITH_FOLLY_DISTRIBUTED_MUTEX "build with folly::DistributedMutex" OFF)
|
||||
else()
|
||||
option(WITH_FOLLY_DISTRIBUTED_MUTEX "build with folly::DistributedMutex" ON)
|
||||
endif()
|
||||
else()
|
||||
option(WITH_FOLLY_DISTRIBUTED_MUTEX "build with folly::DistributedMutex" OFF)
|
||||
endif()
|
||||
|
||||
include(CMakeDependentOption)
|
||||
CMAKE_DEPENDENT_OPTION(WITH_GFLAGS "build with GFlags" ON
|
||||
"NOT MSVC;NOT MINGW" OFF)
|
||||
|
||||
if(MSVC)
|
||||
# Defaults currently different for GFLAGS.
|
||||
# We will address find_package work a little later
|
||||
option(WITH_GFLAGS "build with GFlags" OFF)
|
||||
option(WITH_XPRESS "build with windows built in compression" OFF)
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc)
|
||||
else()
|
||||
@@ -87,14 +104,11 @@ else()
|
||||
endif()
|
||||
|
||||
# No config file for this
|
||||
option(WITH_GFLAGS "build with GFlags" ON)
|
||||
if(WITH_GFLAGS)
|
||||
find_package(gflags)
|
||||
if(gflags_FOUND)
|
||||
add_definitions(-DGFLAGS=1)
|
||||
include_directories(${gflags_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS ${gflags_LIBRARIES})
|
||||
endif()
|
||||
find_package(gflags REQUIRED)
|
||||
add_definitions(-DGFLAGS=1)
|
||||
include_directories(${gflags_INCLUDE_DIR})
|
||||
list(APPEND THIRDPARTY_LIBS gflags::gflags)
|
||||
endif()
|
||||
|
||||
if(WITH_SNAPPY)
|
||||
@@ -174,7 +188,7 @@ else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wextra -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare -Wshadow -Wno-unused-parameter -Wno-unused-variable -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers -Wno-strict-aliasing")
|
||||
if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format -fno-asynchronous-unwind-tables")
|
||||
add_definitions(-D_POSIX_C_SOURCE=1)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
@@ -189,16 +203,25 @@ else()
|
||||
endif()
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
CHECK_C_COMPILER_FLAG("-mcpu=power9" HAS_POWER9)
|
||||
if(HAS_POWER9)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=power9 -mtune=power9")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=power9 -mtune=power9")
|
||||
else()
|
||||
CHECK_C_COMPILER_FLAG("-mcpu=power8" HAS_POWER8)
|
||||
if(HAS_POWER8)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=power8 -mtune=power8")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=power8 -mtune=power8")
|
||||
endif(HAS_POWER8)
|
||||
endif(HAS_POWER9)
|
||||
CHECK_C_COMPILER_FLAG("-maltivec" HAS_ALTIVEC)
|
||||
if(HAS_ALTIVEC)
|
||||
message(STATUS " HAS_ALTIVEC yes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maltivec")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maltivec")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=power8")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=power8")
|
||||
endif(HAS_ALTIVEC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
|
||||
CHECK_C_COMPILER_FLAG("-march=armv8-a+crc+crypto" HAS_ARMV8_CRC)
|
||||
@@ -221,7 +244,7 @@ else()
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
|
||||
else()
|
||||
if(NOT HAVE_POWER8 AND NOT HAS_ARMV8_CRC)
|
||||
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64" AND NOT HAS_ARMV8_CRC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
|
||||
endif()
|
||||
endif()
|
||||
@@ -467,6 +490,11 @@ if(HAVE_SCHED_GETCPU)
|
||||
add_definitions(-DROCKSDB_SCHED_GETCPU_PRESENT)
|
||||
endif()
|
||||
|
||||
check_cxx_symbol_exists(getauxval auvx.h HAVE_AUXV_GETAUXVAL)
|
||||
if(HAVE_AUXV_GETAUXVAL)
|
||||
add_definitions(-DROCKSDB_AUXV_GETAUXVAL_PRESENT)
|
||||
endif()
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/third-party/gtest-1.8.1/fused-src)
|
||||
@@ -482,6 +510,8 @@ set(SOURCES
|
||||
cache/lru_cache.cc
|
||||
cache/sharded_cache.cc
|
||||
db/arena_wrapped_db_iter.cc
|
||||
db/blob/blob_file_addition.cc
|
||||
db/blob/blob_file_garbage.cc
|
||||
db/builder.cc
|
||||
db/c.cc
|
||||
db/column_family.cc
|
||||
@@ -545,6 +575,7 @@ set(SOURCES
|
||||
env/env_chroot.cc
|
||||
env/env_encryption.cc
|
||||
env/env_hdfs.cc
|
||||
env/file_system.cc
|
||||
env/mock_env.cc
|
||||
file/delete_scheduler.cc
|
||||
file/file_prefetch_buffer.cc
|
||||
@@ -589,20 +620,30 @@ set(SOURCES
|
||||
options/options_sanity_check.cc
|
||||
port/stack_trace.cc
|
||||
table/adaptive/adaptive_table_factory.cc
|
||||
table/block_based/binary_search_index_reader.cc
|
||||
table/block_based/block.cc
|
||||
table/block_based/block_based_filter_block.cc
|
||||
table/block_based/block_based_table_builder.cc
|
||||
table/block_based/block_based_table_factory.cc
|
||||
table/block_based/block_based_table_iterator.cc
|
||||
table/block_based/block_based_table_reader.cc
|
||||
table/block_based/block_builder.cc
|
||||
table/block_based/block_prefetcher.cc
|
||||
table/block_based/block_prefix_index.cc
|
||||
table/block_based/data_block_hash_index.cc
|
||||
table/block_based/data_block_footer.cc
|
||||
table/block_based/filter_block_reader_common.cc
|
||||
table/block_based/filter_policy.cc
|
||||
table/block_based/flush_block_policy.cc
|
||||
table/block_based/full_filter_block.cc
|
||||
table/block_based/hash_index_reader.cc
|
||||
table/block_based/index_builder.cc
|
||||
table/block_based/index_reader_common.cc
|
||||
table/block_based/parsed_full_filter_block.cc
|
||||
table/block_based/partitioned_filter_block.cc
|
||||
table/block_based/partitioned_index_iterator.cc
|
||||
table/block_based/partitioned_index_reader.cc
|
||||
table/block_based/reader_common.cc
|
||||
table/block_based/uncompression_dict_reader.cc
|
||||
table/block_fetcher.cc
|
||||
table/cuckoo/cuckoo_table_builder.cc
|
||||
@@ -629,7 +670,6 @@ set(SOURCES
|
||||
test_util/testutil.cc
|
||||
test_util/transaction_test_util.cc
|
||||
tools/block_cache_analyzer/block_cache_trace_analyzer.cc
|
||||
tools/db_bench_tool.cc
|
||||
tools/dump/db_dump_tool.cc
|
||||
tools/ldb_cmd.cc
|
||||
tools/ldb_tool.cc
|
||||
@@ -637,7 +677,6 @@ set(SOURCES
|
||||
tools/trace_analyzer_tool.cc
|
||||
trace_replay/trace_replay.cc
|
||||
trace_replay/block_cache_tracer.cc
|
||||
util/bloom.cc
|
||||
util/coding.cc
|
||||
util/compaction_job_stats_impl.cc
|
||||
util/comparator.cc
|
||||
@@ -645,12 +684,12 @@ set(SOURCES
|
||||
util/concurrent_task_limiter_impl.cc
|
||||
util/crc32c.cc
|
||||
util/dynamic_bloom.cc
|
||||
util/filter_policy.cc
|
||||
util/hash.cc
|
||||
util/murmurhash.cc
|
||||
util/random.cc
|
||||
util/rate_limiter.cc
|
||||
util/slice.cc
|
||||
util/file_checksum_helper.cc
|
||||
util/status.cc
|
||||
util/string_util.cc
|
||||
util/thread_local.cc
|
||||
@@ -719,11 +758,11 @@ if(HAVE_SSE42 AND NOT MSVC)
|
||||
PROPERTIES COMPILE_FLAGS "-msse4.2 -mpclmul")
|
||||
endif()
|
||||
|
||||
if(HAVE_POWER8)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
list(APPEND SOURCES
|
||||
util/crc32c_ppc.c
|
||||
util/crc32c_ppc_asm.S)
|
||||
endif(HAVE_POWER8)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64")
|
||||
|
||||
if(HAS_ARMV8_CRC)
|
||||
list(APPEND SOURCES
|
||||
@@ -753,6 +792,7 @@ else()
|
||||
list(APPEND SOURCES
|
||||
port/port_posix.cc
|
||||
env/env_posix.cc
|
||||
env/fs_posix.cc
|
||||
env/io_posix.cc)
|
||||
endif()
|
||||
|
||||
@@ -767,7 +807,8 @@ endif()
|
||||
|
||||
set(ROCKSDB_STATIC_LIB rocksdb${ARTIFACT_SUFFIX})
|
||||
set(ROCKSDB_SHARED_LIB rocksdb-shared${ARTIFACT_SUFFIX})
|
||||
set(ROCKSDB_IMPORT_LIB ${ROCKSDB_SHARED_LIB})
|
||||
|
||||
option(ROCKSDB_BUILD_SHARED "Build shared versions of the RocksDB libraries" ON)
|
||||
|
||||
option(WITH_LIBRADOS "Build with librados" OFF)
|
||||
if(WITH_LIBRADOS)
|
||||
@@ -777,41 +818,45 @@ if(WITH_LIBRADOS)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(SYSTEM_LIBS ${SYSTEM_LIBS} Shlwapi.lib Rpcrt4.lib)
|
||||
set(LIBS ${ROCKSDB_STATIC_LIB} ${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
set(SYSTEM_LIBS ${SYSTEM_LIBS} shlwapi.lib rpcrt4.lib)
|
||||
else()
|
||||
set(SYSTEM_LIBS ${CMAKE_THREAD_LIBS_INIT})
|
||||
set(LIBS ${ROCKSDB_SHARED_LIB} ${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
|
||||
add_library(${ROCKSDB_SHARED_LIB} SHARED ${SOURCES})
|
||||
target_link_libraries(${ROCKSDB_SHARED_LIB}
|
||||
${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
set_target_properties(${ROCKSDB_SHARED_LIB} PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
VERSION ${rocksdb_VERSION}
|
||||
SOVERSION ${rocksdb_VERSION_MAJOR}
|
||||
CXX_STANDARD 11
|
||||
OUTPUT_NAME "rocksdb")
|
||||
endif()
|
||||
|
||||
add_library(${ROCKSDB_STATIC_LIB} STATIC ${SOURCES})
|
||||
target_link_libraries(${ROCKSDB_STATIC_LIB}
|
||||
${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
|
||||
if(WIN32)
|
||||
add_library(${ROCKSDB_IMPORT_LIB} SHARED ${SOURCES})
|
||||
target_link_libraries(${ROCKSDB_IMPORT_LIB}
|
||||
if(ROCKSDB_BUILD_SHARED)
|
||||
add_library(${ROCKSDB_SHARED_LIB} SHARED ${SOURCES})
|
||||
target_link_libraries(${ROCKSDB_SHARED_LIB}
|
||||
${THIRDPARTY_LIBS} ${SYSTEM_LIBS})
|
||||
set_target_properties(${ROCKSDB_IMPORT_LIB} PROPERTIES
|
||||
COMPILE_DEFINITIONS "ROCKSDB_DLL;ROCKSDB_LIBRARY_EXPORTS")
|
||||
if(MSVC)
|
||||
set_target_properties(${ROCKSDB_STATIC_LIB} PROPERTIES
|
||||
COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/${ROCKSDB_STATIC_LIB}.pdb")
|
||||
set_target_properties(${ROCKSDB_IMPORT_LIB} PROPERTIES
|
||||
COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/${ROCKSDB_IMPORT_LIB}.pdb")
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(${ROCKSDB_SHARED_LIB} PROPERTIES
|
||||
COMPILE_DEFINITIONS "ROCKSDB_DLL;ROCKSDB_LIBRARY_EXPORTS")
|
||||
if(MSVC)
|
||||
set_target_properties(${ROCKSDB_STATIC_LIB} PROPERTIES
|
||||
COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/${ROCKSDB_STATIC_LIB}.pdb")
|
||||
set_target_properties(${ROCKSDB_SHARED_LIB} PROPERTIES
|
||||
COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/${ROCKSDB_SHARED_LIB}.pdb")
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(${ROCKSDB_SHARED_LIB} PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
VERSION ${rocksdb_VERSION}
|
||||
SOVERSION ${rocksdb_VERSION_MAJOR}
|
||||
CXX_STANDARD 11
|
||||
OUTPUT_NAME "rocksdb")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ROCKSDB_BUILD_SHARED AND NOT WIN32)
|
||||
set(ROCKSDB_LIB ${ROCKSDB_SHARED_LIB})
|
||||
else()
|
||||
set(ROCKSDB_LIB ${ROCKSDB_STATIC_LIB})
|
||||
endif()
|
||||
|
||||
option(WITH_JNI "build with JNI" OFF)
|
||||
if(WITH_JNI OR JNI)
|
||||
message(STATUS "JNI library is enabled")
|
||||
@@ -858,15 +903,17 @@ if(NOT WIN32 OR ROCKSDB_INSTALL_ON_WINDOWS)
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${ROCKSDB_SHARED_LIB}
|
||||
EXPORT RocksDBTargets
|
||||
COMPONENT runtime
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
if(ROCKSDB_BUILD_SHARED)
|
||||
install(
|
||||
TARGETS ${ROCKSDB_SHARED_LIB}
|
||||
EXPORT RocksDBTargets
|
||||
COMPONENT runtime
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
EXPORT RocksDBTargets
|
||||
@@ -884,12 +931,21 @@ if(NOT WIN32 OR ROCKSDB_INSTALL_ON_WINDOWS)
|
||||
)
|
||||
endif()
|
||||
|
||||
option(WITH_TESTS "build with tests" ON)
|
||||
# Tests are excluded from Release builds
|
||||
CMAKE_DEPENDENT_OPTION(WITH_TESTS "build with tests" ON
|
||||
"CMAKE_BUILD_TYPE STREQUAL Debug" OFF)
|
||||
if(WITH_TESTS)
|
||||
add_subdirectory(third-party/gtest-1.8.1/fused-src/gtest)
|
||||
add_library(testharness STATIC
|
||||
test_util/testharness.cc)
|
||||
target_link_libraries(testharness gtest)
|
||||
|
||||
set(TESTS
|
||||
cache/cache_test.cc
|
||||
cache/lru_cache_test.cc
|
||||
db/blob/blob_file_addition_test.cc
|
||||
db/blob/blob_file_garbage_test.cc
|
||||
db/blob/db_blob_index_test.cc
|
||||
db/column_family_test.cc
|
||||
db/compact_files_test.cc
|
||||
db/compaction/compaction_job_stats_test.cc
|
||||
@@ -900,7 +956,7 @@ if(WITH_TESTS)
|
||||
db/corruption_test.cc
|
||||
db/cuckoo_table_db_test.cc
|
||||
db/db_basic_test.cc
|
||||
db/db_blob_index_test.cc
|
||||
db/db_with_timestamp_basic_test.cc
|
||||
db/db_block_cache_test.cc
|
||||
db/db_bloom_filter_test.cc
|
||||
db/db_compaction_filter_test.cc
|
||||
@@ -926,12 +982,13 @@ if(WITH_TESTS)
|
||||
db/db_tailing_iter_test.cc
|
||||
db/db_test.cc
|
||||
db/db_test2.cc
|
||||
db/db_logical_block_size_cache_test.cc
|
||||
db/db_universal_compaction_test.cc
|
||||
db/db_wal_test.cc
|
||||
db/db_write_test.cc
|
||||
db/dbformat_test.cc
|
||||
db/deletefile_test.cc
|
||||
db/error_handler_test.cc
|
||||
db/error_handler_fs_test.cc
|
||||
db/obsolete_files_test.cc
|
||||
db/external_sst_file_basic_test.cc
|
||||
db/external_sst_file_test.cc
|
||||
@@ -962,6 +1019,7 @@ if(WITH_TESTS)
|
||||
db/write_controller_test.cc
|
||||
env/env_basic_test.cc
|
||||
env/env_test.cc
|
||||
env/io_posix_test.cc
|
||||
env/mock_env_test.cc
|
||||
file/delete_scheduler_test.cc
|
||||
logging/auto_roll_logger_test.cc
|
||||
@@ -997,13 +1055,16 @@ if(WITH_TESTS)
|
||||
util/bloom_test.cc
|
||||
util/coding_test.cc
|
||||
util/crc32c_test.cc
|
||||
util/defer_test.cc
|
||||
util/dynamic_bloom_test.cc
|
||||
util/file_reader_writer_test.cc
|
||||
util/filelock_test.cc
|
||||
util/hash_test.cc
|
||||
util/heap_test.cc
|
||||
util/random_test.cc
|
||||
util/rate_limiter_test.cc
|
||||
util/repeatable_thread_test.cc
|
||||
util/slice_test.cc
|
||||
util/slice_transform_test.cc
|
||||
util/timer_queue_test.cc
|
||||
util/thread_list_test.cc
|
||||
@@ -1040,36 +1101,19 @@ if(WITH_TESTS)
|
||||
list(APPEND TESTS third-party/folly/folly/synchronization/test/DistributedMutexTest.cpp)
|
||||
endif()
|
||||
|
||||
set(BENCHMARKS
|
||||
cache/cache_bench.cc
|
||||
memtable/memtablerep_bench.cc
|
||||
db/range_del_aggregator_bench.cc
|
||||
tools/db_bench.cc
|
||||
table/table_reader_bench.cc
|
||||
util/filter_bench.cc
|
||||
utilities/persistent_cache/hash_table_bench.cc)
|
||||
add_library(testharness OBJECT test_util/testharness.cc)
|
||||
foreach(sourcefile ${BENCHMARKS})
|
||||
get_filename_component(exename ${sourcefile} NAME_WE)
|
||||
add_executable(${exename}${ARTIFACT_SUFFIX} ${sourcefile}
|
||||
$<TARGET_OBJECTS:testharness>)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} gtest ${LIBS})
|
||||
endforeach(sourcefile ${BENCHMARKS})
|
||||
|
||||
# For test util library that is build only in DEBUG mode
|
||||
# and linked to tests. Add test only code that is not #ifdefed for Release here.
|
||||
set(TESTUTIL_SOURCE
|
||||
db/db_test_util.cc
|
||||
monitoring/thread_status_updater_debug.cc
|
||||
table/mock_table.cc
|
||||
test_util/fault_injection_test_env.cc
|
||||
test_util/fault_injection_test_fs.cc
|
||||
utilities/cassandra/test_utils.cc
|
||||
)
|
||||
# test utilities are only build in debug
|
||||
enable_testing()
|
||||
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
|
||||
set(TESTUTILLIB testutillib${ARTIFACT_SUFFIX})
|
||||
add_library(${TESTUTILLIB} STATIC ${TESTUTIL_SOURCE})
|
||||
target_link_libraries(${TESTUTILLIB} ${ROCKSDB_LIB})
|
||||
if(MSVC)
|
||||
set_target_properties(${TESTUTILLIB} PROPERTIES COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/testutillib${ARTIFACT_SUFFIX}.pdb")
|
||||
endif()
|
||||
@@ -1079,46 +1123,92 @@ if(WITH_TESTS)
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
|
||||
# Tests are excluded from Release builds
|
||||
set(TEST_EXES ${TESTS})
|
||||
|
||||
foreach(sourcefile ${TEST_EXES})
|
||||
foreach(sourcefile ${TESTS})
|
||||
get_filename_component(exename ${sourcefile} NAME_WE)
|
||||
add_executable(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX} ${sourcefile}
|
||||
$<TARGET_OBJECTS:testharness>)
|
||||
add_executable(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX} ${sourcefile})
|
||||
set_target_properties(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
OUTPUT_NAME ${exename}${ARTIFACT_SUFFIX}
|
||||
)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX} testutillib${ARTIFACT_SUFFIX} gtest ${LIBS})
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX} testutillib${ARTIFACT_SUFFIX} testharness gtest ${ROCKSDB_LIB})
|
||||
if(NOT "${exename}" MATCHES "db_sanity_test")
|
||||
add_test(NAME ${exename} COMMAND ${exename}${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check ${CMAKE_PROJECT_NAME}_${exename}${ARTIFACT_SUFFIX})
|
||||
endif()
|
||||
endforeach(sourcefile ${TEST_EXES})
|
||||
endforeach(sourcefile ${TESTS})
|
||||
|
||||
# C executables must link to a shared object
|
||||
set(C_TESTS db/c_test.c)
|
||||
set(C_TEST_EXES ${C_TESTS})
|
||||
if(WIN32)
|
||||
# C executables must link to a shared object
|
||||
if(ROCKSDB_BUILD_SHARED)
|
||||
set(ROCKSDB_LIB_FOR_C ${ROCKSDB_SHARED_LIB})
|
||||
else()
|
||||
set(ROCKSDB_LIB_FOR_C OFF)
|
||||
endif()
|
||||
else()
|
||||
set(ROCKSDB_LIB_FOR_C ${ROCKSDB_LIB})
|
||||
endif()
|
||||
|
||||
foreach(sourcefile ${C_TEST_EXES})
|
||||
string(REPLACE ".c" "" exename ${sourcefile})
|
||||
string(REGEX REPLACE "^((.+)/)+" "" exename ${exename})
|
||||
add_executable(${exename}${ARTIFACT_SUFFIX} ${sourcefile})
|
||||
set_target_properties(${exename}${ARTIFACT_SUFFIX}
|
||||
PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD_RELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_MINRELEASE 1
|
||||
EXCLUDE_FROM_DEFAULT_BUILD_RELWITHDEBINFO 1
|
||||
)
|
||||
target_link_libraries(${exename}${ARTIFACT_SUFFIX} ${ROCKSDB_IMPORT_LIB} testutillib${ARTIFACT_SUFFIX})
|
||||
add_test(NAME ${exename} COMMAND ${exename}${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check ${exename}${ARTIFACT_SUFFIX})
|
||||
endforeach(sourcefile ${C_TEST_EXES})
|
||||
if(ROCKSDB_LIB_FOR_C)
|
||||
set(C_TESTS db/c_test.c)
|
||||
# C executables must link to a shared object
|
||||
add_executable(c_test db/c_test.c)
|
||||
target_link_libraries(c_test ${ROCKSDB_SHARED_LIB} testharness)
|
||||
add_test(NAME c_test COMMAND c_test${ARTIFACT_SUFFIX})
|
||||
add_dependencies(check c_test)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(WITH_BENCHMARK_TOOLS "build with benchmarks" ON)
|
||||
if(WITH_BENCHMARK_TOOLS)
|
||||
add_executable(db_bench
|
||||
tools/db_bench.cc
|
||||
tools/db_bench_tool.cc)
|
||||
target_link_libraries(db_bench
|
||||
${ROCKSDB_LIB})
|
||||
|
||||
add_executable(cache_bench
|
||||
cache/cache_bench.cc)
|
||||
target_link_libraries(cache_bench
|
||||
${ROCKSDB_LIB})
|
||||
|
||||
add_executable(memtablerep_bench
|
||||
memtable/memtablerep_bench.cc)
|
||||
target_link_libraries(memtablerep_bench
|
||||
${ROCKSDB_LIB})
|
||||
|
||||
add_executable(range_del_aggregator_bench
|
||||
db/range_del_aggregator_bench.cc)
|
||||
target_link_libraries(range_del_aggregator_bench
|
||||
${ROCKSDB_LIB})
|
||||
|
||||
add_executable(table_reader_bench
|
||||
table/table_reader_bench.cc)
|
||||
target_link_libraries(table_reader_bench
|
||||
${ROCKSDB_LIB} testharness)
|
||||
|
||||
add_executable(filter_bench
|
||||
util/filter_bench.cc)
|
||||
target_link_libraries(filter_bench
|
||||
${ROCKSDB_LIB})
|
||||
|
||||
add_executable(hash_table_bench
|
||||
utilities/persistent_cache/hash_table_bench.cc)
|
||||
target_link_libraries(hash_table_bench
|
||||
${ROCKSDB_LIB})
|
||||
endif()
|
||||
|
||||
option(WITH_CORE_TOOLS "build with ldb and sst_dump" ON)
|
||||
option(WITH_TOOLS "build with tools" ON)
|
||||
if(WITH_TOOLS)
|
||||
if(WITH_CORE_TOOLS OR WITH_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
add_custom_target(core_tools
|
||||
DEPENDS ${core_tool_deps})
|
||||
endif()
|
||||
|
||||
if(WITH_TOOLS)
|
||||
add_subdirectory(db_stress_tool)
|
||||
add_custom_target(tools
|
||||
DEPENDS ${tool_deps})
|
||||
endif()
|
||||
+157
-18
@@ -1,35 +1,174 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
### Public API Change
|
||||
* Fix spelling so that API now has correctly spelled transaction state name `COMMITTED`, while the old misspelled `COMMITED` is still available as an alias.
|
||||
|
||||
### Bug Fixes
|
||||
* Fixed a number of data races in BlobDB.
|
||||
* Fix a bug where the compaction snapshot refresh feature is not disabled as advertised when `snap_refresh_nanos` is set to 0..
|
||||
* Fix bloom filter lookups by the MultiGet batching API when BlockBasedTableOptions::whole_key_filtering is false, by checking that a key is in the perfix_extractor domain and extracting the prefix before looking up.
|
||||
* Fix a bug in file ingestion caused by incorrect file number allocation when the number of column families involved in the ingestion exceeds 2.
|
||||
* Fix a bug when format_version=3, partitioned fitlers, and prefix search are used in conjunction. The bug could result into Seek::(prefix) returning NotFound for an existing prefix.
|
||||
* Fix a bug where range tombstone blocks in ingested files were cached incorrectly during ingestion. If range tombstones were read from those incorrectly cached blocks, the keys they covered would be exposed.
|
||||
* Fix a data race that might cause crash when calling DB::GetCreationTimeOfOldestFile() by a small chance. The bug was introduced in 6.6 Release.
|
||||
|
||||
### Performance Improvements
|
||||
* In CompactRange, for levels starting from 0, if the level does not have any file with any key falling in the specified range, the level is skipped. So instead of always compacting from level 0, the compaction starts from the first level with keys in the specified range until the last such level.
|
||||
|
||||
### New Features
|
||||
* Basic support for user timestamp in iterator. Seek/SeekToFirst/Next and lower/upper bounds are supported. Reverse iteration is not supported. Merge is not considered.
|
||||
* When file lock failure when the lock is held by the current process, return acquiring time and thread ID in the error message.
|
||||
|
||||
## 6.8.0 (02/24/2020)
|
||||
### Java API Changes
|
||||
* Major breaking changes to Java comparators, toward standardizing on ByteBuffer for performant, locale-neutral operations on keys (#6252).
|
||||
* Added overloads of common API methods using direct ByteBuffers for keys and values (#2283).
|
||||
|
||||
### Bug Fixes
|
||||
* Fix incorrect results while block-based table uses kHashSearch, together with Prev()/SeekForPrev().
|
||||
* Fix a bug that prevents opening a DB after two consecutive crash with TransactionDB, where the first crash recovers from a corrupted WAL with kPointInTimeRecovery but the second cannot.
|
||||
* Fixed issue #6316 that can cause a corruption of the MANIFEST file in the middle when writing to it fails due to no disk space.
|
||||
* Add DBOptions::skip_checking_sst_file_sizes_on_db_open. It disables potentially expensive checking of all sst file sizes in DB::Open().
|
||||
* BlobDB now ignores trivially moved files when updating the mapping between blob files and SSTs. This should mitigate issue #6338 where out of order flush/compaction notifications could trigger an assertion with the earlier code.
|
||||
* Batched MultiGet() ignores IO errors while reading data blocks, causing it to potentially continue looking for a key and returning stale results.
|
||||
* `WriteBatchWithIndex::DeleteRange` returns `Status::NotSupported`. Previously it returned success even though reads on the batch did not account for range tombstones. The corresponding language bindings now cannot be used. In C, that includes `rocksdb_writebatch_wi_delete_range`, `rocksdb_writebatch_wi_delete_range_cf`, `rocksdb_writebatch_wi_delete_rangev`, and `rocksdb_writebatch_wi_delete_rangev_cf`. In Java, that includes `WriteBatchWithIndex::deleteRange`.
|
||||
* Assign new MANIFEST file number when caller tries to create a new MANIFEST by calling LogAndApply(..., new_descriptor_log=true). This bug can cause MANIFEST being overwritten during recovery if options.write_dbid_to_manifest = true and there are WAL file(s).
|
||||
|
||||
### Performance Improvements
|
||||
* Perfom readahead when reading from option files. Inside DB, options.log_readahead_size will be used as the readahead size. In other cases, a default 512KB is used.
|
||||
|
||||
### Public API Change
|
||||
* The BlobDB garbage collector now emits the statistics `BLOB_DB_GC_NUM_FILES` (number of blob files obsoleted during GC), `BLOB_DB_GC_NUM_NEW_FILES` (number of new blob files generated during GC), `BLOB_DB_GC_FAILURES` (number of failed GC passes), `BLOB_DB_GC_NUM_KEYS_RELOCATED` (number of blobs relocated during GC), and `BLOB_DB_GC_BYTES_RELOCATED` (total size of blobs relocated during GC). On the other hand, the following statistics, which are not relevant for the new GC implementation, are now deprecated: `BLOB_DB_GC_NUM_KEYS_OVERWRITTEN`, `BLOB_DB_GC_NUM_KEYS_EXPIRED`, `BLOB_DB_GC_BYTES_OVERWRITTEN`, `BLOB_DB_GC_BYTES_EXPIRED`, and `BLOB_DB_GC_MICROS`.
|
||||
* Disable recycle_log_file_num when an inconsistent recovery modes are requested: kPointInTimeRecovery and kAbsoluteConsistency
|
||||
|
||||
### New Features
|
||||
* Added the checksum for each SST file generated by Flush or Compaction. Added sst_file_checksum_func to Options such that user can plugin their own SST file checksum function via override the FileChecksumFunc class. If user does not set the sst_file_checksum_func, SST file checksum calculation will not be enabled. The checksum information inlcuding uint32_t checksum value and a checksum function name (string). The checksum information is stored in FileMetadata in version store and also logged to MANIFEST. A new tool is added to LDB such that user can dump out a list of file checksum information from MANIFEST (stored in an unordered_map).
|
||||
* `db_bench` now supports `value_size_distribution_type`, `value_size_min`, `value_size_max` options for generating random variable sized value. Added `blob_db_compression_type` option for BlobDB to enable blob compression.
|
||||
* Replace RocksDB namespace "rocksdb" with flag "ROCKSDB_NAMESPACE" which if is not defined, defined as "rocksdb" in header file rocksdb_namespace.h.
|
||||
|
||||
## 6.7.0 (01/21/2020)
|
||||
### Public API Change
|
||||
* Added a rocksdb::FileSystem class in include/rocksdb/file_system.h to encapsulate file creation/read/write operations, and an option DBOptions::file_system to allow a user to pass in an instance of rocksdb::FileSystem. If its a non-null value, this will take precendence over DBOptions::env for file operations. A new API rocksdb::FileSystem::Default() returns a platform default object. The DBOptions::env option and Env::Default() API will continue to be used for threading and other OS related functions, and where DBOptions::file_system is not specified, for file operations. For storage developers who are accustomed to rocksdb::Env, the interface in rocksdb::FileSystem is new and will probably undergo some changes as more storage systems are ported to it from rocksdb::Env. As of now, no env other than Posix has been ported to the new interface.
|
||||
* A new rocksdb::NewSstFileManager() API that allows the caller to pass in separate Env and FileSystem objects.
|
||||
* Changed Java API for RocksDB.keyMayExist functions to use Holder<byte[]> instead of StringBuilder, so that retrieved values need not decode to Strings.
|
||||
* A new `OptimisticTransactionDBOptions` Option that allows users to configure occ validation policy. The default policy changes from kValidateSerial to kValidateParallel to reduce mutex contention.
|
||||
|
||||
### Bug Fixes
|
||||
* Fix a bug that can cause unnecessary bg thread to be scheduled(#6104).
|
||||
* Fix crash caused by concurrent CF iterations and drops(#6147).
|
||||
* Fix a race condition for cfd->log_number_ between manifest switch and memtable switch (PR 6249) when number of column families is greater than 1.
|
||||
* Fix a bug on fractional cascading index when multiple files at the same level contain the same smallest user key, and those user keys are for merge operands. In this case, Get() the exact key may miss some merge operands.
|
||||
* Delcare kHashSearch index type feature-incompatible with index_block_restart_interval larger than 1.
|
||||
* Fixed an issue where the thread pools were not resized upon setting `max_background_jobs` dynamically through the `SetDBOptions` interface.
|
||||
* Fix a bug that can cause write threads to hang when a slowdown/stall happens and there is a mix of writers with WriteOptions::no_slowdown set/unset.
|
||||
* Fixed an issue where an incorrect "number of input records" value was used to compute the "records dropped" statistics for compactions.
|
||||
* Fix a regression bug that causes segfault when hash is used, max_open_files != -1 and total order seek is used and switched back.
|
||||
|
||||
### New Features
|
||||
* It is now possible to enable periodic compactions for the base DB when using BlobDB.
|
||||
* BlobDB now garbage collects non-TTL blobs when `enable_garbage_collection` is set to `true` in `BlobDBOptions`. Garbage collection is performed during compaction: any valid blobs located in the oldest N files (where N is the number of non-TTL blob files multiplied by the value of `BlobDBOptions::garbage_collection_cutoff`) encountered during compaction get relocated to new blob files, and old blob files are dropped once they are no longer needed. Note: we recommend enabling periodic compactions for the base DB when using this feature to deal with the case when some old blob files are kept alive by SSTs that otherwise do not get picked for compaction.
|
||||
* `db_bench` now supports the `garbage_collection_cutoff` option for BlobDB.
|
||||
* Introduce ReadOptions.auto_prefix_mode. When set to true, iterator will return the same result as total order seek, but may choose to use prefix seek internally based on seek key and iterator upper bound.
|
||||
* MultiGet() can use IO Uring to parallelize read from the same SST file. This featuer is by default disabled. It can be enabled with environment variable ROCKSDB_USE_IO_URING.
|
||||
|
||||
## 6.6.2 (01/13/2020)
|
||||
### Bug Fixes
|
||||
* Fixed a bug where non-L0 compaction input files were not considered to compute the `creation_time` of new compaction outputs.
|
||||
|
||||
## 6.6.1 (01/02/2020)
|
||||
### Bug Fixes
|
||||
* Fix a bug in WriteBatchWithIndex::MultiGetFromBatchAndDB, which is called by Transaction::MultiGet, that causes due to stale pointer access when the number of keys is > 32
|
||||
* Fixed two performance issues related to memtable history trimming. First, a new SuperVersion is now created only if some memtables were actually trimmed. Second, trimming is only scheduled if there is at least one flushed memtable that is kept in memory for the purposes of transaction conflict checking.
|
||||
* BlobDB no longer updates the SST to blob file mapping upon failed compactions.
|
||||
* Fix a bug in which a snapshot read through an iterator could be affected by a DeleteRange after the snapshot (#6062).
|
||||
* Fixed a bug where BlobDB was comparing the `ColumnFamilyHandle` pointers themselves instead of only the column family IDs when checking whether an API call uses the default column family or not.
|
||||
* Delete superversions in BackgroundCallPurge.
|
||||
* Fix use-after-free and double-deleting files in BackgroundCallPurge().
|
||||
|
||||
## 6.6.0 (11/25/2019)
|
||||
### Bug Fixes
|
||||
* Fix data corruption caused by output of intra-L0 compaction on ingested file not being placed in correct order in L0.
|
||||
* Fix a data race between Version::GetColumnFamilyMetaData() and Compaction::MarkFilesBeingCompacted() for access to being_compacted (#6056). The current fix acquires the db mutex during Version::GetColumnFamilyMetaData(), which may cause regression.
|
||||
* Fix a bug in DBIter that is_blob_ state isn't updated when iterating backward using seek.
|
||||
* Fix a bug when format_version=3, partitioned filters, and prefix search are used in conjunction. The bug could result into Seek::(prefix) returning NotFound for an existing prefix.
|
||||
* Revert the feature "Merging iterator to avoid child iterator reseek for some cases (#5286)" since it might cause strong results when reseek happens with a different iterator upper bound.
|
||||
* Fix a bug causing a crash during ingest external file when background compaction cause severe error (file not found).
|
||||
* Fix a bug when partitioned filters and prefix search are used in conjunction, ::SeekForPrev could return invalid for an existing prefix. ::SeekForPrev might be called by the user, or internally on ::Prev, or within ::Seek if the return value involves Delete or a Merge operand.
|
||||
* Fix OnFlushCompleted fired before flush result persisted in MANIFEST when there's concurrent flush job. The bug exists since OnFlushCompleted was introduced in rocksdb 3.8.
|
||||
* Fixed an sst_dump crash on some plain table SST files.
|
||||
* Fixed a memory leak in some error cases of opening plain table SST files.
|
||||
* Fix a bug when a crash happens while calling WriteLevel0TableForRecovery for multiple column families, leading to a column family's log number greater than the first corrutped log number when the DB is being opened in PointInTime recovery mode during next recovery attempt (#5856).
|
||||
|
||||
### New Features
|
||||
* Introduced DBOptions::max_write_batch_group_size_bytes to configure maximum limit on number of bytes that are written in a single batch of WAL or memtable write. It is followed when the leader write size is larger than 1/8 of this limit.
|
||||
* VerifyChecksum() by default will issue readahead. Allow ReadOptions to be passed in to those functions to override the readhead size. For checksum verifying before external SST file ingestion, a new option IngestExternalFileOptions.verify_checksums_readahead_size, is added for this readahead setting.
|
||||
* When user uses options.force_consistency_check in RocksDb, instead of crashing the process, we now pass the error back to the users without killing the process.
|
||||
* Add an option `memtable_insert_hint_per_batch` to WriteOptions. If it is true, each WriteBatch will maintain its own insert hints for each memtable in concurrent write. See include/rocksdb/options.h for more details.
|
||||
* Universal compaction to support options.periodic_compaction_seconds. A full compaction will be triggered if any file is over the threshold.
|
||||
* `GetLiveFilesMetaData` and `GetColumnFamilyMetaData` now expose the file number of SST files as well as the oldest blob file referenced by each SST.
|
||||
* A batched MultiGet API (DB::MultiGet()) that supports retrieving keys from multiple column families.
|
||||
* Full and partitioned filters in the block-based table use an improved Bloom filter implementation, enabled with format_version 5 (or above) because previous releases cannot read this filter. This replacement is faster and more accurate, especially for high bits per key or millions of keys in a single (full) filter. For example, the new Bloom filter has the same false positive rate at 9.55 bits per key as the old one at 10 bits per key, and a lower false positive rate at 16 bits per key than the old one at 100 bits per key.
|
||||
* Added AVX2 instructions to USE_SSE builds to accelerate the new Bloom filter and XXH3-based hash function on compatible x86_64 platforms (Haswell and later, ~2014).
|
||||
* Support options.ttl or options.periodic_compaction_seconds with options.max_open_files = -1. File's oldest ancester time and file creation time will be written to manifest. If it is availalbe, this information will be used instead of creation_time and file_creation_time in table properties.
|
||||
* Setting options.ttl for universal compaction now has the same meaning as setting periodic_compaction_seconds.
|
||||
* SstFileMetaData also returns file creation time and oldest ancester time.
|
||||
* The `sst_dump` command line tool `recompress` command now displays how many blocks were compressed and how many were not, in particular how many were not compressed because the compression ratio was not met (12.5% threshold for GoodCompressionRatio), as seen in the `number.block.not_compressed` counter stat since version 6.0.0.
|
||||
* The block cache usage is now takes into account the overhead of metadata per each entry. This results into more accurate managment of memory. A side-effect of this feature is that less items are fit into the block cache of the same size, which would result to higher cache miss rates. This can be remedied by increasing the block cache size or passing kDontChargeCacheMetadata to its constuctor to restore the old behavior.
|
||||
* The block cache usage is now takes into account the overhead of metadata per each entry. This results into more accurate management of memory. A side-effect of this feature is that less items are fit into the block cache of the same size, which would result to higher cache miss rates. This can be remedied by increasing the block cache size or passing kDontChargeCacheMetadata to its constuctor to restore the old behavior.
|
||||
* When using BlobDB, a mapping is maintained and persisted in the MANIFEST between each SST file and the oldest non-TTL blob file it references.
|
||||
* `db_bench` now supports and by default issues non-TTL Puts to BlobDB. TTL Puts can be enabled by specifying a non-zero value for the `blob_db_max_ttl_range` command line parameter explicitly.
|
||||
* `sst_dump` now supports printing BlobDB blob indexes in a human-readable format. This can be enabled by specifying the `decode_blob_index` flag on the command line.
|
||||
* A number of new information elements are now exposed through the EventListener interface. For flushes, the file numbers of the new SST file and the oldest blob file referenced by the SST are propagated. For compactions, the level, file number, and the oldest blob file referenced are passed to the client for each compaction input and output file.
|
||||
|
||||
### Public API Change
|
||||
* Added max_write_buffer_size_to_maintain option to better control memory usage of immutable memtables.
|
||||
* Added a lightweight API GetCurrentWalFile() to get last live WAL filename and size. Meant to be used as a helper for backup/restore tooling in a larger ecosystem such as MySQL with a MyRocks storage engine.
|
||||
* The MemTable Bloom filter, when enabled, now always uses cache locality. Options::bloom_locality now only affects the PlainTable SST format.
|
||||
* RocksDB release 4.1 or older will not be able to open DB generated by the new release. 4.2 was released on Feb 23, 2016.
|
||||
* TTL Compactions in Level compaction style now initiate successive cascading compactions on a key range so that it reaches the bottom level quickly on TTL expiry. `creation_time` table property for compaction output files is now set to the minimum of the creation times of all compaction inputs.
|
||||
* With FIFO compaction style, options.periodic_compaction_seconds will have the same meaning as options.ttl. Whichever stricter will be used. With the default options.periodic_compaction_seconds value with options.ttl's default of 0, RocksDB will give a default of 30 days.
|
||||
* Added an API GetCreationTimeOfOldestFile(uint64_t* creation_time) to get the file_creation_time of the oldest SST file in the DB.
|
||||
* FilterPolicy now exposes additional API to make it possible to choose filter configurations based on context, such as table level and compaction style. See `LevelAndStyleCustomFilterPolicy` in db_bloom_filter_test.cc. While most existing custom implementations of FilterPolicy should continue to work as before, those wrapping the return of NewBloomFilterPolicy will require overriding new function `GetBuilderWithContext()`, because calling `GetFilterBitsBuilder()` on the FilterPolicy returned by NewBloomFilterPolicy is no longer supported.
|
||||
* An unlikely usage of FilterPolicy is no longer supported. Calling GetFilterBitsBuilder() on the FilterPolicy returned by NewBloomFilterPolicy will now cause an assertion violation in debug builds, because RocksDB has internally migrated to a more elaborate interface that is expected to evolve further. Custom implementations of FilterPolicy should work as before, except those wrapping the return of NewBloomFilterPolicy, which will require a new override of a protected function in FilterPolicy.
|
||||
* NewBloomFilterPolicy now takes bits_per_key as a double instead of an int. This permits finer control over the memory vs. accuracy trade-off in the new Bloom filter implementation and should not change source code compatibility.
|
||||
* The option BackupableDBOptions::max_valid_backups_to_open is now only used when opening BackupEngineReadOnly. When opening a read/write BackupEngine, anything but the default value logs a warning and is treated as the default. This change ensures that backup deletion has proper accounting of shared files to ensure they are deleted when no longer referenced by a backup.
|
||||
* Deprecate `snap_refresh_nanos` option.
|
||||
* Added DisableManualCompaction/EnableManualCompaction to stop and resume manual compaction.
|
||||
* Add TryCatchUpWithPrimary() to StackableDB in non-LITE mode.
|
||||
* Add a new Env::LoadEnv() overloaded function to return a shared_ptr to Env.
|
||||
* Flush sets file name to "(nil)" for OnTableFileCreationCompleted() if the flush does not produce any L0. This can happen if the file is empty thus delete by RocksDB.
|
||||
|
||||
### Default Option Changes
|
||||
* Changed the default value of periodic_compaction_seconds to `UINT64_MAX - 1` which allows RocksDB to auto-tune periodic compaction scheduling. When using the default value, periodic compactions are now auto-enabled if a compaction filter is used. A value of `0` will turn off the feature completely.
|
||||
* Changed the default value of ttl to `UINT64_MAX - 1` which allows RocksDB to auto-tune ttl value. When using the default value, TTL will be auto-enabled to 30 days, when the feature is supported. To revert the old behavior, you can explicitly set it to 0.
|
||||
|
||||
### Performance Improvements
|
||||
* For 64-bit hashing, RocksDB is standardizing on a slightly modified preview version of XXH3. This function is now used for many non-persisted hashes, along with fastrange64() in place of the modulus operator, and some benchmarks show a slight improvement.
|
||||
* Level iterator to invlidate the iterator more often in prefix seek and the level is filtered out by prefix bloom.
|
||||
|
||||
## 6.5.2 (11/15/2019)
|
||||
### Bug Fixes
|
||||
* Fix a assertion failure in MultiGet() when BlockBasedTableOptions::no_block_cache is true and there is no compressed block cache
|
||||
* Fix a buffer overrun problem in BlockBasedTable::MultiGet() when compression is enabled and no compressed block cache is configured.
|
||||
* If a call to BackupEngine::PurgeOldBackups or BackupEngine::DeleteBackup suffered a crash, power failure, or I/O error, files could be left over from old backups that could only be purged with a call to GarbageCollect. Any call to PurgeOldBackups, DeleteBackup, or GarbageCollect should now suffice to purge such files.
|
||||
|
||||
## 6.5.1 (10/16/2019)
|
||||
### Bug Fixes
|
||||
* Revert the feature "Merging iterator to avoid child iterator reseek for some cases (#5286)" since it might cause strange results when reseek happens with a different iterator upper bound.
|
||||
* Fix a bug in BlockBasedTableIterator that might return incorrect results when reseek happens with a different iterator upper bound.
|
||||
* Fix a bug when partitioned filters and prefix search are used in conjunction, ::SeekForPrev could return invalid for an existing prefix. ::SeekForPrev might be called by the user, or internally on ::Prev, or within ::Seek if the return value involves Delete or a Merge operand.
|
||||
|
||||
## 6.5.0 (9/13/2019)
|
||||
### Bug Fixes
|
||||
* Fixed a number of data races in BlobDB.
|
||||
* Fix a bug where the compaction snapshot refresh feature is not disabled as advertised when `snap_refresh_nanos` is set to 0..
|
||||
* Fix bloom filter lookups by the MultiGet batching API when BlockBasedTableOptions::whole_key_filtering is false, by checking that a key is in the perfix_extractor domain and extracting the prefix before looking up.
|
||||
* Fix a bug in file ingestion caused by incorrect file number allocation when the number of column families involved in the ingestion exceeds 2.
|
||||
|
||||
### New Features
|
||||
* Introduced DBOptions::max_write_batch_group_size_bytes to configure maximum limit on number of bytes that are written in a single batch of WAL or memtable write. It is followed when the leader write size is larger than 1/8 of this limit.
|
||||
* VerifyChecksum() by default will issue readahead. Allow ReadOptions to be passed in to those functions to override the readhead size. For checksum verifying before external SST file ingestion, a new option IngestExternalFileOptions.verify_checksums_readahead_size, is added for this readahead setting.
|
||||
* When user uses options.force_consistency_check in RocksDb, instead of crashing the process, we now pass the error back to the users without killing the process.
|
||||
* Add an option `memtable_insert_hint_per_batch` to WriteOptions. If it is true, each WriteBatch will maintain its own insert hints for each memtable in concurrent write. See include/rocksdb/options.h for more details.
|
||||
|
||||
### Public API Change
|
||||
* Added max_write_buffer_size_to_maintain option to better control memory usage of immutable memtables.
|
||||
* Added a lightweight API GetCurrentWalFile() to get last live WAL filename and size. Meant to be used as a helper for backup/restore tooling in a larger ecosystem such as MySQL with a MyRocks storage engine.
|
||||
* The MemTable Bloom filter, when enabled, now always uses cache locality. Options::bloom_locality now only affects the PlainTable SST format.
|
||||
|
||||
### Performance Improvements
|
||||
* Improve the speed of the MemTable Bloom filter, reducing the write overhead of enabling it by 1/3 to 1/2, with similar benefit to read performance.
|
||||
|
||||
## 6.4.0 (7/30/2019)
|
||||
### Default Option Change
|
||||
* LRUCacheOptions.high_pri_pool_ratio is set to 0.5 (previously 0.0) by default, which means that by default midpoint insertion is enabled. The same change is made for the default value of high_pri_pool_ratio argument in NewLRUCache(). When block cache is not explictly created, the small block cache created by BlockBasedTable will still has this option to be 0.0.
|
||||
* LRUCacheOptions.high_pri_pool_ratio is set to 0.5 (previously 0.0) by default, which means that by default midpoint insertion is enabled. The same change is made for the default value of high_pri_pool_ratio argument in NewLRUCache(). When block cache is not explicitly created, the small block cache created by BlockBasedTable will still has this option to be 0.0.
|
||||
* Change BlockBasedTableOptions.cache_index_and_filter_blocks_with_high_priority's default value from false to true.
|
||||
|
||||
### Public API Change
|
||||
@@ -53,7 +192,7 @@
|
||||
* Support loading custom objects in unit tests. In the affected unit tests, RocksDB will create custom Env objects based on environment variable TEST_ENV_URI. Users need to make sure custom object types are properly registered. For example, a static library should expose a `RegisterCustomObjects` function. By linking the unit test binary with the static library, the unit test can execute this function.
|
||||
|
||||
### Performance Improvements
|
||||
* Reduce iterator key comparision for upper/lower bound check.
|
||||
* Reduce iterator key comparison for upper/lower bound check.
|
||||
* Improve performance of row_cache: make reads with newer snapshots than data in an SST file share the same cache key, except in some transaction cases.
|
||||
* The compression dictionary is no longer copied to a new object upon retrieval.
|
||||
|
||||
@@ -149,7 +288,7 @@
|
||||
* Introduce two more stats levels, kExceptHistogramOrTimers and kExceptTimers.
|
||||
* Added a feature to perform data-block sampling for compressibility, and report stats to user.
|
||||
* Add support for trace filtering.
|
||||
* Add DBOptions.avoid_unnecessary_blocking_io. If true, we avoid file deletion when destorying ColumnFamilyHandle and Iterator. Instead, a job is scheduled to delete the files in background.
|
||||
* Add DBOptions.avoid_unnecessary_blocking_io. If true, we avoid file deletion when destroying ColumnFamilyHandle and Iterator. Instead, a job is scheduled to delete the files in background.
|
||||
|
||||
### Public API Change
|
||||
* Remove bundled fbson library.
|
||||
@@ -528,7 +667,7 @@ if set to something > 0 user will see 2 changes in iterators behavior 1) only ke
|
||||
|
||||
## 5.2.0 (02/08/2017)
|
||||
### Public API Change
|
||||
* NewLRUCache() will determine number of shard bits automatically based on capacity, if the user doesn't pass one. This also impacts the default block cache when the user doesn't explict provide one.
|
||||
* NewLRUCache() will determine number of shard bits automatically based on capacity, if the user doesn't pass one. This also impacts the default block cache when the user doesn't explicit provide one.
|
||||
* Change the default of delayed slowdown value to 16MB/s and further increase the L0 stop condition to 36 files.
|
||||
* Options::use_direct_writes and Options::use_direct_reads are now ready to use.
|
||||
* (Experimental) Two-level indexing that partition the index and creates a 2nd level index on the partitions. The feature can be enabled by setting kTwoLevelIndexSearch as IndexType and configuring index_per_partition.
|
||||
@@ -599,7 +738,7 @@ if set to something > 0 user will see 2 changes in iterators behavior 1) only ke
|
||||
|
||||
### New Features
|
||||
* A tool to migrate DB after options change. See include/rocksdb/utilities/option_change_migration.h.
|
||||
* Add ReadOptions.background_purge_on_iterator_cleanup. If true, we avoid file deletion when destorying iterators.
|
||||
* Add ReadOptions.background_purge_on_iterator_cleanup. If true, we avoid file deletion when destroying iterators.
|
||||
|
||||
## 4.10.0 (7/5/2016)
|
||||
### Public API Change
|
||||
|
||||
@@ -207,6 +207,7 @@ AM_LINK = $(AM_V_CCLD)$(CXX) $^ $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS
|
||||
dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; export PORTABLE="$(PORTABLE)"; "$(CURDIR)/build_tools/build_detect_platform" "$(CURDIR)/make_config.mk"))
|
||||
# this file is generated by the previous line to set build flags and sources
|
||||
include make_config.mk
|
||||
export JAVAC_ARGS
|
||||
CLEAN_FILES += make_config.mk
|
||||
|
||||
missing_make_config_paths := $(shell \
|
||||
@@ -216,7 +217,7 @@ missing_make_config_paths := $(shell \
|
||||
done | sort | uniq)
|
||||
|
||||
$(foreach path, $(missing_make_config_paths), \
|
||||
$(warning Warning: $(path) dont exist))
|
||||
$(warning Warning: $(path) does not exist))
|
||||
|
||||
ifeq ($(PLATFORM), OS_AIX)
|
||||
# no debug info
|
||||
@@ -439,10 +440,13 @@ BENCHTOOLOBJECTS = $(BENCH_LIB_SOURCES:.cc=.o) $(LIBOBJECTS) $(TESTUTIL)
|
||||
|
||||
ANALYZETOOLOBJECTS = $(ANALYZER_LIB_SOURCES:.cc=.o)
|
||||
|
||||
STRESSTOOLOBJECTS = $(STRESS_LIB_SOURCES:.cc=.o) $(LIBOBJECTS) $(TESTUTIL)
|
||||
|
||||
EXPOBJECTS = $(LIBOBJECTS) $(TESTUTIL)
|
||||
|
||||
TESTS = \
|
||||
db_basic_test \
|
||||
db_with_timestamp_basic_test \
|
||||
db_encryption_test \
|
||||
db_test2 \
|
||||
external_sst_file_basic_test \
|
||||
@@ -457,7 +461,9 @@ TESTS = \
|
||||
env_basic_test \
|
||||
env_test \
|
||||
env_logger_test \
|
||||
io_posix_test \
|
||||
hash_test \
|
||||
random_test \
|
||||
thread_local_test \
|
||||
rate_limiter_test \
|
||||
perf_context_test \
|
||||
@@ -465,6 +471,7 @@ TESTS = \
|
||||
db_wal_test \
|
||||
db_block_cache_test \
|
||||
db_test \
|
||||
db_logical_block_size_cache_test \
|
||||
db_blob_index_test \
|
||||
db_iter_test \
|
||||
db_iter_stress_test \
|
||||
@@ -489,7 +496,7 @@ TESTS = \
|
||||
db_table_properties_test \
|
||||
db_statistics_test \
|
||||
db_write_test \
|
||||
error_handler_test \
|
||||
error_handler_fs_test \
|
||||
autovector_test \
|
||||
blob_db_test \
|
||||
cleanable_test \
|
||||
@@ -500,6 +507,7 @@ TESTS = \
|
||||
data_block_hash_index_test \
|
||||
cache_test \
|
||||
corruption_test \
|
||||
slice_test \
|
||||
slice_transform_test \
|
||||
dbformat_test \
|
||||
fault_injection_test \
|
||||
@@ -592,6 +600,9 @@ TESTS = \
|
||||
db_secondary_test \
|
||||
block_cache_tracer_test \
|
||||
block_cache_trace_analyzer_test \
|
||||
defer_test \
|
||||
blob_file_addition_test \
|
||||
blob_file_garbage_test \
|
||||
|
||||
ifeq ($(USE_FOLLY_DISTRIBUTED_MUTEX),1)
|
||||
TESTS += folly_synchronization_distributed_mutex_test
|
||||
@@ -662,6 +673,7 @@ endif
|
||||
endif
|
||||
LIBRARY = ${LIBNAME}.a
|
||||
TOOLS_LIBRARY = ${LIBNAME}_tools.a
|
||||
STRESS_LIBRARY = ${LIBNAME}_stress.a
|
||||
|
||||
ROCKSDB_MAJOR = $(shell egrep "ROCKSDB_MAJOR.[0-9]" include/rocksdb/version.h | cut -d ' ' -f 3)
|
||||
ROCKSDB_MINOR = $(shell egrep "ROCKSDB_MINOR.[0-9]" include/rocksdb/version.h | cut -d ' ' -f 3)
|
||||
@@ -740,7 +752,8 @@ endif # PLATFORM_SHARED_EXT
|
||||
release tags tags0 valgrind_check whitebox_crash_test format static_lib shared_lib all \
|
||||
dbg rocksdbjavastatic rocksdbjava install install-static install-shared uninstall \
|
||||
analyze tools tools_lib \
|
||||
blackbox_crash_test_with_atomic_flush whitebox_crash_test_with_atomic_flush
|
||||
blackbox_crash_test_with_atomic_flush whitebox_crash_test_with_atomic_flush \
|
||||
blackbox_crash_test_with_txn whitebox_crash_test_with_txn
|
||||
|
||||
|
||||
all: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(TESTS)
|
||||
@@ -751,6 +764,8 @@ static_lib: $(LIBRARY)
|
||||
|
||||
shared_lib: $(SHARED)
|
||||
|
||||
stress_lib: $(STRESS_LIBRARY)
|
||||
|
||||
tools: $(TOOLS)
|
||||
|
||||
tools_lib: $(TOOLS_LIBRARY)
|
||||
@@ -928,10 +943,11 @@ check: all
|
||||
$(MAKE) T="$$t" TMPD=$(TMPD) check_0; \
|
||||
else \
|
||||
for t in $(TESTS); do \
|
||||
echo "===== Running $$t"; ./$$t || exit 1; done; \
|
||||
echo "===== Running $$t (`date`)"; ./$$t || exit 1; done; \
|
||||
fi
|
||||
rm -rf $(TMPD)
|
||||
ifneq ($(PLATFORM), OS_AIX)
|
||||
python tools/check_all_python.py
|
||||
ifeq ($(filter -DROCKSDB_LITE,$(OPT)),)
|
||||
python tools/ldb_test.py
|
||||
sh tools/rocksdb_dump_test.sh
|
||||
@@ -940,7 +956,7 @@ endif
|
||||
|
||||
# TODO add ldb_tests
|
||||
check_some: $(SUBSET)
|
||||
for t in $(SUBSET); do echo "===== Running $$t"; ./$$t || exit 1; done
|
||||
for t in $(SUBSET); do echo "===== Running $$t (`date`)"; ./$$t || exit 1; done
|
||||
|
||||
.PHONY: ldb_tests
|
||||
ldb_tests: ldb
|
||||
@@ -950,6 +966,8 @@ crash_test: whitebox_crash_test blackbox_crash_test
|
||||
|
||||
crash_test_with_atomic_flush: whitebox_crash_test_with_atomic_flush blackbox_crash_test_with_atomic_flush
|
||||
|
||||
crash_test_with_txn: whitebox_crash_test_with_txn blackbox_crash_test_with_txn
|
||||
|
||||
blackbox_crash_test: db_stress
|
||||
python -u tools/db_crashtest.py --simple blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
python -u tools/db_crashtest.py blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
@@ -957,6 +975,9 @@ blackbox_crash_test: db_stress
|
||||
blackbox_crash_test_with_atomic_flush: db_stress
|
||||
python -u tools/db_crashtest.py --cf_consistency blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
blackbox_crash_test_with_txn: db_stress
|
||||
python -u tools/db_crashtest.py --txn blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
ifeq ($(CRASH_TEST_KILL_ODD),)
|
||||
CRASH_TEST_KILL_ODD=888887
|
||||
endif
|
||||
@@ -971,6 +992,10 @@ whitebox_crash_test_with_atomic_flush: db_stress
|
||||
python -u tools/db_crashtest.py --cf_consistency whitebox --random_kill_odd \
|
||||
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
whitebox_crash_test_with_txn: db_stress
|
||||
python -u tools/db_crashtest.py --txn whitebox --random_kill_odd \
|
||||
$(CRASH_TEST_KILL_ODD) $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
asan_check:
|
||||
$(MAKE) clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) check -j32
|
||||
@@ -986,6 +1011,11 @@ asan_crash_test_with_atomic_flush:
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_atomic_flush
|
||||
$(MAKE) clean
|
||||
|
||||
asan_crash_test_with_txn:
|
||||
$(MAKE) clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_txn
|
||||
$(MAKE) clean
|
||||
|
||||
ubsan_check:
|
||||
$(MAKE) clean
|
||||
COMPILE_WITH_UBSAN=1 $(MAKE) check -j32
|
||||
@@ -1001,6 +1031,11 @@ ubsan_crash_test_with_atomic_flush:
|
||||
COMPILE_WITH_UBSAN=1 $(MAKE) crash_test_with_atomic_flush
|
||||
$(MAKE) clean
|
||||
|
||||
ubsan_crash_test_with_txn:
|
||||
$(MAKE) clean
|
||||
COMPILE_WITH_UBSAN=1 $(MAKE) crash_test_with_txn
|
||||
$(MAKE) clean
|
||||
|
||||
valgrind_test:
|
||||
ROCKSDB_VALGRIND_RUN=1 DISABLE_JEMALLOC=1 $(MAKE) valgrind_check
|
||||
|
||||
@@ -1027,7 +1062,7 @@ ifneq ($(PAR_TEST),)
|
||||
parloop:
|
||||
ret_bad=0; \
|
||||
for t in $(PAR_TEST); do \
|
||||
echo "===== Running $$t in parallel $(NUM_PAR)";\
|
||||
echo "===== Running $$t in parallel $(NUM_PAR) (`date`)";\
|
||||
if [ $(db_test) -eq 1 ]; then \
|
||||
seq $(J) | v="$$t" build_tools/gnu_parallel --gnu --plain 's=$(TMPD)/rdb-{}; export TEST_TMPDIR=$$s;' \
|
||||
'timeout 2m ./db_test --gtest_filter=$$v >> $$s/log-{} 2>1'; \
|
||||
@@ -1070,6 +1105,9 @@ parallel_check: $(TESTS)
|
||||
TMPD=$(TMPD) J=$(J) db_test=0 parloop;
|
||||
|
||||
analyze: clean
|
||||
USE_CLANG=1 $(MAKE) analyze_incremental
|
||||
|
||||
analyze_incremental:
|
||||
$(CLANG_SCAN_BUILD) --use-analyzer=$(CLANG_ANALYZER) \
|
||||
--use-c++=$(CXX) --use-cc=$(CC) --status-bugs \
|
||||
-o $(CURDIR)/scan_build_report \
|
||||
@@ -1098,13 +1136,27 @@ unity_test: db/db_test.o db/db_test_util.o $(TESTHARNESS) $(TOOLLIBOBJECTS) unit
|
||||
rocksdb.h rocksdb.cc: build_tools/amalgamate.py Makefile $(LIB_SOURCES) unity.cc
|
||||
build_tools/amalgamate.py -I. -i./include unity.cc -x include/rocksdb/c.h -H rocksdb.h -o rocksdb.cc
|
||||
|
||||
clean:
|
||||
clean: clean-ext-libraries-all clean-rocks clean-rocksjava
|
||||
|
||||
clean-not-downloaded: clean-ext-libraries-bin clean-rocks clean-not-downloaded-rocksjava
|
||||
|
||||
clean-rocks:
|
||||
rm -f $(BENCHMARKS) $(TOOLS) $(TESTS) $(PARALLEL_TEST) $(LIBRARY) $(SHARED)
|
||||
rm -rf $(CLEAN_FILES) ios-x86 ios-arm scan_build_report
|
||||
$(FIND) . -name "*.[oda]" -exec rm -f {} \;
|
||||
$(FIND) . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" -exec rm {} \;
|
||||
|
||||
clean-rocksjava:
|
||||
cd java && $(MAKE) clean
|
||||
|
||||
clean-not-downloaded-rocksjava:
|
||||
cd java && $(MAKE) clean-not-downloaded
|
||||
|
||||
clean-ext-libraries-all:
|
||||
rm -rf bzip2* snappy* zlib* lz4* zstd*
|
||||
cd java; $(MAKE) clean
|
||||
|
||||
clean-ext-libraries-bin:
|
||||
find . -maxdepth 1 -type d \( -name bzip2\* -or -name snappy\* -or -name zlib\* -or -name lz4\* -or -name zstd\* \) -prune -exec rm -rf {} \;
|
||||
|
||||
tags:
|
||||
ctags -R .
|
||||
@@ -1135,6 +1187,10 @@ $(TOOLS_LIBRARY): $(BENCH_LIB_SOURCES:.cc=.o) $(TOOL_LIB_SOURCES:.cc=.o) $(LIB_S
|
||||
$(AM_V_AR)rm -f $@
|
||||
$(AM_V_at)$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
$(STRESS_LIBRARY): $(LIB_SOURCES:.cc=.o) $(TESTUTIL) $(ANALYZER_LIB_SOURCES:.cc=.o) $(STRESS_LIB_SOURCES:.cc=.o)
|
||||
$(AM_V_AR)rm -f $@
|
||||
$(AM_V_at)$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
librocksdb_env_basic_test.a: env/env_basic_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_V_AR)rm -f $@
|
||||
$(AM_V_at)$(AR) $(ARFLAGS) $@ $^
|
||||
@@ -1165,7 +1221,7 @@ memtablerep_bench: memtable/memtablerep_bench.o $(LIBOBJECTS) $(TESTUTIL)
|
||||
filter_bench: util/filter_bench.o $(LIBOBJECTS) $(TESTUTIL)
|
||||
$(AM_LINK)
|
||||
|
||||
db_stress: tools/db_stress.o $(LIBOBJECTS) $(TESTUTIL)
|
||||
db_stress: db_stress_tool/db_stress.o $(STRESSTOOLOBJECTS)
|
||||
$(AM_LINK)
|
||||
|
||||
write_stress: tools/write_stress.o $(LIBOBJECTS) $(TESTUTIL)
|
||||
@@ -1207,6 +1263,9 @@ coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
hash_test: util/hash_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
random_test: util/random_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
option_change_migration_test: utilities/option_change_migration/option_change_migration_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1240,12 +1299,18 @@ corruption_test: db/corruption_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARN
|
||||
crc32c_test: util/crc32c_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
slice_test: util/slice_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
slice_transform_test: util/slice_transform_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_basic_test: db/db_basic_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_with_timestamp_basic_test: db/db_with_timestamp_basic_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_encryption_test: db/db_encryption_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1255,7 +1320,10 @@ db_test: db/db_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
db_test2: db/db_test2.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_blob_index_test: db/db_blob_index_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
db_logical_block_size_cache_test: db/db_logical_block_size_cache_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_blob_index_test: db/blob/db_blob_index_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
db_block_cache_test: db/db_block_cache_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
@@ -1309,7 +1377,7 @@ db_statistics_test: db/db_statistics_test.o db/db_test_util.o $(LIBOBJECTS) $(TE
|
||||
db_write_test: db/db_write_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
error_handler_test: db/error_handler_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
error_handler_fs_test: db/error_handler_fs_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
external_sst_file_basic_test: db/external_sst_file_basic_test.o db/db_test_util.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
@@ -1422,6 +1490,9 @@ env_basic_test: env/env_basic_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
env_test: env/env_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
io_posix_test: env/io_posix_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
fault_injection_test: db/fault_injection_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1659,6 +1730,15 @@ block_cache_tracer_test: trace_replay/block_cache_tracer_test.o trace_replay/blo
|
||||
block_cache_trace_analyzer_test: tools/block_cache_analyzer/block_cache_trace_analyzer_test.o tools/block_cache_analyzer/block_cache_trace_analyzer.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
defer_test: util/defer_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
blob_file_addition_test: db/blob/blob_file_addition_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
blob_file_garbage_test: db/blob/blob_file_garbage_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
#-------------------------------------------------
|
||||
# make install related stuff
|
||||
INSTALL_PATH ?= /usr/local
|
||||
@@ -1704,7 +1784,7 @@ JAVA_INCLUDE = -I$(JAVA_HOME)/include/ -I$(JAVA_HOME)/include/linux
|
||||
ifeq ($(PLATFORM), OS_SOLARIS)
|
||||
ARCH := $(shell isainfo -b)
|
||||
else ifeq ($(PLATFORM), OS_OPENBSD)
|
||||
ifneq (,$(filter $(MACHINE), amd64 arm64 aarch64 sparc64))
|
||||
ifneq (,$(filter amd64 ppc64 ppc64le arm64 aarch64 sparc64, $(MACHINE)))
|
||||
ARCH := 64
|
||||
else
|
||||
ARCH := 32
|
||||
@@ -1713,12 +1793,23 @@ else
|
||||
ARCH := $(shell getconf LONG_BIT)
|
||||
endif
|
||||
|
||||
ifeq (,$(filter $(MACHINE), ppc arm64 aarch64 sparc64))
|
||||
ROCKSDBJNILIB = librocksdbjni-linux$(ARCH).so
|
||||
else
|
||||
ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE).so
|
||||
ifeq ($(shell ldd /usr/bin/env 2>/dev/null | grep -q musl; echo $$?),0)
|
||||
JNI_LIBC = musl
|
||||
# GNU LibC (or glibc) is so pervasive we can assume it is the default
|
||||
# else
|
||||
# JNI_LIBC = glibc
|
||||
endif
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH).jar
|
||||
|
||||
ifneq ($(origin JNI_LIBC), undefined)
|
||||
JNI_LIBC_POSTFIX = -$(JNI_LIBC)
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ppc% arm64 aarch64 sparc64, $(MACHINE)))
|
||||
ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE)$(JNI_LIBC_POSTFIX).so
|
||||
else
|
||||
ROCKSDBJNILIB = librocksdbjni-linux$(ARCH)$(JNI_LIBC_POSTFIX).so
|
||||
endif
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH)$(JNI_LIBC_POSTFIX).jar
|
||||
ROCKSDB_JAR_ALL = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH).jar
|
||||
ROCKSDB_JAVADOCS_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-javadoc.jar
|
||||
ROCKSDB_SOURCES_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-sources.jar
|
||||
@@ -1729,15 +1820,15 @@ ZLIB_SHA256 ?= c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
|
||||
ZLIB_DOWNLOAD_BASE ?= http://zlib.net
|
||||
BZIP2_VER ?= 1.0.6
|
||||
BZIP2_SHA256 ?= a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd
|
||||
BZIP2_DOWNLOAD_BASE ?= https://web.archive.org/web/20180624184835/http://www.bzip.org
|
||||
SNAPPY_VER ?= 1.1.7
|
||||
SNAPPY_SHA256 ?= 3dfa02e873ff51a11ee02b9ca391807f0c8ea0529a4924afa645fbf97163f9d4
|
||||
BZIP2_DOWNLOAD_BASE ?= https://downloads.sourceforge.net/project/bzip2
|
||||
SNAPPY_VER ?= 1.1.8
|
||||
SNAPPY_SHA256 ?= 16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f
|
||||
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/archive
|
||||
LZ4_VER ?= 1.8.3
|
||||
LZ4_SHA256 ?= 33af5936ac06536805f9745e0b6d61da606a1f8b4cc5c04dd3cbaca3b9b4fc43
|
||||
LZ4_VER ?= 1.9.2
|
||||
LZ4_SHA256 ?= 658ba6191fa44c92280d4aa2c271b0f4fbc0e34d249578dd05e50e76d0e5efcc
|
||||
LZ4_DOWNLOAD_BASE ?= https://github.com/lz4/lz4/archive
|
||||
ZSTD_VER ?= 1.4.0
|
||||
ZSTD_SHA256 ?= 63be339137d2b683c6d19a9e34f4fb684790e864fee13c7dd40e197a64c705c1
|
||||
ZSTD_VER ?= 1.4.4
|
||||
ZSTD_SHA256 ?= a364f5162c7d1a455cc915e8e3cf5f4bd8b75d09bc0f53965b0c9ca1383c52c8
|
||||
ZSTD_DOWNLOAD_BASE ?= https://github.com/facebook/zstd/archive
|
||||
CURL_SSL_OPTS ?= --tlsv1
|
||||
|
||||
@@ -1777,7 +1868,7 @@ endif
|
||||
libz.a:
|
||||
-rm -rf zlib-$(ZLIB_VER)
|
||||
ifeq (,$(wildcard ./zlib-$(ZLIB_VER).tar.gz))
|
||||
curl --output zlib-$(ZLIB_VER).tar.gz -L ${ZLIB_DOWNLOAD_BASE}/zlib-$(ZLIB_VER).tar.gz
|
||||
curl --fail --output zlib-$(ZLIB_VER).tar.gz --location ${ZLIB_DOWNLOAD_BASE}/zlib-$(ZLIB_VER).tar.gz
|
||||
endif
|
||||
ZLIB_SHA256_ACTUAL=`$(SHA256_CMD) zlib-$(ZLIB_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(ZLIB_SHA256)" != "$$ZLIB_SHA256_ACTUAL" ]; then \
|
||||
@@ -1791,7 +1882,7 @@ endif
|
||||
libbz2.a:
|
||||
-rm -rf bzip2-$(BZIP2_VER)
|
||||
ifeq (,$(wildcard ./bzip2-$(BZIP2_VER).tar.gz))
|
||||
curl --output bzip2-$(BZIP2_VER).tar.gz -L ${BZIP2_DOWNLOAD_BASE}/$(BZIP2_VER)/bzip2-$(BZIP2_VER).tar.gz
|
||||
curl --fail --output bzip2-$(BZIP2_VER).tar.gz --location ${CURL_SSL_OPTS} ${BZIP2_DOWNLOAD_BASE}/bzip2-$(BZIP2_VER).tar.gz
|
||||
endif
|
||||
BZIP2_SHA256_ACTUAL=`$(SHA256_CMD) bzip2-$(BZIP2_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(BZIP2_SHA256)" != "$$BZIP2_SHA256_ACTUAL" ]; then \
|
||||
@@ -1805,7 +1896,7 @@ endif
|
||||
libsnappy.a:
|
||||
-rm -rf snappy-$(SNAPPY_VER)
|
||||
ifeq (,$(wildcard ./snappy-$(SNAPPY_VER).tar.gz))
|
||||
curl --output snappy-$(SNAPPY_VER).tar.gz -L ${CURL_SSL_OPTS} ${SNAPPY_DOWNLOAD_BASE}/$(SNAPPY_VER).tar.gz
|
||||
curl --fail --output snappy-$(SNAPPY_VER).tar.gz --location ${CURL_SSL_OPTS} ${SNAPPY_DOWNLOAD_BASE}/$(SNAPPY_VER).tar.gz
|
||||
endif
|
||||
SNAPPY_SHA256_ACTUAL=`$(SHA256_CMD) snappy-$(SNAPPY_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(SNAPPY_SHA256)" != "$$SNAPPY_SHA256_ACTUAL" ]; then \
|
||||
@@ -1820,7 +1911,7 @@ endif
|
||||
liblz4.a:
|
||||
-rm -rf lz4-$(LZ4_VER)
|
||||
ifeq (,$(wildcard ./lz4-$(LZ4_VER).tar.gz))
|
||||
curl --output lz4-$(LZ4_VER).tar.gz -L ${CURL_SSL_OPTS} ${LZ4_DOWNLOAD_BASE}/v$(LZ4_VER).tar.gz
|
||||
curl --fail --output lz4-$(LZ4_VER).tar.gz --location ${CURL_SSL_OPTS} ${LZ4_DOWNLOAD_BASE}/v$(LZ4_VER).tar.gz
|
||||
endif
|
||||
LZ4_SHA256_ACTUAL=`$(SHA256_CMD) lz4-$(LZ4_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(LZ4_SHA256)" != "$$LZ4_SHA256_ACTUAL" ]; then \
|
||||
@@ -1834,7 +1925,7 @@ endif
|
||||
libzstd.a:
|
||||
-rm -rf zstd-$(ZSTD_VER)
|
||||
ifeq (,$(wildcard ./zstd-$(ZSTD_VER).tar.gz))
|
||||
curl --output zstd-$(ZSTD_VER).tar.gz -L ${CURL_SSL_OPTS} ${ZSTD_DOWNLOAD_BASE}/v$(ZSTD_VER).tar.gz
|
||||
curl --fail --output zstd-$(ZSTD_VER).tar.gz --location ${CURL_SSL_OPTS} ${ZSTD_DOWNLOAD_BASE}/v$(ZSTD_VER).tar.gz
|
||||
endif
|
||||
ZSTD_SHA256_ACTUAL=`$(SHA256_CMD) zstd-$(ZSTD_VER).tar.gz | cut -d ' ' -f 1`; \
|
||||
if [ "$(ZSTD_SHA256)" != "$$ZSTD_SHA256_ACTUAL" ]; then \
|
||||
@@ -1892,35 +1983,47 @@ rocksdbjavastatic: $(java_static_all_libobjects)
|
||||
cd java/src/main/java;jar -cf ../../../target/$(ROCKSDB_SOURCES_JAR) org
|
||||
|
||||
rocksdbjavastaticrelease: rocksdbjavastatic
|
||||
cd java/crossbuild && vagrant destroy -f && vagrant up linux32 && vagrant halt linux32 && vagrant up linux64 && vagrant halt linux64
|
||||
cd java/crossbuild && (vagrant destroy -f || true) && vagrant up linux32 && vagrant halt linux32 && vagrant up linux64 && vagrant halt linux64 && vagrant up linux64-musl && vagrant halt linux64-musl
|
||||
cd java;jar -cf target/$(ROCKSDB_JAR_ALL) HISTORY*.md
|
||||
cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib
|
||||
cd java/target/classes;jar -uf ../$(ROCKSDB_JAR_ALL) org/rocksdb/*.class org/rocksdb/util/*.class
|
||||
|
||||
rocksdbjavastaticreleasedocker: rocksdbjavastatic rocksdbjavastaticdockerx86 rocksdbjavastaticdockerx86_64
|
||||
rocksdbjavastaticreleasedocker: rocksdbjavastatic rocksdbjavastaticdockerx86 rocksdbjavastaticdockerx86_64 rocksdbjavastaticdockerx86musl rocksdbjavastaticdockerx86_64musl
|
||||
cd java;jar -cf target/$(ROCKSDB_JAR_ALL) HISTORY*.md
|
||||
cd java/target;jar -uf $(ROCKSDB_JAR_ALL) librocksdbjni-*.so librocksdbjni-*.jnilib
|
||||
cd java/target/classes;jar -uf ../$(ROCKSDB_JAR_ALL) org/rocksdb/*.class org/rocksdb/util/*.class
|
||||
|
||||
rocksdbjavastaticdockerx86:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_x86-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos6_x86-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
docker run --rm --name rocksdb_linux_x86-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos6_x86-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerx86_64:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_x64-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos6_x64-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
docker run --rm --name rocksdb_linux_x64-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos6_x64-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerppc64le:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_ppc64le-be --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos7_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
docker run --rm --name rocksdb_linux_ppc64le-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos7_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerarm64v8:
|
||||
mkdir -p java/target
|
||||
DOCKER_LINUX_ARM64V8_CONTAINER=`docker ps -aqf name=rocksdb_linux_arm64v8-be`; \
|
||||
if [ -z "$$DOCKER_LINUX_ARM64V8_CONTAINER" ]; then \
|
||||
docker container create --attach stdin --attach stdout --attach stderr --volume `pwd`:/rocksdb-host --name rocksdb_linux_arm64v8-be evolvedbinary/rocksjava:centos7_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh; \
|
||||
fi
|
||||
docker start -a rocksdb_linux_arm64v8-be
|
||||
docker run --rm --name rocksdb_linux_arm64v8-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:centos7_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerx86musl:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_x86-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_x86-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerx86_64musl:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_x64-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_x64-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerppc64lemusl:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_ppc64le-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_ppc64le-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticdockerarm64v8musl:
|
||||
mkdir -p java/target
|
||||
docker run --rm --name rocksdb_linux_arm64v8-musl-be --attach stdin --attach stdout --attach stderr --volume $(HOME)/.m2:/root/.m2:ro --volume `pwd`:/rocksdb-host:ro --volume /rocksdb-local-build --volume `pwd`/java/target:/rocksdb-java-target --env DEBUG_LEVEL=$(DEBUG_LEVEL) evolvedbinary/rocksjava:alpine3_arm64v8-be /rocksdb-host/java/crossbuild/docker-build-linux-centos.sh
|
||||
|
||||
rocksdbjavastaticpublish: rocksdbjavastaticrelease rocksdbjavastaticpublishcentral
|
||||
|
||||
@@ -1931,6 +2034,8 @@ rocksdbjavastaticpublishcentral:
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-sources.jar -Dclassifier=sources
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux64.jar -Dclassifier=linux64
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux32.jar -Dclassifier=linux32
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux64-musl.jar -Dclassifier=linux64-musl
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux32-musl.jar -Dclassifier=linux32-musl
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-osx.jar -Dclassifier=osx
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-win64.jar -Dclassifier=win64
|
||||
mvn gpg:sign-and-deploy-file -Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/ -DrepositoryId=sonatype-nexus-staging -DpomFile=java/rocksjni.pom -Dfile=java/target/rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH).jar
|
||||
@@ -1984,6 +2089,7 @@ jtest_run:
|
||||
|
||||
jtest: rocksdbjava
|
||||
cd java;$(MAKE) sample;$(MAKE) test;
|
||||
python tools/check_all_python.py # TODO peterd: find a better place for this check in CI targets
|
||||
|
||||
jdb_bench:
|
||||
cd java;$(MAKE) db_bench;
|
||||
@@ -2031,6 +2137,9 @@ endif
|
||||
.cc.o:
|
||||
$(AM_V_CC)$(CXX) $(CXXFLAGS) -c $< -o $@ $(COVERAGEFLAGS)
|
||||
|
||||
.cpp.o:
|
||||
$(AM_V_CC)$(CXX) $(CXXFLAGS) -c $< -o $@ $(COVERAGEFLAGS)
|
||||
|
||||
.c.o:
|
||||
$(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@
|
||||
endif
|
||||
@@ -2038,9 +2147,13 @@ endif
|
||||
# Source files dependencies detection
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
all_sources = $(LIB_SOURCES) $(MAIN_SOURCES) $(MOCK_LIB_SOURCES) $(TOOL_LIB_SOURCES) $(BENCH_LIB_SOURCES) $(TEST_LIB_SOURCES) $(ANALYZER_LIB_SOURCES)
|
||||
all_sources = $(LIB_SOURCES) $(MAIN_SOURCES) $(MOCK_LIB_SOURCES) $(TOOL_LIB_SOURCES) $(BENCH_LIB_SOURCES) $(TEST_LIB_SOURCES) $(ANALYZER_LIB_SOURCES) $(STRESS_LIB_SOURCES)
|
||||
DEPFILES = $(all_sources:.cc=.cc.d)
|
||||
|
||||
ifeq ($(USE_FOLLY_DISTRIBUTED_MUTEX),1)
|
||||
DEPFILES += $(FOLLY_SOURCES:.cpp=.cpp.d)
|
||||
endif
|
||||
|
||||
# Add proper dependency support so changing a .h file forces a .cc file to
|
||||
# rebuild.
|
||||
|
||||
@@ -2050,6 +2163,10 @@ DEPFILES = $(all_sources:.cc=.cc.d)
|
||||
@$(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) \
|
||||
-MM -MT'$@' -MT'$(<:.cc=.o)' "$<" -o '$@'
|
||||
|
||||
%.cpp.d: %.cpp
|
||||
@$(CXX) $(CXXFLAGS) $(PLATFORM_SHARED_CFLAGS) \
|
||||
-MM -MT'$@' -MT'$(<:.cpp=.o)' "$<" -o '$@'
|
||||
|
||||
ifeq ($(HAVE_POWER8),1)
|
||||
DEPFILES_C = $(LIB_SOURCES_C:.c=.c.d)
|
||||
DEPFILES_ASM = $(LIB_SOURCES_ASM:.S=.S.d)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
# This file @generated by `python 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.
|
||||
#
|
||||
load("@fbcode_macros//build_defs:auto_headers.bzl", "AutoHeaders")
|
||||
load("@fbcode_macros//build_defs:cpp_library.bzl", "cpp_library")
|
||||
load(":defs.bzl", "test_binary")
|
||||
@@ -27,7 +32,7 @@ ROCKSDB_EXTERNAL_DEPS = [
|
||||
ROCKSDB_OS_DEPS = [
|
||||
(
|
||||
"linux",
|
||||
["third-party//numa:numa"],
|
||||
["third-party//numa:numa", "third-party//liburing:uring"],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -41,7 +46,9 @@ ROCKSDB_OS_PREPROCESSOR_FLAGS = [
|
||||
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
|
||||
"-DROCKSDB_RANGESYNC_PRESENT",
|
||||
"-DROCKSDB_SCHED_GETCPU_PRESENT",
|
||||
"-DROCKSDB_IOURING_PRESENT",
|
||||
"-DHAVE_SSE42",
|
||||
"-DLIBURING",
|
||||
"-DNUMA",
|
||||
],
|
||||
),
|
||||
@@ -109,6 +116,8 @@ cpp_library(
|
||||
"cache/lru_cache.cc",
|
||||
"cache/sharded_cache.cc",
|
||||
"db/arena_wrapped_db_iter.cc",
|
||||
"db/blob/blob_file_addition.cc",
|
||||
"db/blob/blob_file_garbage.cc",
|
||||
"db/builder.cc",
|
||||
"db/c.cc",
|
||||
"db/column_family.cc",
|
||||
@@ -173,6 +182,8 @@ cpp_library(
|
||||
"env/env_encryption.cc",
|
||||
"env/env_hdfs.cc",
|
||||
"env/env_posix.cc",
|
||||
"env/file_system.cc",
|
||||
"env/fs_posix.cc",
|
||||
"env/io_posix.cc",
|
||||
"env/mock_env.cc",
|
||||
"file/delete_scheduler.cc",
|
||||
@@ -220,20 +231,30 @@ cpp_library(
|
||||
"port/port_posix.cc",
|
||||
"port/stack_trace.cc",
|
||||
"table/adaptive/adaptive_table_factory.cc",
|
||||
"table/block_based/binary_search_index_reader.cc",
|
||||
"table/block_based/block.cc",
|
||||
"table/block_based/block_based_filter_block.cc",
|
||||
"table/block_based/block_based_table_builder.cc",
|
||||
"table/block_based/block_based_table_factory.cc",
|
||||
"table/block_based/block_based_table_iterator.cc",
|
||||
"table/block_based/block_based_table_reader.cc",
|
||||
"table/block_based/block_builder.cc",
|
||||
"table/block_based/block_prefetcher.cc",
|
||||
"table/block_based/block_prefix_index.cc",
|
||||
"table/block_based/data_block_footer.cc",
|
||||
"table/block_based/data_block_hash_index.cc",
|
||||
"table/block_based/filter_block_reader_common.cc",
|
||||
"table/block_based/filter_policy.cc",
|
||||
"table/block_based/flush_block_policy.cc",
|
||||
"table/block_based/full_filter_block.cc",
|
||||
"table/block_based/hash_index_reader.cc",
|
||||
"table/block_based/index_builder.cc",
|
||||
"table/block_based/index_reader_common.cc",
|
||||
"table/block_based/parsed_full_filter_block.cc",
|
||||
"table/block_based/partitioned_filter_block.cc",
|
||||
"table/block_based/partitioned_index_iterator.cc",
|
||||
"table/block_based/partitioned_index_reader.cc",
|
||||
"table/block_based/reader_common.cc",
|
||||
"table/block_based/uncompression_dict_reader.cc",
|
||||
"table/block_fetcher.cc",
|
||||
"table/cuckoo/cuckoo_table_builder.cc",
|
||||
@@ -264,7 +285,6 @@ cpp_library(
|
||||
"tools/sst_dump_tool.cc",
|
||||
"trace_replay/block_cache_tracer.cc",
|
||||
"trace_replay/trace_replay.cc",
|
||||
"util/bloom.cc",
|
||||
"util/build_version.cc",
|
||||
"util/coding.cc",
|
||||
"util/compaction_job_stats_impl.cc",
|
||||
@@ -273,7 +293,7 @@ cpp_library(
|
||||
"util/concurrent_task_limiter_impl.cc",
|
||||
"util/crc32c.cc",
|
||||
"util/dynamic_bloom.cc",
|
||||
"util/filter_policy.cc",
|
||||
"util/file_checksum_helper.cc",
|
||||
"util/hash.cc",
|
||||
"util/murmurhash.cc",
|
||||
"util/random.cc",
|
||||
@@ -357,6 +377,7 @@ cpp_library(
|
||||
"db/db_test_util.cc",
|
||||
"table/mock_table.cc",
|
||||
"test_util/fault_injection_test_env.cc",
|
||||
"test_util/fault_injection_test_fs.cc",
|
||||
"test_util/testharness.cc",
|
||||
"test_util/testutil.cc",
|
||||
"tools/block_cache_analyzer/block_cache_trace_analyzer.cc",
|
||||
@@ -391,6 +412,32 @@ cpp_library(
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
name = "rocksdb_stress_lib",
|
||||
srcs = [
|
||||
"db_stress_tool/batched_ops_stress.cc",
|
||||
"db_stress_tool/cf_consistency_stress.cc",
|
||||
"db_stress_tool/db_stress_common.cc",
|
||||
"db_stress_tool/db_stress_driver.cc",
|
||||
"db_stress_tool/db_stress_gflags.cc",
|
||||
"db_stress_tool/db_stress_shared_state.cc",
|
||||
"db_stress_tool/db_stress_test_base.cc",
|
||||
"db_stress_tool/db_stress_tool.cc",
|
||||
"db_stress_tool/no_batched_ops_stress.cc",
|
||||
"test_util/testutil.cc",
|
||||
"tools/block_cache_analyzer/block_cache_trace_analyzer.cc",
|
||||
"tools/trace_analyzer_tool.cc",
|
||||
],
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
deps = [":rocksdb_lib"],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
name = "env_basic_test_lib",
|
||||
srcs = ["env/env_basic_test.cc"],
|
||||
@@ -441,6 +488,20 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"blob_file_addition_test",
|
||||
"db/blob/blob_file_addition_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"blob_file_garbage_test",
|
||||
"db/blob/blob_file_garbage_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"block_based_filter_block_test",
|
||||
"table/block_based/block_based_filter_block_test.cc",
|
||||
@@ -653,7 +714,7 @@ ROCKS_TESTS = [
|
||||
],
|
||||
[
|
||||
"db_blob_index_test",
|
||||
"db/db_blob_index_test.cc",
|
||||
"db/blob/db_blob_index_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
@@ -749,6 +810,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_logical_block_size_cache_test",
|
||||
"db/db_logical_block_size_cache_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_memtable_test",
|
||||
"db/db_memtable_test.cc",
|
||||
@@ -757,15 +825,15 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_merge_operator_test",
|
||||
"db/db_merge_operator_test.cc",
|
||||
"parallel",
|
||||
"db_merge_operand_test",
|
||||
"db/db_merge_operand_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_merge_operand_test",
|
||||
"db/db_merge_operand_test.cc",
|
||||
"db_merge_operator_test",
|
||||
"db/db_merge_operator_test.cc",
|
||||
"parallel",
|
||||
[],
|
||||
[],
|
||||
@@ -854,6 +922,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_with_timestamp_basic_test",
|
||||
"db/db_with_timestamp_basic_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"db_write_test",
|
||||
"db/db_write_test.cc",
|
||||
@@ -868,6 +943,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"defer_test",
|
||||
"util/defer_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"delete_scheduler_test",
|
||||
"file/delete_scheduler_test.cc",
|
||||
@@ -918,8 +1000,8 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
],
|
||||
[
|
||||
"error_handler_test",
|
||||
"db/error_handler_test.cc",
|
||||
"error_handler_fs_test",
|
||||
"db/error_handler_fs_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
@@ -1036,6 +1118,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"io_posix_test",
|
||||
"env/io_posix_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"iostats_context_test",
|
||||
"monitoring/iostats_context_test.cc",
|
||||
@@ -1211,6 +1300,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"random_test",
|
||||
"util/random_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"range_del_aggregator_test",
|
||||
"db/range_del_aggregator_test.cc",
|
||||
@@ -1267,6 +1363,13 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"slice_test",
|
||||
"util/slice_test.cc",
|
||||
"serial",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"slice_transform_test",
|
||||
"util/slice_transform_test.cc",
|
||||
|
||||
@@ -102,3 +102,7 @@ LzLabs is using RocksDB as a storage engine in their multi-database distributed
|
||||
|
||||
## 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.
|
||||
|
||||
## Nebula Graph
|
||||
|
||||
[Nebula Graph](https://github.com/vesoft-inc/nebula) is a distributed, scalable, lightning-fast, open source graph database capable of hosting super large scale graphs with dozens of billions of vertices (nodes) and trillions of edges, with milliseconds of latency.
|
||||
+16
-8
@@ -17,41 +17,49 @@ environment:
|
||||
ZSTD_INCLUDE: $(ZSTD_HOME)\lib;$(ZSTD_HOME)\lib\dictBuilder
|
||||
ZSTD_LIB_DEBUG: $(ZSTD_HOME)\build\VS2010\bin\x64_Debug\libzstd_static.lib
|
||||
ZSTD_LIB_RELEASE: $(ZSTD_HOME)\build\VS2010\bin\x64_Release\libzstd_static.lib
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
CMAKE_GENERATOR: Visual Studio 14 Win64
|
||||
DEV_ENV: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.com
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
CMAKE_GENERATOR: Visual Studio 15 Win64
|
||||
DEV_ENV: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.com
|
||||
|
||||
install:
|
||||
- md %THIRDPARTY_HOME%
|
||||
- echo "Building Snappy dependency..."
|
||||
- cd %THIRDPARTY_HOME%
|
||||
- curl -fsSL -o snappy-1.1.7.zip https://github.com/google/snappy/archive/1.1.7.zip
|
||||
- curl --fail --silent --show-error --output snappy-1.1.7.zip --location https://github.com/google/snappy/archive/1.1.7.zip
|
||||
- unzip snappy-1.1.7.zip
|
||||
- cd snappy-1.1.7
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..
|
||||
- cmake -G "%CMAKE_GENERATOR%" ..
|
||||
- msbuild Snappy.sln /p:Configuration=Debug /p:Platform=x64
|
||||
- msbuild Snappy.sln /p:Configuration=Release /p:Platform=x64
|
||||
- echo "Building LZ4 dependency..."
|
||||
- cd %THIRDPARTY_HOME%
|
||||
- curl -fsSL -o lz4-1.8.3.zip https://github.com/lz4/lz4/archive/v1.8.3.zip
|
||||
- curl --fail --silent --show-error --output lz4-1.8.3.zip --location https://github.com/lz4/lz4/archive/v1.8.3.zip
|
||||
- unzip lz4-1.8.3.zip
|
||||
- cd lz4-1.8.3\visual\VS2010
|
||||
- ps: $CMD="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.com"; & $CMD lz4.sln /upgrade
|
||||
- ps: $CMD="$Env:DEV_ENV"; & $CMD lz4.sln /upgrade
|
||||
- msbuild lz4.sln /p:Configuration=Debug /p:Platform=x64
|
||||
- msbuild lz4.sln /p:Configuration=Release /p:Platform=x64
|
||||
- echo "Building ZStd dependency..."
|
||||
- cd %THIRDPARTY_HOME%
|
||||
- curl -fsSL -o zstd-1.4.0.zip https://github.com/facebook/zstd/archive/v1.4.0.zip
|
||||
- curl --fail --silent --show-error --output zstd-1.4.0.zip --location https://github.com/facebook/zstd/archive/v1.4.0.zip
|
||||
- unzip zstd-1.4.0.zip
|
||||
- cd zstd-1.4.0\build\VS2010
|
||||
- ps: $CMD="C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.com"; & $CMD zstd.sln /upgrade
|
||||
- ps: $CMD="$Env:DEV_ENV"; & $CMD zstd.sln /upgrade
|
||||
- msbuild zstd.sln /p:Configuration=Debug /p:Platform=x64
|
||||
- msbuild zstd.sln /p:Configuration=Release /p:Platform=x64
|
||||
|
||||
before_build:
|
||||
- md %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cmake -G "Visual Studio 15 Win64" -DOPTDBG=1 -DPORTABLE=1 -DSNAPPY=1 -DLZ4=1 -DZSTD=1 -DXPRESS=1 -DJNI=1 ..
|
||||
- cmake -G "%CMAKE_GENERATOR%" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE=1 -DSNAPPY=1 -DLZ4=1 -DZSTD=1 -DXPRESS=1 -DJNI=1 ..
|
||||
- cd ..
|
||||
|
||||
build:
|
||||
project: build\rocksdb.sln
|
||||
parallel: true
|
||||
@@ -60,7 +68,7 @@ build:
|
||||
test:
|
||||
|
||||
test_script:
|
||||
- ps: build_tools\run_ci_db_test.ps1 -SuiteRun db_basic_test,db_test2,db_test,env_basic_test,env_test,db_merge_operand_test -Concurrency 8
|
||||
- ps: build_tools\run_ci_db_test.ps1 -SuiteRun db_basic_test,db_with_timestamp_basic_test,db_test2,db_test,env_basic_test,env_test,db_merge_operand_test -Concurrency 8
|
||||
|
||||
on_failure:
|
||||
- cmd: 7z a build-failed.zip %APPVEYOR_BUILD_FOLDER%\build\ && appveyor PushArtifact build-failed.zip
|
||||
|
||||
@@ -3,6 +3,10 @@ from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
try:
|
||||
from builtins import str
|
||||
except ImportError:
|
||||
from __builtin__ import str
|
||||
from targets_builder import TARGETSBuilder
|
||||
import json
|
||||
import os
|
||||
@@ -108,9 +112,9 @@ def get_tests(repo_path):
|
||||
# Parse extra dependencies passed by user from command line
|
||||
def get_dependencies():
|
||||
deps_map = {
|
||||
''.encode('ascii'): {
|
||||
'extra_deps'.encode('ascii'): [],
|
||||
'extra_compiler_flags'.encode('ascii'): []
|
||||
'': {
|
||||
'extra_deps': [],
|
||||
'extra_compiler_flags': []
|
||||
}
|
||||
}
|
||||
if len(sys.argv) < 2:
|
||||
@@ -119,13 +123,7 @@ def get_dependencies():
|
||||
def encode_dict(data):
|
||||
rv = {}
|
||||
for k, v in data.items():
|
||||
if isinstance(k, unicode):
|
||||
k = k.encode('ascii')
|
||||
if isinstance(v, unicode):
|
||||
v = v.encode('ascii')
|
||||
elif isinstance(v, list):
|
||||
v = [x.encode('ascii') for x in v]
|
||||
elif isinstance(v, dict):
|
||||
if isinstance(v, dict):
|
||||
v = encode_dict(v)
|
||||
rv[k] = v
|
||||
return rv
|
||||
@@ -169,6 +167,13 @@ def generate_targets(repo_path, deps_map):
|
||||
src_mk.get("ANALYZER_LIB_SOURCES", []) +
|
||||
["test_util/testutil.cc"],
|
||||
[":rocksdb_lib"])
|
||||
# rocksdb_stress_lib
|
||||
TARGETS.add_library(
|
||||
"rocksdb_stress_lib",
|
||||
src_mk.get("ANALYZER_LIB_SOURCES", [])
|
||||
+ src_mk.get('STRESS_LIB_SOURCES', [])
|
||||
+ ["test_util/testutil.cc"],
|
||||
[":rocksdb_lib"])
|
||||
|
||||
print("Extra dependencies:\n{0}".format(str(deps_map)))
|
||||
# test for every test we found in the Makefile
|
||||
|
||||
@@ -3,6 +3,12 @@ from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
try:
|
||||
from builtins import object
|
||||
from builtins import str
|
||||
except ImportError:
|
||||
from __builtin__ import object
|
||||
from __builtin__ import str
|
||||
import targets_cfg
|
||||
|
||||
def pretty_list(lst, indent=8):
|
||||
@@ -18,7 +24,7 @@ def pretty_list(lst, indent=8):
|
||||
return res
|
||||
|
||||
|
||||
class TARGETSBuilder:
|
||||
class TARGETSBuilder(object):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self.targets_file = open(path, 'w')
|
||||
|
||||
@@ -3,7 +3,13 @@ from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
rocksdb_target_header = """load("@fbcode_macros//build_defs:auto_headers.bzl", "AutoHeaders")
|
||||
|
||||
rocksdb_target_header = """# This file \100generated by `python 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.
|
||||
#
|
||||
load("@fbcode_macros//build_defs:auto_headers.bzl", "AutoHeaders")
|
||||
load("@fbcode_macros//build_defs:cpp_library.bzl", "cpp_library")
|
||||
load(":defs.bzl", "test_binary")
|
||||
|
||||
@@ -32,7 +38,7 @@ ROCKSDB_EXTERNAL_DEPS = [
|
||||
ROCKSDB_OS_DEPS = [
|
||||
(
|
||||
"linux",
|
||||
["third-party//numa:numa"],
|
||||
["third-party//numa:numa", "third-party//liburing:uring"],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -46,7 +52,9 @@ ROCKSDB_OS_PREPROCESSOR_FLAGS = [
|
||||
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
|
||||
"-DROCKSDB_RANGESYNC_PRESENT",
|
||||
"-DROCKSDB_SCHED_GETCPU_PRESENT",
|
||||
"-DROCKSDB_IOURING_PRESENT",
|
||||
"-DHAVE_SSE42",
|
||||
"-DLIBURING",
|
||||
"-DNUMA",
|
||||
],
|
||||
),
|
||||
|
||||
+13
-2
@@ -6,11 +6,16 @@ from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
try:
|
||||
from builtins import object
|
||||
except ImportError:
|
||||
from __builtin__ import object
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
class ColorString:
|
||||
class ColorString(object):
|
||||
""" Generate colorful strings on terminal """
|
||||
HEADER = '\033[95m'
|
||||
BLUE = '\033[94m'
|
||||
@@ -21,7 +26,13 @@ class ColorString:
|
||||
|
||||
@staticmethod
|
||||
def _make_color_str(text, color):
|
||||
return "".join([color, text.encode('utf-8'), ColorString.ENDC])
|
||||
# In Python2, default encoding for unicode string is ASCII
|
||||
if sys.version_info.major <= 2:
|
||||
return "".join(
|
||||
[color, text.encode('utf-8'), ColorString.ENDC])
|
||||
# From Python3, default encoding for unicode string is UTF-8
|
||||
return "".join(
|
||||
[color, text, ColorString.ENDC])
|
||||
|
||||
@staticmethod
|
||||
def ok(text):
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
# PLATFORM_LDFLAGS Linker flags
|
||||
# JAVA_LDFLAGS Linker flags for RocksDBJava
|
||||
# JAVA_STATIC_LDFLAGS Linker flags for RocksDBJava static build
|
||||
# JAVAC_ARGS Arguments for javac
|
||||
# PLATFORM_SHARED_EXT Extension for shared libraries
|
||||
# PLATFORM_SHARED_LDFLAGS Flags for building shared library
|
||||
# PLATFORM_SHARED_CFLAGS Flags for compiling objects for shared library
|
||||
@@ -56,10 +57,10 @@ if [ -z "$ROCKSDB_NO_FBCODE" -a -d /mnt/gvfs/third-party ]; then
|
||||
if [ -n "$ROCKSDB_FBCODE_BUILD_WITH_481" ]; then
|
||||
# we need this to build with MySQL. Don't use for other purposes.
|
||||
source "$PWD/build_tools/fbcode_config4.8.1.sh"
|
||||
elif [ -n "$ROCKSDB_FBCODE_BUILD_WITH_PLATFORM007" ]; then
|
||||
source "$PWD/build_tools/fbcode_config_platform007.sh"
|
||||
else
|
||||
elif [ -n "$ROCKSDB_FBCODE_BUILD_WITH_5xx" ]; then
|
||||
source "$PWD/build_tools/fbcode_config.sh"
|
||||
else
|
||||
source "$PWD/build_tools/fbcode_config_platform007.sh"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -150,6 +151,21 @@ case "$TARGET_OS" in
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -latomic"
|
||||
fi
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread -lrt"
|
||||
if test $ROCKSDB_USE_IO_URING; then
|
||||
# check for liburing
|
||||
$CXX $CFLAGS -x c++ - -luring -o /dev/null 2>/dev/null <<EOF
|
||||
#include <liburing.h>
|
||||
int main() {
|
||||
struct io_uring ring;
|
||||
io_uring_queue_init(1, &ring, 0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -luring"
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_IOURING_PRESENT"
|
||||
fi
|
||||
fi
|
||||
if test -z "$USE_FOLLY_DISTRIBUTED_MUTEX"; then
|
||||
USE_FOLLY_DISTRIBUTED_MUTEX=1
|
||||
fi
|
||||
@@ -224,6 +240,7 @@ esac
|
||||
PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS ${CXXFLAGS}"
|
||||
JAVA_LDFLAGS="$PLATFORM_LDFLAGS"
|
||||
JAVA_STATIC_LDFLAGS="$PLATFORM_LDFLAGS"
|
||||
JAVAC_ARGS="-source 7"
|
||||
|
||||
if [ "$CROSS_COMPILE" = "true" -o "$FBCODE_BUILD" = "true" ]; then
|
||||
# Cross-compiling; do not try any compilation tests.
|
||||
@@ -493,6 +510,20 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_AUXV_GETAUXVAL; then
|
||||
# Test whether getauxval is supported
|
||||
$CXX $CFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <sys/auxv.h>
|
||||
int main() {
|
||||
uint64_t auxv = getauxval(AT_HWCAP);
|
||||
(void)auxv;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_AUXV_GETAUXVAL_PRESENT"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ALIGNED_NEW; then
|
||||
# Test whether c++17 aligned-new is supported
|
||||
$CXX $PLATFORM_CXXFLAGS -faligned-new -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
@@ -572,6 +603,8 @@ if test "$TRY_SSE_ETC"; then
|
||||
TRY_SSE42="-msse4.2"
|
||||
# PCLMUL available since westmere, ca. 2010-2011
|
||||
TRY_PCLMUL="-mpclmul"
|
||||
# AVX2 available since haswell, ca. 2013-2015
|
||||
TRY_AVX2="-mavx2"
|
||||
fi
|
||||
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS $TRY_SSE42 -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
@@ -605,6 +638,34 @@ elif test "$USE_SSE"; then
|
||||
echo "warning: USE_SSE specified but compiler could not use PCLMUL intrinsics, disabling" >&2
|
||||
fi
|
||||
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS $TRY_AVX2 -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <cstdint>
|
||||
#include <immintrin.h>
|
||||
int main() {
|
||||
const auto a = _mm256_setr_epi32(0, 1, 2, 3, 4, 7, 6, 5);
|
||||
const auto b = _mm256_permutevar8x32_epi32(a, a);
|
||||
(void)b;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS $TRY_AVX2 -DHAVE_AVX2"
|
||||
elif test "$USE_SSE"; then
|
||||
echo "warning: USE_SSE specified but compiler could not use AVX2 intrinsics, disabling" >&2
|
||||
fi
|
||||
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <cstdint>
|
||||
int main() {
|
||||
uint64_t a = 0xffffFFFFffffFFFF;
|
||||
__uint128_t b = __uint128_t(a) * a;
|
||||
a = static_cast<uint64_t>(b >> 64);
|
||||
(void)a;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DHAVE_UINT128_EXTENSION"
|
||||
fi
|
||||
|
||||
# iOS doesn't support thread-local storage, but this check would erroneously
|
||||
# succeed because the cross-compiler flags are added by the Makefile, not this
|
||||
# script.
|
||||
@@ -651,6 +712,7 @@ echo "PLATFORM=$PLATFORM" >> "$OUTPUT"
|
||||
echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> "$OUTPUT"
|
||||
echo "JAVA_LDFLAGS=$JAVA_LDFLAGS" >> "$OUTPUT"
|
||||
echo "JAVA_STATIC_LDFLAGS=$JAVA_STATIC_LDFLAGS" >> "$OUTPUT"
|
||||
echo "JAVAC_ARGS=$JAVAC_ARGS" >> "$OUTPUT"
|
||||
echo "VALGRIND_VER=$VALGRIND_VER" >> "$OUTPUT"
|
||||
echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> "$OUTPUT"
|
||||
echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> "$OUTPUT"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/7331085db891a2ef4a88a48a751d834e8d68f4cb/7.x/centos7-native/b2ef2b6
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/1bd23f9917738974ad0ff305aa23eb5f93f18305/9.0.0/centos7-native/c9f9104
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/963d9aeda70cc4779885b1277484fe7544a04e3e/9.0.0/platform007/9e92d53/
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/6ace84e956873d53638c738b6f65f3f469cca74c/7.x/platform007/5620abc
|
||||
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/192b0f42d63dcf6210d6ceae387b49af049e6e0c/2.26/platform007/f259413
|
||||
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/7f9bdaada18f59bc27ec2b0871eb8a6144343aef/1.1.3/platform007/ca4da3d
|
||||
@@ -13,7 +13,8 @@ JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/c26f08f47ac35fc31da2633b7da92d6b86
|
||||
NUMA_BASE=/mnt/gvfs/third-party2/numa/3f3fb57a5ccc5fd21c66416c0b83e0aa76a05376/2.0.11/platform007/ca4da3d
|
||||
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/40c73d874898b386a71847f1b99115d93822d11f/1.4/platform007/6f3e0a9
|
||||
TBB_BASE=/mnt/gvfs/third-party2/tbb/4ce8e8dba77cdbd81b75d6f0c32fd7a1b76a11ec/2018_U5/platform007/ca4da3d
|
||||
LIBURING_BASE=/mnt/gvfs/third-party2/liburing/79427253fd0d42677255aacfe6d13bfe63f752eb/20190828/platform007/ca4da3d
|
||||
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/fb251ecd2f5ae16f8671f7014c246e52a748fe0b/fb/platform007/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/2e3cb7d119b3cea5f1e738cc13a1ac69f49eb875/2.29.1/centos7-native/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/ab9f09bba370e7066cafd4eb59752db93f2e8312/2.29.1/platform007/15a3614
|
||||
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/d42d152a15636529b0861ec493927200ebebca8e/3.15.0/platform007/ca4da3d
|
||||
LUA_BASE=/mnt/gvfs/third-party2/lua/f0cd714433206d5139df61659eb7b28b1dea6683/5.3.4/platform007/5007832
|
||||
@@ -133,13 +133,16 @@ _TEST_NAME_TO_PARSERS = {
|
||||
'lite_test': [CompilerErrorParser, GTestErrorParser],
|
||||
'stress_crash': [CompilerErrorParser, DbCrashErrorParser],
|
||||
'stress_crash_with_atomic_flush': [CompilerErrorParser, DbCrashErrorParser],
|
||||
'stress_crash_with_txn': [CompilerErrorParser, DbCrashErrorParser],
|
||||
'write_stress': [CompilerErrorParser, WriteStressErrorParser],
|
||||
'asan': [CompilerErrorParser, GTestErrorParser, AsanErrorParser],
|
||||
'asan_crash': [CompilerErrorParser, AsanErrorParser, DbCrashErrorParser],
|
||||
'asan_crash_with_atomic_flush': [CompilerErrorParser, AsanErrorParser, DbCrashErrorParser],
|
||||
'asan_crash_with_txn': [CompilerErrorParser, AsanErrorParser, DbCrashErrorParser],
|
||||
'ubsan': [CompilerErrorParser, GTestErrorParser, UbsanErrorParser],
|
||||
'ubsan_crash': [CompilerErrorParser, UbsanErrorParser, DbCrashErrorParser],
|
||||
'ubsan_crash_with_atomic_flush': [CompilerErrorParser, UbsanErrorParser, DbCrashErrorParser],
|
||||
'ubsan_crash_with_txn': [CompilerErrorParser, UbsanErrorParser, DbCrashErrorParser],
|
||||
'valgrind': [CompilerErrorParser, GTestErrorParser, ValgrindErrorParser],
|
||||
'tsan': [CompilerErrorParser, GTestErrorParser, TsanErrorParser],
|
||||
'format_compatible': [CompilerErrorParser, CompatErrorParser],
|
||||
|
||||
@@ -86,6 +86,15 @@ else
|
||||
fi
|
||||
CFLAGS+=" -DTBB"
|
||||
|
||||
# location of LIBURING
|
||||
LIBURING_INCLUDE=" -isystem $LIBURING_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
LIBURING_LIBS="$LIBURING_BASE/lib/liburing.a"
|
||||
else
|
||||
LIBURING_LIBS="$LIBURING_BASE/lib/liburing_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DLIBURING"
|
||||
|
||||
test "$USE_SSE" || USE_SSE=1
|
||||
export USE_SSE
|
||||
test "$PORTABLE" || PORTABLE=1
|
||||
@@ -94,7 +103,7 @@ export PORTABLE
|
||||
BINUTILS="$BINUTILS_BASE/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE"
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE $LIBURING_INCLUDE"
|
||||
|
||||
STDLIBS="-L $GCC_BASE/lib64"
|
||||
|
||||
@@ -135,10 +144,10 @@ else
|
||||
fi
|
||||
|
||||
CFLAGS+=" $DEPS_INCLUDE"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_SUPPORT_THREAD_LOCAL -DHAVE_SSE42"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_SUPPORT_THREAD_LOCAL -DHAVE_SSE42 -DROCKSDB_IOURING_PRESENT"
|
||||
CXXFLAGS+=" $CFLAGS"
|
||||
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS"
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS $LIBURING_LIBS"
|
||||
EXEC_LDFLAGS+=" -B$BINUTILS/gold"
|
||||
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,/usr/local/fbcode/platform007/lib/ld.so"
|
||||
EXEC_LDFLAGS+=" $LIBUNWIND"
|
||||
@@ -148,7 +157,7 @@ EXEC_LDFLAGS+=" -ldl"
|
||||
|
||||
PLATFORM_LDFLAGS="$LIBGCC_LIBS $GLIBC_LIBS $STDLIBS -lgcc -lstdc++"
|
||||
|
||||
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $TBB_LIBS"
|
||||
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $TBB_LIBS $LIBURING_LIBS"
|
||||
|
||||
VALGRIND_VER="$VALGRIND_BASE/bin/"
|
||||
|
||||
|
||||
@@ -13,9 +13,14 @@ then
|
||||
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 http://goo.gl/iUW1u2 -o ${CLANG_FORMAT_DIFF}"
|
||||
echo "You can download clang-format by running: "
|
||||
echo "You can download clang-format by running:"
|
||||
echo " brew install clang-format"
|
||||
echo " Or"
|
||||
echo " apt install clang-format"
|
||||
echo " This might work too:"
|
||||
echo " yum install git-clang-format"
|
||||
echo "Then, move both files (i.e. ${CLANG_FORMAT_DIFF} and clang-format) to some directory within PATH=${PATH}"
|
||||
echo "and make sure ${CLANG_FORMAT_DIFF} is executable."
|
||||
exit 128
|
||||
fi
|
||||
|
||||
|
||||
@@ -5801,7 +5801,7 @@ sub workdir {
|
||||
. "-" . $self->seq();
|
||||
} else {
|
||||
$workdir = $opt::workdir;
|
||||
# Rsync treats /./ special. We dont want that
|
||||
# Rsync treats /./ special. We don't want that
|
||||
$workdir =~ s:/\./:/:g; # Remove /./
|
||||
$workdir =~ s:/+$::; # Remove ending / if any
|
||||
$workdir =~ s:^\./::g; # Remove starting ./ if any
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/local/fbcode/gcc-4.9-glibc-2.20-fb/bin/python2.7
|
||||
#!/usr/bin/env python2.7
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
@@ -378,7 +378,7 @@ function send_to_ods {
|
||||
echo >&2 "ERROR: Key $key doesn't have a value."
|
||||
return
|
||||
fi
|
||||
curl -s "https://www.intern.facebook.com/intern/agent/ods_set.php?entity=rocksdb_build$git_br&key=$key&value=$value" \
|
||||
curl --silent "https://www.intern.facebook.com/intern/agent/ods_set.php?entity=rocksdb_build$git_br&key=$key&value=$value" \
|
||||
--connect-timeout 60
|
||||
}
|
||||
|
||||
|
||||
@@ -414,7 +414,8 @@ STRESS_CRASH_TEST_COMMANDS="[
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 crash_test || $CONTRUN_NAME=crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -450,6 +451,36 @@ STRESS_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB stress/crash test with txn
|
||||
#
|
||||
STRESS_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb Stress and Crash Test with txn',
|
||||
'oncall':'$ONCALL',
|
||||
'executeLocal': 'true',
|
||||
'timeout': 86400,
|
||||
'steps': [
|
||||
$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',
|
||||
'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',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
]"
|
||||
|
||||
# RocksDB write stress test.
|
||||
# We run on disk device on purpose (i.e. no $SHM)
|
||||
# because we want to add some randomness to fsync commands
|
||||
@@ -512,6 +543,7 @@ ASAN_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -541,6 +573,30 @@ ASAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB crash testing with txn under address sanitizer
|
||||
#
|
||||
ASAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb crash test with txn under ASAN',
|
||||
'oncall':'$ONCALL',
|
||||
'executeLocal': 'true',
|
||||
'timeout': 86400,
|
||||
'steps': [
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'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',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB test under undefined behavior sanitizer
|
||||
#
|
||||
@@ -553,7 +609,7 @@ UBSAN_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Test RocksDB debug under UBSAN',
|
||||
'shell':'set -o pipefail && $SHM $UBSAN $DEBUG make $PARALLELISM ubsan_check || $CONTRUN_NAME=ubsan_check $TASK_CREATION_TOOL',
|
||||
'shell':'set -o pipefail && $SHM $UBSAN $CLANG $DEBUG make $PARALLELISM ubsan_check || $CONTRUN_NAME=ubsan_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
@@ -576,10 +632,11 @@ UBSAN_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Build and run RocksDB debug ubsan_crash_test',
|
||||
'timeout': 86400,
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH make J=1 ubsan_crash_test || $CONTRUN_NAME=ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'shell':'$SHM $DEBUG $NON_TSAN_CRASH $CLANG make J=1 ubsan_crash_test || $CONTRUN_NAME=ubsan_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -599,7 +656,31 @@ 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 make J=1 ubsan_crash_test_with_atomic_flush || $CONTRUN_NAME=ubsan_crash_test_with_atomic_flush $TASK_CREATION_TOOL',
|
||||
'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',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB crash testing with txn under undefined behavior sanitizer
|
||||
#
|
||||
UBSAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb crash test with txn under UBSAN',
|
||||
'oncall':'$ONCALL',
|
||||
'executeLocal': 'true',
|
||||
'timeout': 86400,
|
||||
'steps': [
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'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',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -673,6 +754,7 @@ TSAN_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -702,6 +784,30 @@ TSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB crash test with txn under TSAN
|
||||
#
|
||||
TSAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb Crash Test with txn under TSAN',
|
||||
'oncall':'$ONCALL',
|
||||
'executeLocal': 'true',
|
||||
'timeout': 86400,
|
||||
'steps': [
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'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',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB format compatible
|
||||
#
|
||||
@@ -778,7 +884,7 @@ run_regression()
|
||||
|
||||
# parameters: $1 -- key, $2 -- value
|
||||
function send_size_to_ods {
|
||||
curl -s "https://www.intern.facebook.com/intern/agent/ods_set.php?entity=rocksdb_build&key=rocksdb.build_size.$1&value=$2" \
|
||||
curl --silent "https://www.intern.facebook.com/intern/agent/ods_set.php?entity=rocksdb_build&key=rocksdb.build_size.$1&value=$2" \
|
||||
--connect-timeout 60
|
||||
}
|
||||
|
||||
@@ -889,6 +995,9 @@ case $1 in
|
||||
stress_crash_with_atomic_flush)
|
||||
echo $STRESS_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS
|
||||
;;
|
||||
stress_crash_with_txn)
|
||||
echo $STRESS_CRASH_TEST_WITH_TXN_COMMANDS
|
||||
;;
|
||||
write_stress)
|
||||
echo $WRITE_STRESS_COMMANDS
|
||||
;;
|
||||
@@ -901,6 +1010,9 @@ case $1 in
|
||||
asan_crash_with_atomic_flush)
|
||||
echo $ASAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS
|
||||
;;
|
||||
asan_crash_with_txn)
|
||||
echo $ASAN_CRASH_TEST_WITH_TXN_COMMANDS
|
||||
;;
|
||||
ubsan)
|
||||
echo $UBSAN_TEST_COMMANDS
|
||||
;;
|
||||
@@ -910,6 +1022,9 @@ case $1 in
|
||||
ubsan_crash_with_atomic_flush)
|
||||
echo $UBSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS
|
||||
;;
|
||||
ubsan_crash_with_txn)
|
||||
echo $UBSAN_CRASH_TEST_WITH_TXN_COMMANDS
|
||||
;;
|
||||
valgrind)
|
||||
echo $VALGRIND_TEST_COMMANDS
|
||||
;;
|
||||
@@ -922,6 +1037,9 @@ case $1 in
|
||||
tsan_crash_with_atomic_flush)
|
||||
echo $TSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS
|
||||
;;
|
||||
tsan_crash_with_txn)
|
||||
echo $TSAN_CRASH_TEST_WITH_TXN_COMMANDS
|
||||
;;
|
||||
format_compatible)
|
||||
echo $FORMAT_COMPATIBLE_COMMANDS
|
||||
;;
|
||||
@@ -945,5 +1063,6 @@ case $1 in
|
||||
;;
|
||||
*)
|
||||
echo "Invalid determinator command"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -92,6 +92,7 @@ get_lib_base jemalloc LATEST platform007
|
||||
get_lib_base numa LATEST platform007
|
||||
get_lib_base libunwind LATEST platform007
|
||||
get_lib_base tbb LATEST platform007
|
||||
get_lib_base liburing LATEST platform007
|
||||
|
||||
get_lib_base kernel-headers fb platform007
|
||||
get_lib_base binutils LATEST centos7-native
|
||||
|
||||
Vendored
+4
-4
@@ -45,7 +45,7 @@ DEFINE_int32(erase_percent, 10,
|
||||
|
||||
DEFINE_bool(use_clock_cache, false, "");
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class CacheBench;
|
||||
namespace {
|
||||
@@ -154,7 +154,7 @@ class CacheBench {
|
||||
}
|
||||
|
||||
bool Run() {
|
||||
rocksdb::Env* env = rocksdb::Env::Default();
|
||||
ROCKSDB_NAMESPACE::Env* env = ROCKSDB_NAMESPACE::Env::Default();
|
||||
|
||||
PrintEnv();
|
||||
SharedState shared(this);
|
||||
@@ -257,7 +257,7 @@ class CacheBench {
|
||||
printf("----------------------------\n");
|
||||
}
|
||||
};
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ParseCommandLineFlags(&argc, &argv, true);
|
||||
@@ -267,7 +267,7 @@ int main(int argc, char** argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rocksdb::CacheBench bench;
|
||||
ROCKSDB_NAMESPACE::CacheBench bench;
|
||||
if (FLAGS_populate_cache) {
|
||||
bench.PopulateCache();
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -20,7 +20,7 @@
|
||||
#include "util/coding.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Conversions between numeric keys/values and the types expected by Cache.
|
||||
static std::string EncodeKey(int k) {
|
||||
@@ -365,7 +365,7 @@ TEST_P(CacheTest, EvictionPolicy) {
|
||||
Insert(200, 201);
|
||||
|
||||
// Frequently used entry must be kept around
|
||||
for (int i = 0; i < kCacheSize + 200; i++) {
|
||||
for (int i = 0; i < kCacheSize * 2; i++) {
|
||||
Insert(1000+i, 2000+i);
|
||||
ASSERT_EQ(101, Lookup(100));
|
||||
}
|
||||
@@ -418,7 +418,7 @@ TEST_P(CacheTest, EvictionPolicyRef) {
|
||||
Insert(303, 104);
|
||||
|
||||
// Insert entries much more than Cache capacity
|
||||
for (int i = 0; i < kCacheSize + 200; i++) {
|
||||
for (int i = 0; i < kCacheSize * 2; i++) {
|
||||
Insert(1000 + i, 2000 + i);
|
||||
}
|
||||
|
||||
@@ -765,7 +765,7 @@ INSTANTIATE_TEST_CASE_P(CacheTestInstance, CacheTest, testing::Values(kLRU));
|
||||
#endif // SUPPORT_CLOCK_CACHE
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, LRUCacheTest, testing::Values(kLRU));
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
Vendored
+4
-4
@@ -11,7 +11,7 @@
|
||||
|
||||
#ifndef SUPPORT_CLOCK_CACHE
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
std::shared_ptr<Cache> NewClockCache(
|
||||
size_t /*capacity*/, int /*num_shard_bits*/, bool /*strict_capacity_limit*/,
|
||||
@@ -20,7 +20,7 @@ std::shared_ptr<Cache> NewClockCache(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#else
|
||||
|
||||
@@ -41,7 +41,7 @@ std::shared_ptr<Cache> NewClockCache(
|
||||
#include "util/autovector.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -756,6 +756,6 @@ std::shared_ptr<Cache> NewClockCache(
|
||||
capacity, num_shard_bits, strict_capacity_limit, metadata_charge_policy);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // SUPPORT_CLOCK_CACHE
|
||||
Vendored
+2
-2
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
LRUHandleTable::LRUHandleTable() : list_(nullptr), length_(0), elems_(0) {
|
||||
Resize();
|
||||
@@ -571,4 +571,4 @@ std::shared_ptr<Cache> NewLRUCache(
|
||||
std::move(memory_allocator), use_adaptive_mutex, metadata_charge_policy);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
+2
-3
@@ -16,7 +16,7 @@
|
||||
#include "port/port.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// LRU cache implementation. This class is not thread-safe.
|
||||
|
||||
@@ -133,7 +133,6 @@ struct LRUHandle {
|
||||
// Caclculate the memory usage by metadata
|
||||
inline size_t CalcTotalCharge(
|
||||
CacheMetadataChargePolicy metadata_charge_policy) {
|
||||
assert(key_length);
|
||||
size_t meta_charge = 0;
|
||||
if (metadata_charge_policy == kFullChargeCacheMetadata) {
|
||||
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
|
||||
@@ -337,4 +336,4 @@ class LRUCache
|
||||
int num_shards_ = 0;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
+2
-2
@@ -10,7 +10,7 @@
|
||||
#include "port/port.h"
|
||||
#include "test_util/testharness.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class LRUCacheTest : public testing::Test {
|
||||
public:
|
||||
@@ -190,7 +190,7 @@ TEST_F(LRUCacheTest, EntriesWithPriority) {
|
||||
ValidateLRUList({"e", "f", "g", "Z", "d"}, 2);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
Vendored
+2
-2
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
ShardedCache::ShardedCache(size_t capacity, int num_shard_bits,
|
||||
bool strict_capacity_limit,
|
||||
@@ -159,4 +159,4 @@ int GetDefaultCacheShardBits(size_t capacity) {
|
||||
return num_shard_bits;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
+2
-2
@@ -16,7 +16,7 @@
|
||||
#include "rocksdb/cache.h"
|
||||
#include "util/hash.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Single cache shard interface.
|
||||
class CacheShard {
|
||||
@@ -108,4 +108,4 @@ class ShardedCache : public Cache {
|
||||
|
||||
extern int GetDefaultCacheShardBits(size_t capacity);
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,29 @@
|
||||
# - Find gflags library
|
||||
# Find the gflags includes and library
|
||||
#
|
||||
# gflags_INCLUDE_DIR - where to find gflags.h.
|
||||
# gflags_LIBRARIES - List of libraries when using gflags.
|
||||
# gflags_FOUND - True if gflags found.
|
||||
|
||||
find_path(GFLAGS_INCLUDE_DIR
|
||||
NAMES gflags/gflags.h)
|
||||
|
||||
find_library(GFLAGS_LIBRARIES
|
||||
NAMES gflags)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(gflags
|
||||
DEFAULT_MSG GFLAGS_LIBRARIES GFLAGS_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(
|
||||
GFLAGS_LIBRARIES
|
||||
GFLAGS_INCLUDE_DIR)
|
||||
|
||||
if(gflags_FOUND AND NOT (TARGET gflags::gflags))
|
||||
add_library(gflags::gflags UNKNOWN IMPORTED)
|
||||
set_target_properties(gflags::gflags
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${GFLAGS_LIBRARIES}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${GFLAGS_INCLUDE_DIR}
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "CXX")
|
||||
endif()
|
||||
@@ -1,7 +1,7 @@
|
||||
# Read rocksdb version from version.h header file.
|
||||
|
||||
function(get_rocksdb_version version_var)
|
||||
file(READ "${CMAKE_SOURCE_DIR}/include/rocksdb/version.h" version_header_file)
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/include/rocksdb/version.h" version_header_file)
|
||||
foreach(component MAJOR MINOR PATCH)
|
||||
string(REGEX MATCH "#define ROCKSDB_${component} ([0-9]+)" _ ${version_header_file})
|
||||
set(ROCKSDB_VERSION_${component} ${CMAKE_MATCH_1})
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "table/iterator_wrapper.h"
|
||||
#include "util/user_comparator_wrapper.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
|
||||
std::string* prop) {
|
||||
@@ -64,7 +64,7 @@ Status ArenaWrappedDBIter::Refresh() {
|
||||
arena_.~Arena();
|
||||
new (&arena_) Arena();
|
||||
|
||||
SuperVersion* sv = cfd_->GetReferencedSuperVersion(db_impl_->mutex());
|
||||
SuperVersion* sv = cfd_->GetReferencedSuperVersion(db_impl_);
|
||||
if (read_callback_) {
|
||||
read_callback_->Refresh(latest_seq);
|
||||
}
|
||||
@@ -103,4 +103,4 @@ ArenaWrappedDBIter* NewArenaWrappedDbIterator(
|
||||
return iter;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+18
-15
@@ -20,7 +20,7 @@
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class Arena;
|
||||
|
||||
@@ -45,26 +45,29 @@ class ArenaWrappedDBIter : public Iterator {
|
||||
// Set the internal iterator wrapped inside the DB Iterator. Usually it is
|
||||
// a merging iterator.
|
||||
virtual void SetIterUnderDBIter(InternalIterator* iter) {
|
||||
static_cast<DBIter*>(db_iter_)->SetIter(iter);
|
||||
db_iter_->SetIter(iter);
|
||||
}
|
||||
|
||||
virtual bool Valid() const override { return db_iter_->Valid(); }
|
||||
virtual void SeekToFirst() override { db_iter_->SeekToFirst(); }
|
||||
virtual void SeekToLast() override { db_iter_->SeekToLast(); }
|
||||
virtual void Seek(const Slice& target) override { db_iter_->Seek(target); }
|
||||
virtual void SeekForPrev(const Slice& target) override {
|
||||
bool Valid() const override { return db_iter_->Valid(); }
|
||||
void SeekToFirst() override { db_iter_->SeekToFirst(); }
|
||||
void SeekToLast() override { db_iter_->SeekToLast(); }
|
||||
// 'target' does not contain timestamp, even if user timestamp feature is
|
||||
// enabled.
|
||||
void Seek(const Slice& target) override { db_iter_->Seek(target); }
|
||||
void SeekForPrev(const Slice& target) override {
|
||||
db_iter_->SeekForPrev(target);
|
||||
}
|
||||
virtual void Next() override { db_iter_->Next(); }
|
||||
virtual void Prev() override { db_iter_->Prev(); }
|
||||
virtual Slice key() const override { return db_iter_->key(); }
|
||||
virtual Slice value() const override { return db_iter_->value(); }
|
||||
virtual Status status() const override { return db_iter_->status(); }
|
||||
void Next() override { db_iter_->Next(); }
|
||||
void Prev() override { db_iter_->Prev(); }
|
||||
Slice key() const override { return db_iter_->key(); }
|
||||
Slice value() const override { return db_iter_->value(); }
|
||||
Status status() const override { return db_iter_->status(); }
|
||||
Slice timestamp() const override { return db_iter_->timestamp(); }
|
||||
bool IsBlob() const { return db_iter_->IsBlob(); }
|
||||
|
||||
virtual Status GetProperty(std::string prop_name, std::string* prop) override;
|
||||
Status GetProperty(std::string prop_name, std::string* prop) override;
|
||||
|
||||
virtual Status Refresh() override;
|
||||
Status Refresh() override;
|
||||
|
||||
void Init(Env* env, const ReadOptions& read_options,
|
||||
const ImmutableCFOptions& cf_options,
|
||||
@@ -109,4 +112,4 @@ extern ArenaWrappedDBIter* NewArenaWrappedDbIterator(
|
||||
ReadCallback* read_callback, DBImpl* db_impl = nullptr,
|
||||
ColumnFamilyData* cfd = nullptr, bool allow_blob = false,
|
||||
bool allow_refresh = true);
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
constexpr uint64_t kInvalidBlobFileNumber = 0;
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/blob/blob_file_addition.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "logging/event_logger.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Tags for custom fields. Note that these get persisted in the manifest,
|
||||
// so existing tags should not be modified.
|
||||
enum BlobFileAddition::CustomFieldTags : uint32_t {
|
||||
kEndMarker,
|
||||
|
||||
// Add forward compatible fields here
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
kForwardIncompatibleMask = 1 << 6,
|
||||
|
||||
// Add forward incompatible fields here
|
||||
};
|
||||
|
||||
void BlobFileAddition::EncodeTo(std::string* output) const {
|
||||
PutVarint64(output, blob_file_number_);
|
||||
PutVarint64(output, total_blob_count_);
|
||||
PutVarint64(output, total_blob_bytes_);
|
||||
PutLengthPrefixedSlice(output, checksum_method_);
|
||||
PutLengthPrefixedSlice(output, checksum_value_);
|
||||
|
||||
// Encode any custom fields here. The format to use is a Varint32 tag (see
|
||||
// CustomFieldTags above) followed by a length prefixed slice. Unknown custom
|
||||
// fields will be ignored during decoding unless they're in the forward
|
||||
// incompatible range.
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("BlobFileAddition::EncodeTo::CustomFields", output);
|
||||
|
||||
PutVarint32(output, kEndMarker);
|
||||
}
|
||||
|
||||
Status BlobFileAddition::DecodeFrom(Slice* input) {
|
||||
constexpr char class_name[] = "BlobFileAddition";
|
||||
|
||||
if (!GetVarint64(input, &blob_file_number_)) {
|
||||
return Status::Corruption(class_name, "Error decoding blob file number");
|
||||
}
|
||||
|
||||
if (!GetVarint64(input, &total_blob_count_)) {
|
||||
return Status::Corruption(class_name, "Error decoding total blob count");
|
||||
}
|
||||
|
||||
if (!GetVarint64(input, &total_blob_bytes_)) {
|
||||
return Status::Corruption(class_name, "Error decoding total blob bytes");
|
||||
}
|
||||
|
||||
Slice checksum_method;
|
||||
if (!GetLengthPrefixedSlice(input, &checksum_method)) {
|
||||
return Status::Corruption(class_name, "Error decoding checksum method");
|
||||
}
|
||||
checksum_method_ = checksum_method.ToString();
|
||||
|
||||
Slice checksum_value;
|
||||
if (!GetLengthPrefixedSlice(input, &checksum_value)) {
|
||||
return Status::Corruption(class_name, "Error decoding checksum value");
|
||||
}
|
||||
checksum_value_ = checksum_value.ToString();
|
||||
|
||||
while (true) {
|
||||
uint32_t custom_field_tag = 0;
|
||||
if (!GetVarint32(input, &custom_field_tag)) {
|
||||
return Status::Corruption(class_name, "Error decoding custom field tag");
|
||||
}
|
||||
|
||||
if (custom_field_tag == kEndMarker) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (custom_field_tag & kForwardIncompatibleMask) {
|
||||
return Status::Corruption(
|
||||
class_name, "Forward incompatible custom field encountered");
|
||||
}
|
||||
|
||||
Slice custom_field_value;
|
||||
if (!GetLengthPrefixedSlice(input, &custom_field_value)) {
|
||||
return Status::Corruption(class_name,
|
||||
"Error decoding custom field value");
|
||||
}
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string BlobFileAddition::DebugString() const {
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << *this;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string BlobFileAddition::DebugJSON() const {
|
||||
JSONWriter jw;
|
||||
|
||||
jw << *this;
|
||||
|
||||
jw.EndObject();
|
||||
|
||||
return jw.Get();
|
||||
}
|
||||
|
||||
bool operator==(const BlobFileAddition& lhs, const BlobFileAddition& rhs) {
|
||||
return lhs.GetBlobFileNumber() == rhs.GetBlobFileNumber() &&
|
||||
lhs.GetTotalBlobCount() == rhs.GetTotalBlobCount() &&
|
||||
lhs.GetTotalBlobBytes() == rhs.GetTotalBlobBytes() &&
|
||||
lhs.GetChecksumMethod() == rhs.GetChecksumMethod() &&
|
||||
lhs.GetChecksumValue() == rhs.GetChecksumValue();
|
||||
}
|
||||
|
||||
bool operator!=(const BlobFileAddition& lhs, const BlobFileAddition& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const BlobFileAddition& blob_file_addition) {
|
||||
os << "blob_file_number: " << blob_file_addition.GetBlobFileNumber()
|
||||
<< " total_blob_count: " << blob_file_addition.GetTotalBlobCount()
|
||||
<< " total_blob_bytes: " << blob_file_addition.GetTotalBlobBytes()
|
||||
<< " checksum_method: " << blob_file_addition.GetChecksumMethod()
|
||||
<< " checksum_value: " << blob_file_addition.GetChecksumValue();
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
JSONWriter& operator<<(JSONWriter& jw,
|
||||
const BlobFileAddition& blob_file_addition) {
|
||||
jw << "BlobFileNumber" << blob_file_addition.GetBlobFileNumber()
|
||||
<< "TotalBlobCount" << blob_file_addition.GetTotalBlobCount()
|
||||
<< "TotalBlobBytes" << blob_file_addition.GetTotalBlobBytes()
|
||||
<< "ChecksumMethod" << blob_file_addition.GetChecksumMethod()
|
||||
<< "ChecksumValue" << blob_file_addition.GetChecksumValue();
|
||||
|
||||
return jw;
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "db/blob/blob_constants.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class JSONWriter;
|
||||
class Slice;
|
||||
class Status;
|
||||
|
||||
class BlobFileAddition {
|
||||
public:
|
||||
BlobFileAddition() = default;
|
||||
|
||||
BlobFileAddition(uint64_t blob_file_number, uint64_t total_blob_count,
|
||||
uint64_t total_blob_bytes, std::string checksum_method,
|
||||
std::string checksum_value)
|
||||
: blob_file_number_(blob_file_number),
|
||||
total_blob_count_(total_blob_count),
|
||||
total_blob_bytes_(total_blob_bytes),
|
||||
checksum_method_(std::move(checksum_method)),
|
||||
checksum_value_(std::move(checksum_value)) {
|
||||
assert(checksum_method_.empty() == checksum_value_.empty());
|
||||
}
|
||||
|
||||
uint64_t GetBlobFileNumber() const { return blob_file_number_; }
|
||||
uint64_t GetTotalBlobCount() const { return total_blob_count_; }
|
||||
uint64_t GetTotalBlobBytes() const { return total_blob_bytes_; }
|
||||
const std::string& GetChecksumMethod() const { return checksum_method_; }
|
||||
const std::string& GetChecksumValue() const { return checksum_value_; }
|
||||
|
||||
void EncodeTo(std::string* output) const;
|
||||
Status DecodeFrom(Slice* input);
|
||||
|
||||
std::string DebugString() const;
|
||||
std::string DebugJSON() const;
|
||||
|
||||
private:
|
||||
enum CustomFieldTags : uint32_t;
|
||||
|
||||
uint64_t blob_file_number_ = kInvalidBlobFileNumber;
|
||||
uint64_t total_blob_count_ = 0;
|
||||
uint64_t total_blob_bytes_ = 0;
|
||||
std::string checksum_method_;
|
||||
std::string checksum_value_;
|
||||
};
|
||||
|
||||
bool operator==(const BlobFileAddition& lhs, const BlobFileAddition& rhs);
|
||||
bool operator!=(const BlobFileAddition& lhs, const BlobFileAddition& rhs);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const BlobFileAddition& blob_file_addition);
|
||||
JSONWriter& operator<<(JSONWriter& jw,
|
||||
const BlobFileAddition& blob_file_addition);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,206 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/blob/blob_file_addition.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class BlobFileAdditionTest : public testing::Test {
|
||||
public:
|
||||
static void TestEncodeDecode(const BlobFileAddition& blob_file_addition) {
|
||||
std::string encoded;
|
||||
blob_file_addition.EncodeTo(&encoded);
|
||||
|
||||
BlobFileAddition decoded;
|
||||
Slice input(encoded);
|
||||
ASSERT_OK(decoded.DecodeFrom(&input));
|
||||
|
||||
ASSERT_EQ(blob_file_addition, decoded);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BlobFileAdditionTest, Empty) {
|
||||
BlobFileAddition blob_file_addition;
|
||||
|
||||
ASSERT_EQ(blob_file_addition.GetBlobFileNumber(), kInvalidBlobFileNumber);
|
||||
ASSERT_EQ(blob_file_addition.GetTotalBlobCount(), 0);
|
||||
ASSERT_EQ(blob_file_addition.GetTotalBlobBytes(), 0);
|
||||
ASSERT_TRUE(blob_file_addition.GetChecksumMethod().empty());
|
||||
ASSERT_TRUE(blob_file_addition.GetChecksumValue().empty());
|
||||
|
||||
TestEncodeDecode(blob_file_addition);
|
||||
}
|
||||
|
||||
TEST_F(BlobFileAdditionTest, NonEmpty) {
|
||||
constexpr uint64_t blob_file_number = 123;
|
||||
constexpr uint64_t total_blob_count = 2;
|
||||
constexpr uint64_t total_blob_bytes = 123456;
|
||||
const std::string checksum_method("SHA1");
|
||||
const std::string checksum_value("bdb7f34a59dfa1592ce7f52e99f98c570c525cbd");
|
||||
|
||||
BlobFileAddition blob_file_addition(blob_file_number, total_blob_count,
|
||||
total_blob_bytes, checksum_method,
|
||||
checksum_value);
|
||||
|
||||
ASSERT_EQ(blob_file_addition.GetBlobFileNumber(), blob_file_number);
|
||||
ASSERT_EQ(blob_file_addition.GetTotalBlobCount(), total_blob_count);
|
||||
ASSERT_EQ(blob_file_addition.GetTotalBlobBytes(), total_blob_bytes);
|
||||
ASSERT_EQ(blob_file_addition.GetChecksumMethod(), checksum_method);
|
||||
ASSERT_EQ(blob_file_addition.GetChecksumValue(), checksum_value);
|
||||
|
||||
TestEncodeDecode(blob_file_addition);
|
||||
}
|
||||
|
||||
TEST_F(BlobFileAdditionTest, DecodeErrors) {
|
||||
std::string str;
|
||||
Slice slice(str);
|
||||
|
||||
BlobFileAddition blob_file_addition;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "blob file number"));
|
||||
}
|
||||
|
||||
constexpr uint64_t blob_file_number = 123;
|
||||
PutVarint64(&str, blob_file_number);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "total blob count"));
|
||||
}
|
||||
|
||||
constexpr uint64_t total_blob_count = 4567;
|
||||
PutVarint64(&str, total_blob_count);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "total blob bytes"));
|
||||
}
|
||||
|
||||
constexpr uint64_t total_blob_bytes = 12345678;
|
||||
PutVarint64(&str, total_blob_bytes);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "checksum method"));
|
||||
}
|
||||
|
||||
constexpr char checksum_method[] = "SHA1";
|
||||
PutLengthPrefixedSlice(&str, checksum_method);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "checksum value"));
|
||||
}
|
||||
|
||||
constexpr char checksum_value[] = "bdb7f34a59dfa1592ce7f52e99f98c570c525cbd";
|
||||
PutLengthPrefixedSlice(&str, checksum_value);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "custom field tag"));
|
||||
}
|
||||
|
||||
constexpr uint32_t custom_tag = 2;
|
||||
PutVarint32(&str, custom_tag);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_addition.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "custom field value"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BlobFileAdditionTest, ForwardCompatibleCustomField) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BlobFileAddition::EncodeTo::CustomFields", [&](void* arg) {
|
||||
std::string* output = static_cast<std::string*>(arg);
|
||||
|
||||
constexpr uint32_t forward_compatible_tag = 2;
|
||||
PutVarint32(output, forward_compatible_tag);
|
||||
|
||||
PutLengthPrefixedSlice(output, "deadbeef");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
constexpr uint64_t blob_file_number = 678;
|
||||
constexpr uint64_t total_blob_count = 9999;
|
||||
constexpr uint64_t total_blob_bytes = 100000000;
|
||||
const std::string checksum_method("CRC32");
|
||||
const std::string checksum_value("3d87ff57");
|
||||
|
||||
BlobFileAddition blob_file_addition(blob_file_number, total_blob_count,
|
||||
total_blob_bytes, checksum_method,
|
||||
checksum_value);
|
||||
|
||||
TestEncodeDecode(blob_file_addition);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_F(BlobFileAdditionTest, ForwardIncompatibleCustomField) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BlobFileAddition::EncodeTo::CustomFields", [&](void* arg) {
|
||||
std::string* output = static_cast<std::string*>(arg);
|
||||
|
||||
constexpr uint32_t forward_incompatible_tag = (1 << 6) + 1;
|
||||
PutVarint32(output, forward_incompatible_tag);
|
||||
|
||||
PutLengthPrefixedSlice(output, "foobar");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
constexpr uint64_t blob_file_number = 456;
|
||||
constexpr uint64_t total_blob_count = 100;
|
||||
constexpr uint64_t total_blob_bytes = 2000000;
|
||||
const std::string checksum_method("CRC32B");
|
||||
const std::string checksum_value("6dbdf23a");
|
||||
|
||||
BlobFileAddition blob_file_addition(blob_file_number, total_blob_count,
|
||||
total_blob_bytes, checksum_method,
|
||||
checksum_value);
|
||||
|
||||
std::string encoded;
|
||||
blob_file_addition.EncodeTo(&encoded);
|
||||
|
||||
BlobFileAddition decoded_blob_file_addition;
|
||||
Slice input(encoded);
|
||||
const Status s = decoded_blob_file_addition.DecodeFrom(&input);
|
||||
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "Forward incompatible"));
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/blob/blob_file_garbage.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "logging/event_logger.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Tags for custom fields. Note that these get persisted in the manifest,
|
||||
// so existing tags should not be modified.
|
||||
enum BlobFileGarbage::CustomFieldTags : uint32_t {
|
||||
kEndMarker,
|
||||
|
||||
// Add forward compatible fields here
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
kForwardIncompatibleMask = 1 << 6,
|
||||
|
||||
// Add forward incompatible fields here
|
||||
};
|
||||
|
||||
void BlobFileGarbage::EncodeTo(std::string* output) const {
|
||||
PutVarint64(output, blob_file_number_);
|
||||
PutVarint64(output, garbage_blob_count_);
|
||||
PutVarint64(output, garbage_blob_bytes_);
|
||||
|
||||
// Encode any custom fields here. The format to use is a Varint32 tag (see
|
||||
// CustomFieldTags above) followed by a length prefixed slice. Unknown custom
|
||||
// fields will be ignored during decoding unless they're in the forward
|
||||
// incompatible range.
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("BlobFileGarbage::EncodeTo::CustomFields", output);
|
||||
|
||||
PutVarint32(output, kEndMarker);
|
||||
}
|
||||
|
||||
Status BlobFileGarbage::DecodeFrom(Slice* input) {
|
||||
constexpr char class_name[] = "BlobFileGarbage";
|
||||
|
||||
if (!GetVarint64(input, &blob_file_number_)) {
|
||||
return Status::Corruption(class_name, "Error decoding blob file number");
|
||||
}
|
||||
|
||||
if (!GetVarint64(input, &garbage_blob_count_)) {
|
||||
return Status::Corruption(class_name, "Error decoding garbage blob count");
|
||||
}
|
||||
|
||||
if (!GetVarint64(input, &garbage_blob_bytes_)) {
|
||||
return Status::Corruption(class_name, "Error decoding garbage blob bytes");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
uint32_t custom_field_tag = 0;
|
||||
if (!GetVarint32(input, &custom_field_tag)) {
|
||||
return Status::Corruption(class_name, "Error decoding custom field tag");
|
||||
}
|
||||
|
||||
if (custom_field_tag == kEndMarker) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (custom_field_tag & kForwardIncompatibleMask) {
|
||||
return Status::Corruption(
|
||||
class_name, "Forward incompatible custom field encountered");
|
||||
}
|
||||
|
||||
Slice custom_field_value;
|
||||
if (!GetLengthPrefixedSlice(input, &custom_field_value)) {
|
||||
return Status::Corruption(class_name,
|
||||
"Error decoding custom field value");
|
||||
}
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string BlobFileGarbage::DebugString() const {
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << *this;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string BlobFileGarbage::DebugJSON() const {
|
||||
JSONWriter jw;
|
||||
|
||||
jw << *this;
|
||||
|
||||
jw.EndObject();
|
||||
|
||||
return jw.Get();
|
||||
}
|
||||
|
||||
bool operator==(const BlobFileGarbage& lhs, const BlobFileGarbage& rhs) {
|
||||
return lhs.GetBlobFileNumber() == rhs.GetBlobFileNumber() &&
|
||||
lhs.GetGarbageBlobCount() == rhs.GetGarbageBlobCount() &&
|
||||
lhs.GetGarbageBlobBytes() == rhs.GetGarbageBlobBytes();
|
||||
}
|
||||
|
||||
bool operator!=(const BlobFileGarbage& lhs, const BlobFileGarbage& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const BlobFileGarbage& blob_file_garbage) {
|
||||
os << "blob_file_number: " << blob_file_garbage.GetBlobFileNumber()
|
||||
<< " garbage_blob_count: " << blob_file_garbage.GetGarbageBlobCount()
|
||||
<< " garbage_blob_bytes: " << blob_file_garbage.GetGarbageBlobBytes();
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
JSONWriter& operator<<(JSONWriter& jw,
|
||||
const BlobFileGarbage& blob_file_garbage) {
|
||||
jw << "BlobFileNumber" << blob_file_garbage.GetBlobFileNumber()
|
||||
<< "GarbageBlobCount" << blob_file_garbage.GetGarbageBlobCount()
|
||||
<< "GarbageBlobBytes" << blob_file_garbage.GetGarbageBlobBytes();
|
||||
|
||||
return jw;
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "db/blob/blob_constants.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class JSONWriter;
|
||||
class Slice;
|
||||
class Status;
|
||||
|
||||
class BlobFileGarbage {
|
||||
public:
|
||||
BlobFileGarbage() = default;
|
||||
|
||||
BlobFileGarbage(uint64_t blob_file_number, uint64_t garbage_blob_count,
|
||||
uint64_t garbage_blob_bytes)
|
||||
: blob_file_number_(blob_file_number),
|
||||
garbage_blob_count_(garbage_blob_count),
|
||||
garbage_blob_bytes_(garbage_blob_bytes) {}
|
||||
|
||||
uint64_t GetBlobFileNumber() const { return blob_file_number_; }
|
||||
uint64_t GetGarbageBlobCount() const { return garbage_blob_count_; }
|
||||
uint64_t GetGarbageBlobBytes() const { return garbage_blob_bytes_; }
|
||||
|
||||
void EncodeTo(std::string* output) const;
|
||||
Status DecodeFrom(Slice* input);
|
||||
|
||||
std::string DebugString() const;
|
||||
std::string DebugJSON() const;
|
||||
|
||||
private:
|
||||
enum CustomFieldTags : uint32_t;
|
||||
|
||||
uint64_t blob_file_number_ = kInvalidBlobFileNumber;
|
||||
uint64_t garbage_blob_count_ = 0;
|
||||
uint64_t garbage_blob_bytes_ = 0;
|
||||
};
|
||||
|
||||
bool operator==(const BlobFileGarbage& lhs, const BlobFileGarbage& rhs);
|
||||
bool operator!=(const BlobFileGarbage& lhs, const BlobFileGarbage& rhs);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const BlobFileGarbage& blob_file_garbage);
|
||||
JSONWriter& operator<<(JSONWriter& jw,
|
||||
const BlobFileGarbage& blob_file_garbage);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -0,0 +1,173 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include "db/blob/blob_file_garbage.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class BlobFileGarbageTest : public testing::Test {
|
||||
public:
|
||||
static void TestEncodeDecode(const BlobFileGarbage& blob_file_garbage) {
|
||||
std::string encoded;
|
||||
blob_file_garbage.EncodeTo(&encoded);
|
||||
|
||||
BlobFileGarbage decoded;
|
||||
Slice input(encoded);
|
||||
ASSERT_OK(decoded.DecodeFrom(&input));
|
||||
|
||||
ASSERT_EQ(blob_file_garbage, decoded);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BlobFileGarbageTest, Empty) {
|
||||
BlobFileGarbage blob_file_garbage;
|
||||
|
||||
ASSERT_EQ(blob_file_garbage.GetBlobFileNumber(), kInvalidBlobFileNumber);
|
||||
ASSERT_EQ(blob_file_garbage.GetGarbageBlobCount(), 0);
|
||||
ASSERT_EQ(blob_file_garbage.GetGarbageBlobBytes(), 0);
|
||||
|
||||
TestEncodeDecode(blob_file_garbage);
|
||||
}
|
||||
|
||||
TEST_F(BlobFileGarbageTest, NonEmpty) {
|
||||
constexpr uint64_t blob_file_number = 123;
|
||||
constexpr uint64_t garbage_blob_count = 1;
|
||||
constexpr uint64_t garbage_blob_bytes = 9876;
|
||||
|
||||
BlobFileGarbage blob_file_garbage(blob_file_number, garbage_blob_count,
|
||||
garbage_blob_bytes);
|
||||
|
||||
ASSERT_EQ(blob_file_garbage.GetBlobFileNumber(), blob_file_number);
|
||||
ASSERT_EQ(blob_file_garbage.GetGarbageBlobCount(), garbage_blob_count);
|
||||
ASSERT_EQ(blob_file_garbage.GetGarbageBlobBytes(), garbage_blob_bytes);
|
||||
|
||||
TestEncodeDecode(blob_file_garbage);
|
||||
}
|
||||
|
||||
TEST_F(BlobFileGarbageTest, DecodeErrors) {
|
||||
std::string str;
|
||||
Slice slice(str);
|
||||
|
||||
BlobFileGarbage blob_file_garbage;
|
||||
|
||||
{
|
||||
const Status s = blob_file_garbage.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "blob file number"));
|
||||
}
|
||||
|
||||
constexpr uint64_t blob_file_number = 123;
|
||||
PutVarint64(&str, blob_file_number);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_garbage.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "garbage blob count"));
|
||||
}
|
||||
|
||||
constexpr uint64_t garbage_blob_count = 4567;
|
||||
PutVarint64(&str, garbage_blob_count);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_garbage.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "garbage blob bytes"));
|
||||
}
|
||||
|
||||
constexpr uint64_t garbage_blob_bytes = 12345678;
|
||||
PutVarint64(&str, garbage_blob_bytes);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_garbage.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "custom field tag"));
|
||||
}
|
||||
|
||||
constexpr uint32_t custom_tag = 2;
|
||||
PutVarint32(&str, custom_tag);
|
||||
slice = str;
|
||||
|
||||
{
|
||||
const Status s = blob_file_garbage.DecodeFrom(&slice);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "custom field value"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BlobFileGarbageTest, ForwardCompatibleCustomField) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BlobFileGarbage::EncodeTo::CustomFields", [&](void* arg) {
|
||||
std::string* output = static_cast<std::string*>(arg);
|
||||
|
||||
constexpr uint32_t forward_compatible_tag = 2;
|
||||
PutVarint32(output, forward_compatible_tag);
|
||||
|
||||
PutLengthPrefixedSlice(output, "deadbeef");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
constexpr uint64_t blob_file_number = 678;
|
||||
constexpr uint64_t garbage_blob_count = 9999;
|
||||
constexpr uint64_t garbage_blob_bytes = 100000000;
|
||||
|
||||
BlobFileGarbage blob_file_garbage(blob_file_number, garbage_blob_count,
|
||||
garbage_blob_bytes);
|
||||
|
||||
TestEncodeDecode(blob_file_garbage);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_F(BlobFileGarbageTest, ForwardIncompatibleCustomField) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BlobFileGarbage::EncodeTo::CustomFields", [&](void* arg) {
|
||||
std::string* output = static_cast<std::string*>(arg);
|
||||
|
||||
constexpr uint32_t forward_incompatible_tag = (1 << 6) + 1;
|
||||
PutVarint32(output, forward_incompatible_tag);
|
||||
|
||||
PutLengthPrefixedSlice(output, "foobar");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
constexpr uint64_t blob_file_number = 456;
|
||||
constexpr uint64_t garbage_blob_count = 100;
|
||||
constexpr uint64_t garbage_blob_bytes = 2000000;
|
||||
|
||||
BlobFileGarbage blob_file_garbage(blob_file_number, garbage_blob_count,
|
||||
garbage_blob_bytes);
|
||||
|
||||
std::string encoded;
|
||||
blob_file_garbage.EncodeTo(&encoded);
|
||||
|
||||
BlobFileGarbage decoded_blob_file_addition;
|
||||
Slice input(encoded);
|
||||
const Status s = decoded_blob_file_addition.DecodeFrom(&input);
|
||||
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "Forward incompatible"));
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -5,11 +5,14 @@
|
||||
#pragma once
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "rocksdb/options.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// BlobIndex is a pointer to the blob and metadata of the blob. The index is
|
||||
// stored in base DB as ValueType::kTypeBlobIndex.
|
||||
@@ -108,6 +111,23 @@ class BlobIndex {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string DebugString(bool output_hex) const {
|
||||
std::ostringstream oss;
|
||||
|
||||
if (IsInlined()) {
|
||||
oss << "[inlined blob] value:" << value_.ToString(output_hex);
|
||||
} else {
|
||||
oss << "[blob ref] file:" << file_number_ << " offset:" << offset_
|
||||
<< " size:" << size_;
|
||||
}
|
||||
|
||||
if (HasTTL()) {
|
||||
oss << " exp:" << expiration_;
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static void EncodeInlinedTTL(std::string* dst, uint64_t expiration,
|
||||
const Slice& value) {
|
||||
assert(dst != nullptr);
|
||||
@@ -155,5 +175,5 @@ class BlobIndex {
|
||||
CompressionType compression_ = kNoCompression;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // ROCKSDB_LITE
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// kTypeBlobIndex is a value type used by BlobDB only. The base rocksdb
|
||||
// should accept the value type on write, and report not supported value
|
||||
@@ -398,16 +398,39 @@ TEST_F(DBBlobIndexTest, Iterate) {
|
||||
verify(15, Status::kOk, get_value(16, 0), get_value(14, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
// Iterator with blob support and using seek.
|
||||
ASSERT_OK(dbfull()->SetOptions(
|
||||
cfh(), {{"max_sequential_skip_in_iterations", "0"}}));
|
||||
verify(1, Status::kOk, get_value(1, 0), get_value(1, 0),
|
||||
create_blob_iterator, check_is_blob(true));
|
||||
verify(3, Status::kOk, get_value(3, 0), get_value(3, 0),
|
||||
create_blob_iterator, check_is_blob(true));
|
||||
verify(5, Status::kOk, get_value(5, 0), get_value(5, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(7, Status::kOk, get_value(8, 0), get_value(6, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(9, Status::kOk, get_value(10, 0), get_value(8, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(11, Status::kNotSupported, "", "", create_blob_iterator);
|
||||
verify(13, Status::kOk,
|
||||
get_value(13, 2) + "," + get_value(13, 1) + "," + get_value(13, 0),
|
||||
get_value(13, 2) + "," + get_value(13, 1) + "," + get_value(13, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
verify(15, Status::kOk, get_value(16, 0), get_value(14, 0),
|
||||
create_blob_iterator, check_is_blob(false));
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
for (auto* snapshot : snapshots) {
|
||||
dbfull()->ReleaseSnapshot(snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+17
-12
@@ -37,7 +37,7 @@
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/stop_watch.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class TableFactory;
|
||||
|
||||
@@ -66,8 +66,9 @@ TableBuilder* NewTableBuilder(
|
||||
}
|
||||
|
||||
Status BuildTable(
|
||||
const std::string& dbname, Env* env, const ImmutableCFOptions& ioptions,
|
||||
const MutableCFOptions& mutable_cf_options, const EnvOptions& env_options,
|
||||
const std::string& dbname, Env* env, FileSystem* fs,
|
||||
const ImmutableCFOptions& ioptions,
|
||||
const MutableCFOptions& mutable_cf_options, const FileOptions& file_options,
|
||||
TableCache* table_cache, InternalIterator* iter,
|
||||
std::vector<std::unique_ptr<FragmentedRangeTombstoneIterator>>
|
||||
range_del_iters,
|
||||
@@ -115,12 +116,12 @@ Status BuildTable(
|
||||
compression_opts_for_flush.max_dict_bytes = 0;
|
||||
compression_opts_for_flush.zstd_max_train_bytes = 0;
|
||||
{
|
||||
std::unique_ptr<WritableFile> file;
|
||||
std::unique_ptr<FSWritableFile> file;
|
||||
#ifndef NDEBUG
|
||||
bool use_direct_writes = env_options.use_direct_writes;
|
||||
bool use_direct_writes = file_options.use_direct_writes;
|
||||
TEST_SYNC_POINT_CALLBACK("BuildTable:create_file", &use_direct_writes);
|
||||
#endif // !NDEBUG
|
||||
s = NewWritableFile(env, fname, &file, env_options);
|
||||
s = NewWritableFile(fs, fname, &file, file_options);
|
||||
if (!s.ok()) {
|
||||
EventHelpers::LogAndNotifyTableFileCreationFinished(
|
||||
event_logger, ioptions.listeners, dbname, column_family_name, fname,
|
||||
@@ -130,9 +131,10 @@ Status BuildTable(
|
||||
file->SetIOPriority(io_priority);
|
||||
file->SetWriteLifeTimeHint(write_hint);
|
||||
|
||||
file_writer.reset(
|
||||
new WritableFileWriter(std::move(file), fname, env_options, env,
|
||||
ioptions.statistics, ioptions.listeners));
|
||||
file_writer.reset(new WritableFileWriter(
|
||||
std::move(file), fname, file_options, env, ioptions.statistics,
|
||||
ioptions.listeners, ioptions.sst_file_checksum_func));
|
||||
|
||||
builder = NewTableBuilder(
|
||||
ioptions, mutable_cf_options, internal_comparator,
|
||||
int_tbl_prop_collector_factories, column_family_id,
|
||||
@@ -198,6 +200,9 @@ Status BuildTable(
|
||||
if (table_properties) {
|
||||
*table_properties = tp;
|
||||
}
|
||||
// Add the checksum information to file metadata.
|
||||
meta->file_checksum = builder->GetFileChecksum();
|
||||
meta->file_checksum_func_name = builder->GetFileChecksumFuncName();
|
||||
}
|
||||
delete builder;
|
||||
|
||||
@@ -218,7 +223,7 @@ Status BuildTable(
|
||||
// we will regrad this verification as user reads since the goal is
|
||||
// to cache it here for further user reads
|
||||
std::unique_ptr<InternalIterator> it(table_cache->NewIterator(
|
||||
ReadOptions(), env_options, internal_comparator, *meta,
|
||||
ReadOptions(), file_options, internal_comparator, *meta,
|
||||
nullptr /* range_del_agg */,
|
||||
mutable_cf_options.prefix_extractor.get(), nullptr,
|
||||
(internal_stats == nullptr) ? nullptr
|
||||
@@ -241,7 +246,7 @@ Status BuildTable(
|
||||
}
|
||||
|
||||
if (!s.ok() || meta->fd.GetFileSize() == 0) {
|
||||
env->DeleteFile(fname);
|
||||
fs->DeleteFile(fname, IOOptions(), nullptr);
|
||||
}
|
||||
|
||||
if (meta->fd.GetFileSize() == 0) {
|
||||
@@ -255,4 +260,4 @@ Status BuildTable(
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+5
-4
@@ -22,7 +22,7 @@
|
||||
#include "rocksdb/types.h"
|
||||
#include "table/scoped_arena_iterator.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
struct Options;
|
||||
struct FileMetaData;
|
||||
@@ -62,8 +62,9 @@ TableBuilder* NewTableBuilder(
|
||||
// @param column_family_name Name of the column family that is also identified
|
||||
// by column_family_id, or empty string if unknown.
|
||||
extern Status BuildTable(
|
||||
const std::string& dbname, Env* env, const ImmutableCFOptions& options,
|
||||
const MutableCFOptions& mutable_cf_options, const EnvOptions& env_options,
|
||||
const std::string& dbname, Env* env, FileSystem* fs,
|
||||
const ImmutableCFOptions& options,
|
||||
const MutableCFOptions& mutable_cf_options, const FileOptions& file_options,
|
||||
TableCache* table_cache, InternalIterator* iter,
|
||||
std::vector<std::unique_ptr<FragmentedRangeTombstoneIterator>>
|
||||
range_del_iters,
|
||||
@@ -84,4 +85,4 @@ extern Status BuildTable(
|
||||
Env::WriteLifeTimeHint write_hint = Env::WLTH_NOT_SET,
|
||||
const uint64_t file_creation_time = 0);
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -46,74 +46,74 @@
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
|
||||
using rocksdb::BytewiseComparator;
|
||||
using rocksdb::Cache;
|
||||
using rocksdb::ColumnFamilyDescriptor;
|
||||
using rocksdb::ColumnFamilyHandle;
|
||||
using rocksdb::ColumnFamilyOptions;
|
||||
using rocksdb::CompactionFilter;
|
||||
using rocksdb::CompactionFilterFactory;
|
||||
using rocksdb::CompactionFilterContext;
|
||||
using rocksdb::CompactionOptionsFIFO;
|
||||
using rocksdb::Comparator;
|
||||
using rocksdb::CompressionType;
|
||||
using rocksdb::WALRecoveryMode;
|
||||
using rocksdb::DB;
|
||||
using rocksdb::DBOptions;
|
||||
using rocksdb::DbPath;
|
||||
using rocksdb::Env;
|
||||
using rocksdb::EnvOptions;
|
||||
using rocksdb::InfoLogLevel;
|
||||
using rocksdb::FileLock;
|
||||
using rocksdb::FilterPolicy;
|
||||
using rocksdb::FlushOptions;
|
||||
using rocksdb::IngestExternalFileOptions;
|
||||
using rocksdb::Iterator;
|
||||
using rocksdb::Logger;
|
||||
using rocksdb::MergeOperator;
|
||||
using rocksdb::MergeOperators;
|
||||
using rocksdb::NewBloomFilterPolicy;
|
||||
using rocksdb::NewLRUCache;
|
||||
using rocksdb::Options;
|
||||
using rocksdb::BlockBasedTableOptions;
|
||||
using rocksdb::CuckooTableOptions;
|
||||
using rocksdb::RandomAccessFile;
|
||||
using rocksdb::Range;
|
||||
using rocksdb::ReadOptions;
|
||||
using rocksdb::SequentialFile;
|
||||
using rocksdb::Slice;
|
||||
using rocksdb::SliceParts;
|
||||
using rocksdb::SliceTransform;
|
||||
using rocksdb::Snapshot;
|
||||
using rocksdb::SstFileWriter;
|
||||
using rocksdb::Status;
|
||||
using rocksdb::WritableFile;
|
||||
using rocksdb::WriteBatch;
|
||||
using rocksdb::WriteBatchWithIndex;
|
||||
using rocksdb::WriteOptions;
|
||||
using rocksdb::LiveFileMetaData;
|
||||
using rocksdb::BackupEngine;
|
||||
using rocksdb::BackupableDBOptions;
|
||||
using rocksdb::BackupInfo;
|
||||
using rocksdb::BackupID;
|
||||
using rocksdb::RestoreOptions;
|
||||
using rocksdb::CompactRangeOptions;
|
||||
using rocksdb::BottommostLevelCompaction;
|
||||
using rocksdb::RateLimiter;
|
||||
using rocksdb::NewGenericRateLimiter;
|
||||
using rocksdb::PinnableSlice;
|
||||
using rocksdb::TransactionDBOptions;
|
||||
using rocksdb::TransactionDB;
|
||||
using rocksdb::TransactionOptions;
|
||||
using rocksdb::OptimisticTransactionDB;
|
||||
using rocksdb::OptimisticTransactionOptions;
|
||||
using rocksdb::Transaction;
|
||||
using rocksdb::Checkpoint;
|
||||
using rocksdb::TransactionLogIterator;
|
||||
using rocksdb::BatchResult;
|
||||
using rocksdb::PerfLevel;
|
||||
using rocksdb::PerfContext;
|
||||
using rocksdb::MemoryUtil;
|
||||
using ROCKSDB_NAMESPACE::BackupableDBOptions;
|
||||
using ROCKSDB_NAMESPACE::BackupEngine;
|
||||
using ROCKSDB_NAMESPACE::BackupID;
|
||||
using ROCKSDB_NAMESPACE::BackupInfo;
|
||||
using ROCKSDB_NAMESPACE::BatchResult;
|
||||
using ROCKSDB_NAMESPACE::BlockBasedTableOptions;
|
||||
using ROCKSDB_NAMESPACE::BottommostLevelCompaction;
|
||||
using ROCKSDB_NAMESPACE::BytewiseComparator;
|
||||
using ROCKSDB_NAMESPACE::Cache;
|
||||
using ROCKSDB_NAMESPACE::Checkpoint;
|
||||
using ROCKSDB_NAMESPACE::ColumnFamilyDescriptor;
|
||||
using ROCKSDB_NAMESPACE::ColumnFamilyHandle;
|
||||
using ROCKSDB_NAMESPACE::ColumnFamilyOptions;
|
||||
using ROCKSDB_NAMESPACE::CompactionFilter;
|
||||
using ROCKSDB_NAMESPACE::CompactionFilterContext;
|
||||
using ROCKSDB_NAMESPACE::CompactionFilterFactory;
|
||||
using ROCKSDB_NAMESPACE::CompactionOptionsFIFO;
|
||||
using ROCKSDB_NAMESPACE::CompactRangeOptions;
|
||||
using ROCKSDB_NAMESPACE::Comparator;
|
||||
using ROCKSDB_NAMESPACE::CompressionType;
|
||||
using ROCKSDB_NAMESPACE::CuckooTableOptions;
|
||||
using ROCKSDB_NAMESPACE::DB;
|
||||
using ROCKSDB_NAMESPACE::DBOptions;
|
||||
using ROCKSDB_NAMESPACE::DbPath;
|
||||
using ROCKSDB_NAMESPACE::Env;
|
||||
using ROCKSDB_NAMESPACE::EnvOptions;
|
||||
using ROCKSDB_NAMESPACE::FileLock;
|
||||
using ROCKSDB_NAMESPACE::FilterPolicy;
|
||||
using ROCKSDB_NAMESPACE::FlushOptions;
|
||||
using ROCKSDB_NAMESPACE::InfoLogLevel;
|
||||
using ROCKSDB_NAMESPACE::IngestExternalFileOptions;
|
||||
using ROCKSDB_NAMESPACE::Iterator;
|
||||
using ROCKSDB_NAMESPACE::LiveFileMetaData;
|
||||
using ROCKSDB_NAMESPACE::Logger;
|
||||
using ROCKSDB_NAMESPACE::MemoryUtil;
|
||||
using ROCKSDB_NAMESPACE::MergeOperator;
|
||||
using ROCKSDB_NAMESPACE::MergeOperators;
|
||||
using ROCKSDB_NAMESPACE::NewBloomFilterPolicy;
|
||||
using ROCKSDB_NAMESPACE::NewGenericRateLimiter;
|
||||
using ROCKSDB_NAMESPACE::NewLRUCache;
|
||||
using ROCKSDB_NAMESPACE::OptimisticTransactionDB;
|
||||
using ROCKSDB_NAMESPACE::OptimisticTransactionOptions;
|
||||
using ROCKSDB_NAMESPACE::Options;
|
||||
using ROCKSDB_NAMESPACE::PerfContext;
|
||||
using ROCKSDB_NAMESPACE::PerfLevel;
|
||||
using ROCKSDB_NAMESPACE::PinnableSlice;
|
||||
using ROCKSDB_NAMESPACE::RandomAccessFile;
|
||||
using ROCKSDB_NAMESPACE::Range;
|
||||
using ROCKSDB_NAMESPACE::RateLimiter;
|
||||
using ROCKSDB_NAMESPACE::ReadOptions;
|
||||
using ROCKSDB_NAMESPACE::RestoreOptions;
|
||||
using ROCKSDB_NAMESPACE::SequentialFile;
|
||||
using ROCKSDB_NAMESPACE::Slice;
|
||||
using ROCKSDB_NAMESPACE::SliceParts;
|
||||
using ROCKSDB_NAMESPACE::SliceTransform;
|
||||
using ROCKSDB_NAMESPACE::Snapshot;
|
||||
using ROCKSDB_NAMESPACE::SstFileWriter;
|
||||
using ROCKSDB_NAMESPACE::Status;
|
||||
using ROCKSDB_NAMESPACE::Transaction;
|
||||
using ROCKSDB_NAMESPACE::TransactionDB;
|
||||
using ROCKSDB_NAMESPACE::TransactionDBOptions;
|
||||
using ROCKSDB_NAMESPACE::TransactionLogIterator;
|
||||
using ROCKSDB_NAMESPACE::TransactionOptions;
|
||||
using ROCKSDB_NAMESPACE::WALRecoveryMode;
|
||||
using ROCKSDB_NAMESPACE::WritableFile;
|
||||
using ROCKSDB_NAMESPACE::WriteBatch;
|
||||
using ROCKSDB_NAMESPACE::WriteBatchWithIndex;
|
||||
using ROCKSDB_NAMESPACE::WriteOptions;
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::vector;
|
||||
@@ -452,7 +452,7 @@ struct rocksdb_slicetransform_t : public SliceTransform {
|
||||
};
|
||||
|
||||
struct rocksdb_universal_compaction_options_t {
|
||||
rocksdb::CompactionOptionsUniversal *rep;
|
||||
ROCKSDB_NAMESPACE::CompactionOptionsUniversal* rep;
|
||||
};
|
||||
|
||||
static bool SaveError(char** errptr, const Status& s) {
|
||||
@@ -494,8 +494,9 @@ rocksdb_t* rocksdb_open_with_ttl(
|
||||
const char* name,
|
||||
int ttl,
|
||||
char** errptr) {
|
||||
rocksdb::DBWithTTL* db;
|
||||
if (SaveError(errptr, rocksdb::DBWithTTL::Open(options->rep, std::string(name), &db, ttl))) {
|
||||
ROCKSDB_NAMESPACE::DBWithTTL* db;
|
||||
if (SaveError(errptr, ROCKSDB_NAMESPACE::DBWithTTL::Open(
|
||||
options->rep, std::string(name), &db, ttl))) {
|
||||
return nullptr;
|
||||
}
|
||||
rocksdb_t* result = new rocksdb_t;
|
||||
@@ -664,17 +665,15 @@ void rocksdb_close(rocksdb_t* db) {
|
||||
}
|
||||
|
||||
void rocksdb_options_set_uint64add_merge_operator(rocksdb_options_t* opt) {
|
||||
opt->rep.merge_operator = rocksdb::MergeOperators::CreateUInt64AddOperator();
|
||||
opt->rep.merge_operator =
|
||||
ROCKSDB_NAMESPACE::MergeOperators::CreateUInt64AddOperator();
|
||||
}
|
||||
|
||||
rocksdb_t* rocksdb_open_column_families(
|
||||
const rocksdb_options_t* db_options,
|
||||
const char* name,
|
||||
int num_column_families,
|
||||
const char** column_family_names,
|
||||
const rocksdb_options_t** column_family_options,
|
||||
rocksdb_column_family_handle_t** column_family_handles,
|
||||
char** errptr) {
|
||||
const rocksdb_options_t* db_options, const char* name,
|
||||
int num_column_families, const char* const* column_family_names,
|
||||
const rocksdb_options_t* const* column_family_options,
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
@@ -700,14 +699,11 @@ rocksdb_t* rocksdb_open_column_families(
|
||||
}
|
||||
|
||||
rocksdb_t* rocksdb_open_for_read_only_column_families(
|
||||
const rocksdb_options_t* db_options,
|
||||
const char* name,
|
||||
int num_column_families,
|
||||
const char** column_family_names,
|
||||
const rocksdb_options_t** column_family_options,
|
||||
const rocksdb_options_t* db_options, const char* name,
|
||||
int num_column_families, const char* const* column_family_names,
|
||||
const rocksdb_options_t* const* column_family_options,
|
||||
rocksdb_column_family_handle_t** column_family_handles,
|
||||
unsigned char error_if_log_file_exist,
|
||||
char** errptr) {
|
||||
unsigned char error_if_log_file_exist, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
@@ -735,8 +731,8 @@ rocksdb_t* rocksdb_open_for_read_only_column_families(
|
||||
rocksdb_t* rocksdb_open_as_secondary_column_families(
|
||||
const rocksdb_options_t* db_options, const char* name,
|
||||
const char* secondary_path, int num_column_families,
|
||||
const char** column_family_names,
|
||||
const rocksdb_options_t** column_family_options,
|
||||
const char* const* column_family_names,
|
||||
const rocksdb_options_t* const* column_family_options,
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i != num_column_families; ++i) {
|
||||
@@ -852,6 +848,17 @@ void rocksdb_delete_cf(
|
||||
Slice(key, keylen)));
|
||||
}
|
||||
|
||||
void rocksdb_delete_range_cf(rocksdb_t* db,
|
||||
const rocksdb_writeoptions_t* options,
|
||||
rocksdb_column_family_handle_t* column_family,
|
||||
const char* start_key, size_t start_key_len,
|
||||
const char* end_key, size_t end_key_len,
|
||||
char** errptr) {
|
||||
SaveError(errptr, db->rep->DeleteRange(options->rep, column_family->rep,
|
||||
Slice(start_key, start_key_len),
|
||||
Slice(end_key, end_key_len)));
|
||||
}
|
||||
|
||||
void rocksdb_merge(
|
||||
rocksdb_t* db,
|
||||
const rocksdb_writeoptions_t* options,
|
||||
@@ -2032,6 +2039,17 @@ void rocksdb_block_based_options_set_index_type(
|
||||
options->rep.index_type = static_cast<BlockBasedTableOptions::IndexType>(v);
|
||||
}
|
||||
|
||||
void rocksdb_block_based_options_set_data_block_index_type(
|
||||
rocksdb_block_based_table_options_t* options, int v) {
|
||||
options->rep.data_block_index_type =
|
||||
static_cast<BlockBasedTableOptions::DataBlockIndexType>(v);
|
||||
}
|
||||
|
||||
void rocksdb_block_based_options_set_data_block_hash_ratio(
|
||||
rocksdb_block_based_table_options_t* options, double v) {
|
||||
options->rep.data_block_hash_table_util_ratio = v;
|
||||
}
|
||||
|
||||
void rocksdb_block_based_options_set_hash_index_allow_collision(
|
||||
rocksdb_block_based_table_options_t* options, unsigned char v) {
|
||||
options->rep.hash_index_allow_collision = v;
|
||||
@@ -2062,7 +2080,7 @@ void rocksdb_options_set_block_based_table_factory(
|
||||
rocksdb_block_based_table_options_t* table_options) {
|
||||
if (table_options) {
|
||||
opt->rep.table_factory.reset(
|
||||
rocksdb::NewBlockBasedTableFactory(table_options->rep));
|
||||
ROCKSDB_NAMESPACE::NewBlockBasedTableFactory(table_options->rep));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2106,7 +2124,7 @@ void rocksdb_options_set_cuckoo_table_factory(
|
||||
rocksdb_cuckoo_table_options_t* table_options) {
|
||||
if (table_options) {
|
||||
opt->rep.table_factory.reset(
|
||||
rocksdb::NewCuckooTableFactory(table_options->rep));
|
||||
ROCKSDB_NAMESPACE::NewCuckooTableFactory(table_options->rep));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2296,7 +2314,7 @@ void rocksdb_options_set_max_bytes_for_level_multiplier_additional(
|
||||
}
|
||||
|
||||
void rocksdb_options_enable_statistics(rocksdb_options_t* opt) {
|
||||
opt->rep.statistics = rocksdb::CreateDBStatistics();
|
||||
opt->rep.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
}
|
||||
|
||||
void rocksdb_options_set_skip_stats_update_on_db_open(rocksdb_options_t* opt,
|
||||
@@ -2304,6 +2322,11 @@ void rocksdb_options_set_skip_stats_update_on_db_open(rocksdb_options_t* opt,
|
||||
opt->rep.skip_stats_update_on_db_open = val;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_skip_checking_sst_file_sizes_on_db_open(
|
||||
rocksdb_options_t* opt, unsigned char val) {
|
||||
opt->rep.skip_checking_sst_file_sizes_on_db_open = val;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_num_levels(rocksdb_options_t* opt, int n) {
|
||||
opt->rep.num_levels = n;
|
||||
}
|
||||
@@ -2447,16 +2470,20 @@ void rocksdb_options_set_access_hint_on_compaction_start(
|
||||
rocksdb_options_t* opt, int v) {
|
||||
switch(v) {
|
||||
case 0:
|
||||
opt->rep.access_hint_on_compaction_start = rocksdb::Options::NONE;
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::NONE;
|
||||
break;
|
||||
case 1:
|
||||
opt->rep.access_hint_on_compaction_start = rocksdb::Options::NORMAL;
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::NORMAL;
|
||||
break;
|
||||
case 2:
|
||||
opt->rep.access_hint_on_compaction_start = rocksdb::Options::SEQUENTIAL;
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::SEQUENTIAL;
|
||||
break;
|
||||
case 3:
|
||||
opt->rep.access_hint_on_compaction_start = rocksdb::Options::WILLNEED;
|
||||
opt->rep.access_hint_on_compaction_start =
|
||||
ROCKSDB_NAMESPACE::Options::WILLNEED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2622,7 +2649,7 @@ void rocksdb_options_prepare_for_bulk_load(rocksdb_options_t* opt) {
|
||||
}
|
||||
|
||||
void rocksdb_options_set_memtable_vector_rep(rocksdb_options_t *opt) {
|
||||
opt->rep.memtable_factory.reset(new rocksdb::VectorRepFactory);
|
||||
opt->rep.memtable_factory.reset(new ROCKSDB_NAMESPACE::VectorRepFactory);
|
||||
}
|
||||
|
||||
void rocksdb_options_set_memtable_prefix_bloom_size_ratio(
|
||||
@@ -2638,26 +2665,29 @@ void rocksdb_options_set_memtable_huge_page_size(rocksdb_options_t* opt,
|
||||
void rocksdb_options_set_hash_skip_list_rep(
|
||||
rocksdb_options_t *opt, size_t bucket_count,
|
||||
int32_t skiplist_height, int32_t skiplist_branching_factor) {
|
||||
rocksdb::MemTableRepFactory* factory = rocksdb::NewHashSkipListRepFactory(
|
||||
bucket_count, skiplist_height, skiplist_branching_factor);
|
||||
ROCKSDB_NAMESPACE::MemTableRepFactory* factory =
|
||||
ROCKSDB_NAMESPACE::NewHashSkipListRepFactory(
|
||||
bucket_count, skiplist_height, skiplist_branching_factor);
|
||||
opt->rep.memtable_factory.reset(factory);
|
||||
}
|
||||
|
||||
void rocksdb_options_set_hash_link_list_rep(
|
||||
rocksdb_options_t *opt, size_t bucket_count) {
|
||||
opt->rep.memtable_factory.reset(rocksdb::NewHashLinkListRepFactory(bucket_count));
|
||||
opt->rep.memtable_factory.reset(
|
||||
ROCKSDB_NAMESPACE::NewHashLinkListRepFactory(bucket_count));
|
||||
}
|
||||
|
||||
void rocksdb_options_set_plain_table_factory(
|
||||
rocksdb_options_t *opt, uint32_t user_key_len, int bloom_bits_per_key,
|
||||
double hash_table_ratio, size_t index_sparseness) {
|
||||
rocksdb::PlainTableOptions options;
|
||||
ROCKSDB_NAMESPACE::PlainTableOptions options;
|
||||
options.user_key_len = user_key_len;
|
||||
options.bloom_bits_per_key = bloom_bits_per_key;
|
||||
options.hash_table_ratio = hash_table_ratio;
|
||||
options.index_sparseness = index_sparseness;
|
||||
|
||||
rocksdb::TableFactory* factory = rocksdb::NewPlainTableFactory(options);
|
||||
ROCKSDB_NAMESPACE::TableFactory* factory =
|
||||
ROCKSDB_NAMESPACE::NewPlainTableFactory(options);
|
||||
opt->rep.table_factory.reset(factory);
|
||||
}
|
||||
|
||||
@@ -2687,7 +2717,8 @@ void rocksdb_options_set_report_bg_io_stats(
|
||||
}
|
||||
|
||||
void rocksdb_options_set_compaction_style(rocksdb_options_t *opt, int style) {
|
||||
opt->rep.compaction_style = static_cast<rocksdb::CompactionStyle>(style);
|
||||
opt->rep.compaction_style =
|
||||
static_cast<ROCKSDB_NAMESPACE::CompactionStyle>(style);
|
||||
}
|
||||
|
||||
void rocksdb_options_set_universal_compaction_options(rocksdb_options_t *opt, rocksdb_universal_compaction_options_t *uco) {
|
||||
@@ -2701,7 +2732,7 @@ void rocksdb_options_set_fifo_compaction_options(
|
||||
}
|
||||
|
||||
char *rocksdb_options_statistics_get_string(rocksdb_options_t *opt) {
|
||||
rocksdb::Statistics *statistics = opt->rep.statistics.get();
|
||||
ROCKSDB_NAMESPACE::Statistics* statistics = opt->rep.statistics.get();
|
||||
if (statistics) {
|
||||
return strdup(statistics->ToString().c_str());
|
||||
}
|
||||
@@ -2714,6 +2745,11 @@ void rocksdb_options_set_ratelimiter(rocksdb_options_t *opt, rocksdb_ratelimiter
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_options_set_atomic_flush(rocksdb_options_t* opt,
|
||||
unsigned char atomic_flush) {
|
||||
opt->rep.atomic_flush = atomic_flush;
|
||||
}
|
||||
|
||||
rocksdb_ratelimiter_t* rocksdb_ratelimiter_create(
|
||||
int64_t rate_bytes_per_sec,
|
||||
int64_t refill_period_us,
|
||||
@@ -2729,6 +2765,12 @@ void rocksdb_ratelimiter_destroy(rocksdb_ratelimiter_t *limiter) {
|
||||
delete limiter;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_row_cache(rocksdb_options_t* opt, rocksdb_cache_t* cache) {
|
||||
if(cache) {
|
||||
opt->rep.row_cache = cache->rep;
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_set_perf_level(int v) {
|
||||
PerfLevel level = static_cast<PerfLevel>(v);
|
||||
SetPerfLevel(level);
|
||||
@@ -2736,7 +2778,7 @@ void rocksdb_set_perf_level(int v) {
|
||||
|
||||
rocksdb_perfcontext_t* rocksdb_perfcontext_create() {
|
||||
rocksdb_perfcontext_t* context = new rocksdb_perfcontext_t;
|
||||
context->rep = rocksdb::get_perf_context();
|
||||
context->rep = ROCKSDB_NAMESPACE::get_perf_context();
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -3037,7 +3079,17 @@ rocksdb_filterpolicy_t* rocksdb_filterpolicy_create_bloom_format(int bits_per_ke
|
||||
bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
|
||||
return rep_->KeyMayMatch(key, filter);
|
||||
}
|
||||
static void DoNothing(void*) { }
|
||||
// No need to override GetFilterBitsBuilder if this one is overridden
|
||||
ROCKSDB_NAMESPACE::FilterBitsBuilder* GetBuilderWithContext(
|
||||
const ROCKSDB_NAMESPACE::FilterBuildingContext& context)
|
||||
const override {
|
||||
return rep_->GetBuilderWithContext(context);
|
||||
}
|
||||
ROCKSDB_NAMESPACE::FilterBitsReader* GetFilterBitsReader(
|
||||
const Slice& contents) const override {
|
||||
return rep_->GetFilterBitsReader(contents);
|
||||
}
|
||||
static void DoNothing(void*) {}
|
||||
};
|
||||
Wrapper* wrapper = new Wrapper;
|
||||
wrapper->rep_ = NewBloomFilterPolicy(bits_per_key, original_format);
|
||||
@@ -3135,7 +3187,7 @@ void rocksdb_readoptions_set_iterate_lower_bound(
|
||||
|
||||
void rocksdb_readoptions_set_read_tier(
|
||||
rocksdb_readoptions_t* opt, int v) {
|
||||
opt->rep.read_tier = static_cast<rocksdb::ReadTier>(v);
|
||||
opt->rep.read_tier = static_cast<ROCKSDB_NAMESPACE::ReadTier>(v);
|
||||
}
|
||||
|
||||
void rocksdb_readoptions_set_tailing(
|
||||
@@ -3307,7 +3359,7 @@ rocksdb_env_t* rocksdb_create_default_env() {
|
||||
|
||||
rocksdb_env_t* rocksdb_create_mem_env() {
|
||||
rocksdb_env_t* result = new rocksdb_env_t;
|
||||
result->rep = rocksdb::NewMemEnv(Env::Default());
|
||||
result->rep = ROCKSDB_NAMESPACE::NewMemEnv(Env::Default());
|
||||
result->is_default = false;
|
||||
return result;
|
||||
}
|
||||
@@ -3522,7 +3574,7 @@ struct Wrapper : public rocksdb_slicetransform_t {
|
||||
|
||||
rocksdb_slicetransform_t* rocksdb_slicetransform_create_fixed_prefix(size_t prefixLen) {
|
||||
Wrapper* wrapper = new Wrapper;
|
||||
wrapper->rep_ = rocksdb::NewFixedPrefixTransform(prefixLen);
|
||||
wrapper->rep_ = ROCKSDB_NAMESPACE::NewFixedPrefixTransform(prefixLen);
|
||||
wrapper->state_ = nullptr;
|
||||
wrapper->destructor_ = &Wrapper::DoNothing;
|
||||
return wrapper;
|
||||
@@ -3530,7 +3582,7 @@ rocksdb_slicetransform_t* rocksdb_slicetransform_create_fixed_prefix(size_t pref
|
||||
|
||||
rocksdb_slicetransform_t* rocksdb_slicetransform_create_noop() {
|
||||
Wrapper* wrapper = new Wrapper;
|
||||
wrapper->rep_ = rocksdb::NewNoopTransform();
|
||||
wrapper->rep_ = ROCKSDB_NAMESPACE::NewNoopTransform();
|
||||
wrapper->state_ = nullptr;
|
||||
wrapper->destructor_ = &Wrapper::DoNothing;
|
||||
return wrapper;
|
||||
@@ -3538,7 +3590,7 @@ rocksdb_slicetransform_t* rocksdb_slicetransform_create_noop() {
|
||||
|
||||
rocksdb_universal_compaction_options_t* rocksdb_universal_compaction_options_create() {
|
||||
rocksdb_universal_compaction_options_t* result = new rocksdb_universal_compaction_options_t;
|
||||
result->rep = new rocksdb::CompactionOptionsUniversal;
|
||||
result->rep = new ROCKSDB_NAMESPACE::CompactionOptionsUniversal;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3569,7 +3621,8 @@ void rocksdb_universal_compaction_options_set_compression_size_percent(
|
||||
|
||||
void rocksdb_universal_compaction_options_set_stop_style(
|
||||
rocksdb_universal_compaction_options_t* uco, int style) {
|
||||
uco->rep->stop_style = static_cast<rocksdb::CompactionStopStyle>(style);
|
||||
uco->rep->stop_style =
|
||||
static_cast<ROCKSDB_NAMESPACE::CompactionStopStyle>(style);
|
||||
}
|
||||
|
||||
void rocksdb_universal_compaction_options_destroy(
|
||||
@@ -3599,7 +3652,7 @@ void rocksdb_options_set_min_level_to_compress(rocksdb_options_t* opt, int level
|
||||
assert(level <= opt->rep.num_levels);
|
||||
opt->rep.compression_per_level.resize(opt->rep.num_levels);
|
||||
for (int i = 0; i < level; i++) {
|
||||
opt->rep.compression_per_level[i] = rocksdb::kNoCompression;
|
||||
opt->rep.compression_per_level[i] = ROCKSDB_NAMESPACE::kNoCompression;
|
||||
}
|
||||
for (int i = level; i < opt->rep.num_levels; i++) {
|
||||
opt->rep.compression_per_level[i] = opt->rep.compression;
|
||||
@@ -3806,8 +3859,8 @@ rocksdb_transactiondb_t* rocksdb_transactiondb_open(
|
||||
rocksdb_transactiondb_t* rocksdb_transactiondb_open_column_families(
|
||||
const rocksdb_options_t* options,
|
||||
const rocksdb_transactiondb_options_t* txn_db_options, const char* name,
|
||||
int num_column_families, const char** column_family_names,
|
||||
const rocksdb_options_t** column_family_options,
|
||||
int num_column_families, const char* const* column_family_names,
|
||||
const rocksdb_options_t* const* column_family_options,
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
@@ -4184,8 +4237,8 @@ rocksdb_optimistictransactiondb_t* rocksdb_optimistictransactiondb_open(
|
||||
rocksdb_optimistictransactiondb_t*
|
||||
rocksdb_optimistictransactiondb_open_column_families(
|
||||
const rocksdb_options_t* db_options, const char* name,
|
||||
int num_column_families, const char** column_family_names,
|
||||
const rocksdb_options_t** column_family_options,
|
||||
int num_column_families, const char* const* column_family_names,
|
||||
const rocksdb_options_t* const* column_family_options,
|
||||
rocksdb_column_family_handle_t** column_family_handles, char** errptr) {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
for (int i = 0; i < num_column_families; i++) {
|
||||
@@ -4301,7 +4354,8 @@ const char* rocksdb_pinnableslice_value(const rocksdb_pinnableslice_t* v,
|
||||
return v->rep.data();
|
||||
}
|
||||
|
||||
// container to keep databases and caches in order to use rocksdb::MemoryUtil
|
||||
// container to keep databases and caches in order to use
|
||||
// ROCKSDB_NAMESPACE::MemoryUtil
|
||||
struct rocksdb_memory_consumers_t {
|
||||
std::vector<rocksdb_t*> dbs;
|
||||
std::unordered_set<rocksdb_cache_t*> caches;
|
||||
@@ -4329,7 +4383,7 @@ void rocksdb_memory_consumers_destroy(rocksdb_memory_consumers_t* consumers) {
|
||||
delete consumers;
|
||||
}
|
||||
|
||||
// contains memory usage statistics provided by rocksdb::MemoryUtil
|
||||
// contains memory usage statistics provided by ROCKSDB_NAMESPACE::MemoryUtil
|
||||
struct rocksdb_memory_usage_t {
|
||||
uint64_t mem_table_total;
|
||||
uint64_t mem_table_unflushed;
|
||||
@@ -4351,7 +4405,7 @@ rocksdb_memory_usage_t* rocksdb_approximate_memory_usage_create(
|
||||
cache_set.insert(const_cast<const Cache*>(cache->rep.get()));
|
||||
}
|
||||
|
||||
std::map<rocksdb::MemoryUtil::UsageType, uint64_t> usage_by_type;
|
||||
std::map<ROCKSDB_NAMESPACE::MemoryUtil::UsageType, uint64_t> usage_by_type;
|
||||
|
||||
auto status = MemoryUtil::GetApproximateMemoryUsageByType(dbs, cache_set,
|
||||
&usage_by_type);
|
||||
|
||||
+78
-26
@@ -487,8 +487,11 @@ int main(int argc, char** argv) {
|
||||
rocksdb_options_set_paranoid_checks(options, 1);
|
||||
rocksdb_options_set_max_open_files(options, 10);
|
||||
rocksdb_options_set_base_background_compactions(options, 1);
|
||||
|
||||
table_options = rocksdb_block_based_options_create();
|
||||
rocksdb_block_based_options_set_block_cache(table_options, cache);
|
||||
rocksdb_block_based_options_set_data_block_index_type(table_options, 1);
|
||||
rocksdb_block_based_options_set_data_block_hash_ratio(table_options, 0.75);
|
||||
rocksdb_options_set_block_based_table_factory(options, table_options);
|
||||
|
||||
rocksdb_options_set_compression(options, rocksdb_no_compression);
|
||||
@@ -832,23 +835,6 @@ int main(int argc, char** argv) {
|
||||
rocksdb_writebatch_wi_iterate(wbi, &pos, CheckPut, CheckDel);
|
||||
CheckCondition(pos == 3);
|
||||
rocksdb_writebatch_wi_clear(wbi);
|
||||
rocksdb_writebatch_wi_put(wbi, "bar", 3, "b", 1);
|
||||
rocksdb_writebatch_wi_put(wbi, "bay", 3, "d", 1);
|
||||
rocksdb_writebatch_wi_delete_range(wbi, "bar", 3, "bay", 3);
|
||||
rocksdb_write_writebatch_wi(db, woptions, wbi, &err);
|
||||
CheckNoError(err);
|
||||
CheckGet(db, roptions, "bar", NULL);
|
||||
CheckGet(db, roptions, "bay", "d");
|
||||
rocksdb_writebatch_wi_clear(wbi);
|
||||
const char* start_list[1] = {"bay"};
|
||||
const size_t start_sizes[1] = {3};
|
||||
const char* end_list[1] = {"baz"};
|
||||
const size_t end_sizes[1] = {3};
|
||||
rocksdb_writebatch_wi_delete_rangev(wbi, 1, start_list, start_sizes, end_list,
|
||||
end_sizes);
|
||||
rocksdb_write_writebatch_wi(db, woptions, wbi, &err);
|
||||
CheckNoError(err);
|
||||
CheckGet(db, roptions, "bay", NULL);
|
||||
rocksdb_writebatch_wi_destroy(wbi);
|
||||
}
|
||||
|
||||
@@ -1048,17 +1034,20 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
StartPhase("filter");
|
||||
for (run = 0; run < 2; run++) {
|
||||
// First run uses custom filter, second run uses bloom filter
|
||||
for (run = 0; run <= 2; run++) {
|
||||
// First run uses custom filter
|
||||
// Second run uses old block-based bloom filter
|
||||
// Third run uses full bloom filter
|
||||
CheckNoError(err);
|
||||
rocksdb_filterpolicy_t* policy;
|
||||
if (run == 0) {
|
||||
policy = rocksdb_filterpolicy_create(
|
||||
NULL, FilterDestroy, FilterCreate, FilterKeyMatch, NULL, FilterName);
|
||||
policy = rocksdb_filterpolicy_create(NULL, FilterDestroy, FilterCreate,
|
||||
FilterKeyMatch, NULL, FilterName);
|
||||
} else if (run == 1) {
|
||||
policy = rocksdb_filterpolicy_create_bloom(8);
|
||||
} else {
|
||||
policy = rocksdb_filterpolicy_create_bloom(10);
|
||||
policy = rocksdb_filterpolicy_create_bloom_full(8);
|
||||
}
|
||||
|
||||
rocksdb_block_based_options_set_filter_policy(table_options, policy);
|
||||
|
||||
// Create new database
|
||||
@@ -1071,12 +1060,24 @@ int main(int argc, char** argv) {
|
||||
CheckNoError(err);
|
||||
rocksdb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
{
|
||||
// Add enough keys to get just one reasonably populated Bloom filter
|
||||
const int keys_to_add = 1500;
|
||||
int i;
|
||||
char keybuf[100];
|
||||
for (i = 0; i < keys_to_add; i++) {
|
||||
snprintf(keybuf, sizeof(keybuf), "yes%020d", i);
|
||||
rocksdb_put(db, woptions, keybuf, strlen(keybuf), "val", 3, &err);
|
||||
CheckNoError(err);
|
||||
}
|
||||
}
|
||||
rocksdb_compact_range(db, NULL, 0, NULL, 0);
|
||||
|
||||
fake_filter_result = 1;
|
||||
CheckGet(db, roptions, "foo", "foovalue");
|
||||
CheckGet(db, roptions, "bar", "barvalue");
|
||||
if (phase == 0) {
|
||||
if (run == 0) {
|
||||
// Must not find value when custom filter returns false
|
||||
fake_filter_result = 0;
|
||||
CheckGet(db, roptions, "foo", NULL);
|
||||
@@ -1086,6 +1087,43 @@ int main(int argc, char** argv) {
|
||||
CheckGet(db, roptions, "foo", "foovalue");
|
||||
CheckGet(db, roptions, "bar", "barvalue");
|
||||
}
|
||||
|
||||
{
|
||||
// Query some keys not added to identify Bloom filter implementation
|
||||
// from false positive queries, using perfcontext to detect Bloom
|
||||
// filter behavior
|
||||
rocksdb_perfcontext_t* perf = rocksdb_perfcontext_create();
|
||||
rocksdb_perfcontext_reset(perf);
|
||||
|
||||
const int keys_to_query = 10000;
|
||||
int i;
|
||||
char keybuf[100];
|
||||
for (i = 0; i < keys_to_query; i++) {
|
||||
fake_filter_result = i % 2;
|
||||
snprintf(keybuf, sizeof(keybuf), "no%020d", i);
|
||||
CheckGet(db, roptions, keybuf, NULL);
|
||||
}
|
||||
|
||||
const int hits =
|
||||
(int)rocksdb_perfcontext_metric(perf, rocksdb_bloom_sst_hit_count);
|
||||
if (run == 0) {
|
||||
// Due to half true, half false with fake filter result
|
||||
CheckCondition(hits == keys_to_query / 2);
|
||||
} else if (run == 1) {
|
||||
// Essentially a fingerprint of the block-based Bloom schema
|
||||
CheckCondition(hits == 241);
|
||||
} else {
|
||||
// Essentially a fingerprint of the full Bloom schema(s),
|
||||
// format_version < 5, which vary for three different CACHE_LINE_SIZEs
|
||||
CheckCondition(hits == 224 || hits == 180 || hits == 125);
|
||||
}
|
||||
CheckCondition(
|
||||
(keys_to_query - hits) ==
|
||||
(int)rocksdb_perfcontext_metric(perf, rocksdb_bloom_sst_miss_count));
|
||||
|
||||
rocksdb_perfcontext_destroy(perf);
|
||||
}
|
||||
|
||||
// Reset the policy
|
||||
rocksdb_block_based_options_set_filter_policy(table_options, NULL);
|
||||
rocksdb_options_set_block_based_table_factory(options, table_options);
|
||||
@@ -1189,6 +1227,15 @@ int main(int argc, char** argv) {
|
||||
rocksdb_put_cf(db, woptions, handles[1], "foo", 3, "hello", 5, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_put_cf(db, woptions, handles[1], "foobar1", 7, "hello1", 6, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put_cf(db, woptions, handles[1], "foobar2", 7, "hello2", 6, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put_cf(db, woptions, handles[1], "foobar3", 7, "hello3", 6, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_put_cf(db, woptions, handles[1], "foobar4", 7, "hello4", 6, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_flushoptions_t *flush_options = rocksdb_flushoptions_create();
|
||||
rocksdb_flushoptions_set_wait(flush_options, 1);
|
||||
rocksdb_flush_cf(db, flush_options, handles[1], &err);
|
||||
@@ -1201,6 +1248,10 @@ int main(int argc, char** argv) {
|
||||
rocksdb_delete_cf(db, woptions, handles[1], "foo", 3, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
rocksdb_delete_range_cf(db, woptions, handles[1], "foobar2", 7, "foobar4",
|
||||
7, &err);
|
||||
CheckNoError(err);
|
||||
|
||||
CheckGetCF(db, roptions, handles[1], "foo", NULL);
|
||||
CheckPinGetCF(db, roptions, handles[1], "foo", NULL);
|
||||
|
||||
@@ -1253,7 +1304,7 @@ int main(int argc, char** argv) {
|
||||
for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
|
||||
i++;
|
||||
}
|
||||
CheckCondition(i == 1);
|
||||
CheckCondition(i == 3);
|
||||
rocksdb_iter_get_error(iter, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_iter_destroy(iter);
|
||||
@@ -1277,7 +1328,7 @@ int main(int argc, char** argv) {
|
||||
for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
|
||||
i++;
|
||||
}
|
||||
CheckCondition(i == 1);
|
||||
CheckCondition(i == 3);
|
||||
rocksdb_iter_get_error(iter, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_iter_destroy(iter);
|
||||
@@ -1467,6 +1518,7 @@ int main(int argc, char** argv) {
|
||||
CheckCondition(!rocksdb_iter_valid(iter));
|
||||
|
||||
rocksdb_iter_destroy(iter);
|
||||
rocksdb_readoptions_set_iterate_upper_bound(roptions, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+202
-69
@@ -30,12 +30,13 @@
|
||||
#include "memtable/hash_skiplist_rep.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "table/block_based/block_based_table_factory.h"
|
||||
#include "table/merging_iterator.h"
|
||||
#include "util/autovector.h"
|
||||
#include "util/compression.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
ColumnFamilyHandleImpl::ColumnFamilyHandleImpl(
|
||||
ColumnFamilyData* column_family_data, DBImpl* db, InstrumentedMutex* mutex)
|
||||
@@ -59,11 +60,8 @@ ColumnFamilyHandleImpl::~ColumnFamilyHandleImpl() {
|
||||
ColumnFamilyOptions initial_cf_options_copy = cfd_->initial_cf_options();
|
||||
JobContext job_context(0);
|
||||
mutex_->Lock();
|
||||
if (cfd_->Unref()) {
|
||||
bool dropped = cfd_->IsDropped();
|
||||
|
||||
delete cfd_;
|
||||
|
||||
bool dropped = cfd_->IsDropped();
|
||||
if (cfd_->UnrefAndTryDelete()) {
|
||||
if (dropped) {
|
||||
db_->FindObsoleteFiles(&job_context, false, true);
|
||||
}
|
||||
@@ -187,6 +185,11 @@ Status CheckCFPathsSupported(const DBOptions& db_options,
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
namespace {
|
||||
const uint64_t kDefaultTtl = 0xfffffffffffffffe;
|
||||
const uint64_t kDefaultPeriodicCompSecs = 0xfffffffffffffffe;
|
||||
}; // namespace
|
||||
|
||||
ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
const ColumnFamilyOptions& src) {
|
||||
ColumnFamilyOptions result = src;
|
||||
@@ -342,6 +345,61 @@ ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
result.max_compaction_bytes = result.target_file_size_base * 25;
|
||||
}
|
||||
|
||||
bool is_block_based_table =
|
||||
(result.table_factory->Name() == BlockBasedTableFactory().Name());
|
||||
|
||||
const uint64_t kAdjustedTtl = 30 * 24 * 60 * 60;
|
||||
if (result.ttl == kDefaultTtl) {
|
||||
if (is_block_based_table &&
|
||||
result.compaction_style != kCompactionStyleFIFO) {
|
||||
result.ttl = kAdjustedTtl;
|
||||
} else {
|
||||
result.ttl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t kAdjustedPeriodicCompSecs = 30 * 24 * 60 * 60;
|
||||
|
||||
// Turn on periodic compactions and set them to occur once every 30 days if
|
||||
// compaction filters are used and periodic_compaction_seconds is set to the
|
||||
// default value.
|
||||
if (result.compaction_style != kCompactionStyleFIFO) {
|
||||
if ((result.compaction_filter != nullptr ||
|
||||
result.compaction_filter_factory != nullptr) &&
|
||||
result.periodic_compaction_seconds == kDefaultPeriodicCompSecs &&
|
||||
is_block_based_table) {
|
||||
result.periodic_compaction_seconds = kAdjustedPeriodicCompSecs;
|
||||
}
|
||||
} else {
|
||||
// result.compaction_style == kCompactionStyleFIFO
|
||||
if (result.ttl == 0) {
|
||||
if (is_block_based_table) {
|
||||
if (result.periodic_compaction_seconds == kDefaultPeriodicCompSecs) {
|
||||
result.periodic_compaction_seconds = kAdjustedPeriodicCompSecs;
|
||||
}
|
||||
result.ttl = result.periodic_compaction_seconds;
|
||||
}
|
||||
} else if (result.periodic_compaction_seconds != 0) {
|
||||
result.ttl = std::min(result.ttl, result.periodic_compaction_seconds);
|
||||
}
|
||||
}
|
||||
|
||||
// TTL compactions would work similar to Periodic Compactions in Universal in
|
||||
// most of the cases. So, if ttl is set, execute the periodic compaction
|
||||
// codepath.
|
||||
if (result.compaction_style == kCompactionStyleUniversal && result.ttl != 0) {
|
||||
if (result.periodic_compaction_seconds != 0) {
|
||||
result.periodic_compaction_seconds =
|
||||
std::min(result.ttl, result.periodic_compaction_seconds);
|
||||
} else {
|
||||
result.periodic_compaction_seconds = result.ttl;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.periodic_compaction_seconds == kDefaultPeriodicCompSecs) {
|
||||
result.periodic_compaction_seconds = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -378,13 +436,18 @@ void SuperVersion::Cleanup() {
|
||||
to_delete.push_back(m);
|
||||
}
|
||||
current->Unref();
|
||||
if (cfd->Unref()) {
|
||||
delete cfd;
|
||||
}
|
||||
}
|
||||
|
||||
void SuperVersion::Init(MemTable* new_mem, MemTableListVersion* new_imm,
|
||||
Version* new_current) {
|
||||
void SuperVersion::Init(ColumnFamilyData* new_cfd, MemTable* new_mem,
|
||||
MemTableListVersion* new_imm, Version* new_current) {
|
||||
cfd = new_cfd;
|
||||
mem = new_mem;
|
||||
imm = new_imm;
|
||||
current = new_current;
|
||||
cfd->Ref();
|
||||
mem->Ref();
|
||||
imm->Ref();
|
||||
current->Ref();
|
||||
@@ -408,11 +471,22 @@ void SuperVersionUnrefHandle(void* ptr) {
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
std::vector<std::string> ColumnFamilyData::GetDbPaths() const {
|
||||
std::vector<std::string> paths;
|
||||
paths.reserve(ioptions_.cf_paths.size());
|
||||
for (const DbPath& db_path : ioptions_.cf_paths) {
|
||||
paths.emplace_back(db_path.path);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
const uint32_t ColumnFamilyData::kDummyColumnFamilyDataId = port::kMaxUint32;
|
||||
|
||||
ColumnFamilyData::ColumnFamilyData(
|
||||
uint32_t id, const std::string& name, Version* _dummy_versions,
|
||||
Cache* _table_cache, WriteBufferManager* write_buffer_manager,
|
||||
const ColumnFamilyOptions& cf_options, const ImmutableDBOptions& db_options,
|
||||
const EnvOptions& env_options, ColumnFamilySet* column_family_set,
|
||||
const FileOptions& file_options, ColumnFamilySet* column_family_set,
|
||||
BlockCacheTracer* const block_cache_tracer)
|
||||
: id_(id),
|
||||
name_(name),
|
||||
@@ -444,7 +518,23 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
queued_for_compaction_(false),
|
||||
prev_compaction_needed_bytes_(0),
|
||||
allow_2pc_(db_options.allow_2pc),
|
||||
last_memtable_id_(0) {
|
||||
last_memtable_id_(0),
|
||||
db_paths_registered_(false) {
|
||||
if (id_ != kDummyColumnFamilyDataId) {
|
||||
// TODO(cc): RegisterDbPaths can be expensive, considering moving it
|
||||
// outside of this constructor which might be called with db mutex held.
|
||||
// TODO(cc): considering using ioptions_.fs, currently some tests rely on
|
||||
// EnvWrapper, that's the main reason why we use env here.
|
||||
Status s = ioptions_.env->RegisterDbPaths(GetDbPaths());
|
||||
if (s.ok()) {
|
||||
db_paths_registered_ = true;
|
||||
} else {
|
||||
ROCKS_LOG_ERROR(
|
||||
ioptions_.info_log,
|
||||
"Failed to register data paths of column family (id: %d, name: %s)",
|
||||
id_, name_.c_str());
|
||||
}
|
||||
}
|
||||
Ref();
|
||||
|
||||
// Convert user defined table properties collector factories to internal ones.
|
||||
@@ -454,7 +544,7 @@ ColumnFamilyData::ColumnFamilyData(
|
||||
if (_dummy_versions != nullptr) {
|
||||
internal_stats_.reset(
|
||||
new InternalStats(ioptions_.num_levels, db_options.env, this));
|
||||
table_cache_.reset(new TableCache(ioptions_, env_options, _table_cache,
|
||||
table_cache_.reset(new TableCache(ioptions_, file_options, _table_cache,
|
||||
block_cache_tracer));
|
||||
if (ioptions_.compaction_style == kCompactionStyleLevel) {
|
||||
compaction_picker_.reset(
|
||||
@@ -520,21 +610,7 @@ ColumnFamilyData::~ColumnFamilyData() {
|
||||
// compaction_queue_ and we destroyed it
|
||||
assert(!queued_for_flush_);
|
||||
assert(!queued_for_compaction_);
|
||||
|
||||
if (super_version_ != nullptr) {
|
||||
// Release SuperVersion reference kept in ThreadLocalPtr.
|
||||
// This must be done outside of mutex_ since unref handler can lock mutex.
|
||||
super_version_->db_mutex->Unlock();
|
||||
local_sv_.reset();
|
||||
super_version_->db_mutex->Lock();
|
||||
|
||||
bool is_last_reference __attribute__((__unused__));
|
||||
is_last_reference = super_version_->Unref();
|
||||
assert(is_last_reference);
|
||||
super_version_->Cleanup();
|
||||
delete super_version_;
|
||||
super_version_ = nullptr;
|
||||
}
|
||||
assert(super_version_ == nullptr);
|
||||
|
||||
if (dummy_versions_ != nullptr) {
|
||||
// List must be empty
|
||||
@@ -552,6 +628,48 @@ ColumnFamilyData::~ColumnFamilyData() {
|
||||
for (MemTable* m : to_delete) {
|
||||
delete m;
|
||||
}
|
||||
|
||||
if (db_paths_registered_) {
|
||||
// TODO(cc): considering using ioptions_.fs, currently some tests rely on
|
||||
// EnvWrapper, that's the main reason why we use env here.
|
||||
Status s = ioptions_.env->UnregisterDbPaths(GetDbPaths());
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_ERROR(
|
||||
ioptions_.info_log,
|
||||
"Failed to unregister data paths of column family (id: %d, name: %s)",
|
||||
id_, name_.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ColumnFamilyData::UnrefAndTryDelete() {
|
||||
int old_refs = refs_.fetch_sub(1);
|
||||
assert(old_refs > 0);
|
||||
|
||||
if (old_refs == 1) {
|
||||
assert(super_version_ == nullptr);
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (old_refs == 2 && super_version_ != nullptr) {
|
||||
// Only the super_version_ holds me
|
||||
SuperVersion* sv = super_version_;
|
||||
super_version_ = nullptr;
|
||||
// Release SuperVersion reference kept in ThreadLocalPtr.
|
||||
// This must be done outside of mutex_ since unref handler can lock mutex.
|
||||
sv->db_mutex->Unlock();
|
||||
local_sv_.reset();
|
||||
sv->db_mutex->Lock();
|
||||
|
||||
if (sv->Unref()) {
|
||||
// May delete this ColumnFamilyData after calling Cleanup()
|
||||
sv->Cleanup();
|
||||
delete sv;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ColumnFamilyData::SetDropped() {
|
||||
@@ -888,8 +1006,8 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions(
|
||||
return write_stall_condition;
|
||||
}
|
||||
|
||||
const EnvOptions* ColumnFamilyData::soptions() const {
|
||||
return &(column_family_set_->env_options_);
|
||||
const FileOptions* ColumnFamilyData::soptions() const {
|
||||
return &(column_family_set_->file_options_);
|
||||
}
|
||||
|
||||
void ColumnFamilyData::SetCurrent(Version* current_version) {
|
||||
@@ -929,8 +1047,12 @@ bool ColumnFamilyData::NeedsCompaction() const {
|
||||
|
||||
Compaction* ColumnFamilyData::PickCompaction(
|
||||
const MutableCFOptions& mutable_options, LogBuffer* log_buffer) {
|
||||
SequenceNumber earliest_mem_seqno =
|
||||
std::min(mem_->GetEarliestSequenceNumber(),
|
||||
imm_.current()->GetEarliestSequenceNumber(false));
|
||||
auto* result = compaction_picker_->PickCompaction(
|
||||
GetName(), mutable_options, current_->storage_info(), log_buffer);
|
||||
GetName(), mutable_options, current_->storage_info(), log_buffer,
|
||||
earliest_mem_seqno);
|
||||
if (result != nullptr) {
|
||||
result->SetInputVersion(current_);
|
||||
}
|
||||
@@ -1015,9 +1137,8 @@ Compaction* ColumnFamilyData::CompactRange(
|
||||
return result;
|
||||
}
|
||||
|
||||
SuperVersion* ColumnFamilyData::GetReferencedSuperVersion(
|
||||
InstrumentedMutex* db_mutex) {
|
||||
SuperVersion* sv = GetThreadLocalSuperVersion(db_mutex);
|
||||
SuperVersion* ColumnFamilyData::GetReferencedSuperVersion(DBImpl* db) {
|
||||
SuperVersion* sv = GetThreadLocalSuperVersion(db);
|
||||
sv->Ref();
|
||||
if (!ReturnThreadLocalSuperVersion(sv)) {
|
||||
// This Unref() corresponds to the Ref() in GetThreadLocalSuperVersion()
|
||||
@@ -1029,8 +1150,7 @@ SuperVersion* ColumnFamilyData::GetReferencedSuperVersion(
|
||||
return sv;
|
||||
}
|
||||
|
||||
SuperVersion* ColumnFamilyData::GetThreadLocalSuperVersion(
|
||||
InstrumentedMutex* db_mutex) {
|
||||
SuperVersion* ColumnFamilyData::GetThreadLocalSuperVersion(DBImpl* db) {
|
||||
// The SuperVersion is cached in thread local storage to avoid acquiring
|
||||
// mutex when SuperVersion does not change since the last use. When a new
|
||||
// SuperVersion is installed, the compaction or flush thread cleans up
|
||||
@@ -1057,16 +1177,21 @@ SuperVersion* ColumnFamilyData::GetThreadLocalSuperVersion(
|
||||
|
||||
if (sv && sv->Unref()) {
|
||||
RecordTick(ioptions_.statistics, NUMBER_SUPERVERSION_CLEANUPS);
|
||||
db_mutex->Lock();
|
||||
db->mutex()->Lock();
|
||||
// NOTE: underlying resources held by superversion (sst files) might
|
||||
// not be released until the next background job.
|
||||
sv->Cleanup();
|
||||
sv_to_delete = sv;
|
||||
if (db->immutable_db_options().avoid_unnecessary_blocking_io) {
|
||||
db->AddSuperVersionsToFreeQueue(sv);
|
||||
db->SchedulePurge();
|
||||
} else {
|
||||
sv_to_delete = sv;
|
||||
}
|
||||
} else {
|
||||
db_mutex->Lock();
|
||||
db->mutex()->Lock();
|
||||
}
|
||||
sv = super_version_->Ref();
|
||||
db_mutex->Unlock();
|
||||
db->mutex()->Unlock();
|
||||
|
||||
delete sv_to_delete;
|
||||
}
|
||||
@@ -1104,7 +1229,7 @@ void ColumnFamilyData::InstallSuperVersion(
|
||||
SuperVersion* new_superversion = sv_context->new_superversion.release();
|
||||
new_superversion->db_mutex = db_mutex;
|
||||
new_superversion->mutable_cf_options = mutable_cf_options;
|
||||
new_superversion->Init(mem_, imm_.current(), current_);
|
||||
new_superversion->Init(this, mem_, imm_.current(), current_);
|
||||
SuperVersion* old_superversion = super_version_;
|
||||
super_version_ = new_superversion;
|
||||
++super_version_number_;
|
||||
@@ -1161,6 +1286,11 @@ Status ColumnFamilyData::ValidateOptions(
|
||||
if (s.ok() && db_options.allow_concurrent_memtable_write) {
|
||||
s = CheckConcurrentWritesSupported(cf_options);
|
||||
}
|
||||
if (s.ok() && db_options.unordered_write &&
|
||||
cf_options.max_successive_merges != 0) {
|
||||
s = Status::InvalidArgument(
|
||||
"max_successive_merges > 0 is incompatible with unordered_write");
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = CheckCFPathsSupported(db_options, cf_options);
|
||||
}
|
||||
@@ -1168,24 +1298,15 @@ Status ColumnFamilyData::ValidateOptions(
|
||||
return s;
|
||||
}
|
||||
|
||||
if (cf_options.ttl > 0) {
|
||||
if (db_options.max_open_files != -1) {
|
||||
return Status::NotSupported(
|
||||
"TTL is only supported when files are always "
|
||||
"kept open (set max_open_files = -1). ");
|
||||
}
|
||||
if (cf_options.ttl > 0 && cf_options.ttl != kDefaultTtl) {
|
||||
if (cf_options.table_factory->Name() != BlockBasedTableFactory().Name()) {
|
||||
return Status::NotSupported(
|
||||
"TTL is only supported in Block-Based Table format. ");
|
||||
}
|
||||
}
|
||||
|
||||
if (cf_options.periodic_compaction_seconds > 0) {
|
||||
if (db_options.max_open_files != -1) {
|
||||
return Status::NotSupported(
|
||||
"Periodic Compaction is only supported when files are always "
|
||||
"kept open (set max_open_files = -1). ");
|
||||
}
|
||||
if (cf_options.periodic_compaction_seconds > 0 &&
|
||||
cf_options.periodic_compaction_seconds != kDefaultPeriodicCompSecs) {
|
||||
if (cf_options.table_factory->Name() != BlockBasedTableFactory().Name()) {
|
||||
return Status::NotSupported(
|
||||
"Periodic Compaction is only supported in "
|
||||
@@ -1229,28 +1350,41 @@ Env::WriteLifeTimeHint ColumnFamilyData::CalculateSSTWriteHint(int level) {
|
||||
// L1: medium, L2: long, ...
|
||||
if (level - base_level >= 2) {
|
||||
return Env::WLTH_EXTREME;
|
||||
} else if (level < base_level) {
|
||||
// There is no restriction which prevents level passed in to be smaller
|
||||
// than base_level.
|
||||
return Env::WLTH_MEDIUM;
|
||||
}
|
||||
return static_cast<Env::WriteLifeTimeHint>(level - base_level +
|
||||
static_cast<int>(Env::WLTH_MEDIUM));
|
||||
}
|
||||
|
||||
Status ColumnFamilyData::AddDirectories() {
|
||||
Status ColumnFamilyData::AddDirectories(
|
||||
std::map<std::string, std::shared_ptr<FSDirectory>>* created_dirs) {
|
||||
Status s;
|
||||
assert(created_dirs != nullptr);
|
||||
assert(data_dirs_.empty());
|
||||
for (auto& p : ioptions_.cf_paths) {
|
||||
std::unique_ptr<Directory> path_directory;
|
||||
s = DBImpl::CreateAndNewDirectory(ioptions_.env, p.path, &path_directory);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
auto existing_dir = created_dirs->find(p.path);
|
||||
|
||||
if (existing_dir == created_dirs->end()) {
|
||||
std::unique_ptr<FSDirectory> path_directory;
|
||||
s = DBImpl::CreateAndNewDirectory(ioptions_.fs, p.path, &path_directory);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
assert(path_directory != nullptr);
|
||||
data_dirs_.emplace_back(path_directory.release());
|
||||
(*created_dirs)[p.path] = data_dirs_.back();
|
||||
} else {
|
||||
data_dirs_.emplace_back(existing_dir->second);
|
||||
}
|
||||
assert(path_directory != nullptr);
|
||||
data_dirs_.emplace_back(path_directory.release());
|
||||
}
|
||||
assert(data_dirs_.size() == ioptions_.cf_paths.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
Directory* ColumnFamilyData::GetDataDir(size_t path_id) const {
|
||||
FSDirectory* ColumnFamilyData::GetDataDir(size_t path_id) const {
|
||||
if (data_dirs_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1261,19 +1395,20 @@ Directory* ColumnFamilyData::GetDataDir(size_t path_id) const {
|
||||
|
||||
ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
|
||||
const ImmutableDBOptions* db_options,
|
||||
const EnvOptions& env_options,
|
||||
const FileOptions& file_options,
|
||||
Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager,
|
||||
WriteController* write_controller,
|
||||
BlockCacheTracer* const block_cache_tracer)
|
||||
: max_column_family_(0),
|
||||
dummy_cfd_(new ColumnFamilyData(
|
||||
0, "", nullptr, nullptr, nullptr, ColumnFamilyOptions(), *db_options,
|
||||
env_options, nullptr, block_cache_tracer)),
|
||||
ColumnFamilyData::kDummyColumnFamilyDataId, "", nullptr, nullptr,
|
||||
nullptr, ColumnFamilyOptions(), *db_options, file_options, nullptr,
|
||||
block_cache_tracer)),
|
||||
default_cfd_cache_(nullptr),
|
||||
db_name_(dbname),
|
||||
db_options_(db_options),
|
||||
env_options_(env_options),
|
||||
file_options_(file_options),
|
||||
table_cache_(table_cache),
|
||||
write_buffer_manager_(write_buffer_manager),
|
||||
write_controller_(write_controller),
|
||||
@@ -1288,14 +1423,12 @@ ColumnFamilySet::~ColumnFamilySet() {
|
||||
// cfd destructor will delete itself from column_family_data_
|
||||
auto cfd = column_family_data_.begin()->second;
|
||||
bool last_ref __attribute__((__unused__));
|
||||
last_ref = cfd->Unref();
|
||||
last_ref = cfd->UnrefAndTryDelete();
|
||||
assert(last_ref);
|
||||
delete cfd;
|
||||
}
|
||||
bool dummy_last_ref __attribute__((__unused__));
|
||||
dummy_last_ref = dummy_cfd_->Unref();
|
||||
dummy_last_ref = dummy_cfd_->UnrefAndTryDelete();
|
||||
assert(dummy_last_ref);
|
||||
delete dummy_cfd_;
|
||||
}
|
||||
|
||||
ColumnFamilyData* ColumnFamilySet::GetDefault() const {
|
||||
@@ -1345,7 +1478,7 @@ ColumnFamilyData* ColumnFamilySet::CreateColumnFamily(
|
||||
assert(column_families_.find(name) == column_families_.end());
|
||||
ColumnFamilyData* new_cfd = new ColumnFamilyData(
|
||||
id, name, dummy_versions, table_cache_, write_buffer_manager_, options,
|
||||
*db_options_, env_options_, this, block_cache_tracer_);
|
||||
*db_options_, file_options_, this, block_cache_tracer_);
|
||||
column_families_.insert({name, id});
|
||||
column_family_data_.insert({id, new_cfd});
|
||||
max_column_family_ = std::max(max_column_family_, id);
|
||||
@@ -1427,4 +1560,4 @@ const Comparator* GetColumnFamilyUserComparator(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+27
-13
@@ -27,7 +27,7 @@
|
||||
#include "trace_replay/block_cache_tracer.h"
|
||||
#include "util/thread_local.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class Version;
|
||||
class VersionSet;
|
||||
@@ -198,6 +198,7 @@ class ColumnFamilyHandleInternal : public ColumnFamilyHandleImpl {
|
||||
struct SuperVersion {
|
||||
// Accessing members of this class is not thread-safe and requires external
|
||||
// synchronization (ie db mutex held or on write thread).
|
||||
ColumnFamilyData* cfd;
|
||||
MemTable* mem;
|
||||
MemTableListVersion* imm;
|
||||
Version* current;
|
||||
@@ -221,8 +222,8 @@ struct SuperVersion {
|
||||
// that needs to be deleted in to_delete vector. Unrefing those
|
||||
// objects needs to be done in the mutex
|
||||
void Cleanup();
|
||||
void Init(MemTable* new_mem, MemTableListVersion* new_imm,
|
||||
Version* new_current);
|
||||
void Init(ColumnFamilyData* new_cfd, MemTable* new_mem,
|
||||
MemTableListVersion* new_imm, Version* new_current);
|
||||
|
||||
// The value of dummy is not actually used. kSVInUse takes its address as a
|
||||
// mark in the thread local storage to indicate the SuperVersion is in use
|
||||
@@ -288,6 +289,11 @@ class ColumnFamilyData {
|
||||
return old_refs == 1;
|
||||
}
|
||||
|
||||
// UnrefAndTryDelete() decreases the reference count and do free if needed,
|
||||
// return true if this is freed else false, UnrefAndTryDelete() can only
|
||||
// be called while holding a DB mutex, or during single-threaded recovery.
|
||||
bool UnrefAndTryDelete();
|
||||
|
||||
// SetDropped() can only be called under following conditions:
|
||||
// 1) Holding a DB mutex,
|
||||
// 2) from single-threaded write thread, AND
|
||||
@@ -318,7 +324,7 @@ class ColumnFamilyData {
|
||||
}
|
||||
FlushReason GetFlushReason() const { return flush_reason_; }
|
||||
// thread-safe
|
||||
const EnvOptions* soptions() const;
|
||||
const FileOptions* soptions() const;
|
||||
const ImmutableCFOptions* ioptions() const { return &ioptions_; }
|
||||
// REQUIRES: DB mutex held
|
||||
// This returns the MutableCFOptions used by current SuperVersion
|
||||
@@ -430,11 +436,11 @@ class ColumnFamilyData {
|
||||
SuperVersion* GetSuperVersion() { return super_version_; }
|
||||
// thread-safe
|
||||
// Return a already referenced SuperVersion to be used safely.
|
||||
SuperVersion* GetReferencedSuperVersion(InstrumentedMutex* db_mutex);
|
||||
SuperVersion* GetReferencedSuperVersion(DBImpl* db);
|
||||
// thread-safe
|
||||
// Get SuperVersion stored in thread local storage. If it does not exist,
|
||||
// get a reference from a current SuperVersion.
|
||||
SuperVersion* GetThreadLocalSuperVersion(InstrumentedMutex* db_mutex);
|
||||
SuperVersion* GetThreadLocalSuperVersion(DBImpl* db);
|
||||
// Try to return SuperVersion back to thread local storage. Retrun true on
|
||||
// success and false on failure. It fails when the thread local storage
|
||||
// contains anything other than SuperVersion::kSVInUse flag.
|
||||
@@ -491,23 +497,29 @@ class ColumnFamilyData {
|
||||
|
||||
Env::WriteLifeTimeHint CalculateSSTWriteHint(int level);
|
||||
|
||||
Status AddDirectories();
|
||||
// created_dirs remembers directory created, so that we don't need to call
|
||||
// the same data creation operation again.
|
||||
Status AddDirectories(
|
||||
std::map<std::string, std::shared_ptr<FSDirectory>>* created_dirs);
|
||||
|
||||
Directory* GetDataDir(size_t path_id) const;
|
||||
FSDirectory* GetDataDir(size_t path_id) const;
|
||||
|
||||
ThreadLocalPtr* TEST_GetLocalSV() { return local_sv_.get(); }
|
||||
|
||||
private:
|
||||
friend class ColumnFamilySet;
|
||||
static const uint32_t kDummyColumnFamilyDataId;
|
||||
ColumnFamilyData(uint32_t id, const std::string& name,
|
||||
Version* dummy_versions, Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager,
|
||||
const ColumnFamilyOptions& options,
|
||||
const ImmutableDBOptions& db_options,
|
||||
const EnvOptions& env_options,
|
||||
const FileOptions& file_options,
|
||||
ColumnFamilySet* column_family_set,
|
||||
BlockCacheTracer* const block_cache_tracer);
|
||||
|
||||
std::vector<std::string> GetDbPaths() const;
|
||||
|
||||
uint32_t id_;
|
||||
const std::string name_;
|
||||
Version* dummy_versions_; // Head of circular doubly-linked list of versions.
|
||||
@@ -583,7 +595,9 @@ class ColumnFamilyData {
|
||||
std::atomic<uint64_t> last_memtable_id_;
|
||||
|
||||
// Directories corresponding to cf_paths.
|
||||
std::vector<std::unique_ptr<Directory>> data_dirs_;
|
||||
std::vector<std::shared_ptr<FSDirectory>> data_dirs_;
|
||||
|
||||
bool db_paths_registered_;
|
||||
};
|
||||
|
||||
// ColumnFamilySet has interesting thread-safety requirements
|
||||
@@ -632,7 +646,7 @@ class ColumnFamilySet {
|
||||
|
||||
ColumnFamilySet(const std::string& dbname,
|
||||
const ImmutableDBOptions* db_options,
|
||||
const EnvOptions& env_options, Cache* table_cache,
|
||||
const FileOptions& file_options, Cache* table_cache,
|
||||
WriteBufferManager* write_buffer_manager,
|
||||
WriteController* write_controller,
|
||||
BlockCacheTracer* const block_cache_tracer);
|
||||
@@ -690,7 +704,7 @@ class ColumnFamilySet {
|
||||
|
||||
const std::string db_name_;
|
||||
const ImmutableDBOptions* const db_options_;
|
||||
const EnvOptions env_options_;
|
||||
const FileOptions file_options_;
|
||||
Cache* table_cache_;
|
||||
WriteBufferManager* write_buffer_manager_;
|
||||
WriteController* write_controller_;
|
||||
@@ -745,4 +759,4 @@ extern uint32_t GetColumnFamilyID(ColumnFamilyHandle* column_family);
|
||||
extern const Comparator* GetColumnFamilyUserComparator(
|
||||
ColumnFamilyHandle* column_family);
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+132
-91
@@ -30,7 +30,7 @@
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
static const int kValueSize = 1000;
|
||||
|
||||
@@ -67,9 +67,9 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
#ifndef ROCKSDB_LITE
|
||||
const char* test_env_uri = getenv("TEST_ENV_URI");
|
||||
if (test_env_uri) {
|
||||
Status s = ObjectRegistry::NewInstance()->NewSharedObject(test_env_uri,
|
||||
&env_guard_);
|
||||
base_env = env_guard_.get();
|
||||
Env* test_env = nullptr;
|
||||
Status s = Env::LoadEnv(test_env_uri, &test_env, &env_guard_);
|
||||
base_env = test_env;
|
||||
EXPECT_OK(s);
|
||||
EXPECT_NE(Env::Default(), base_env);
|
||||
}
|
||||
@@ -91,7 +91,7 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
column_families.push_back(cfdescriptor);
|
||||
}
|
||||
Close();
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
Destroy(column_families);
|
||||
delete env_;
|
||||
}
|
||||
@@ -595,14 +595,15 @@ TEST_P(ColumnFamilyTest, DontReuseColumnFamilyID) {
|
||||
TEST_P(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
|
||||
Open();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::WriteOptionsFile:1",
|
||||
"ColumnFamilyTest.CreateCFRaceWithGetAggProperty:1"},
|
||||
{"ColumnFamilyTest.CreateCFRaceWithGetAggProperty:2",
|
||||
"DBImpl::WriteOptionsFile:2"}});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
rocksdb::port::Thread thread([&] { CreateColumnFamilies({"one"}); });
|
||||
ROCKSDB_NAMESPACE::port::Thread thread(
|
||||
[&] { CreateColumnFamilies({"one"}); });
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest.CreateCFRaceWithGetAggProperty:1");
|
||||
uint64_t pv;
|
||||
@@ -611,7 +612,7 @@ TEST_P(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
|
||||
|
||||
thread.join();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -820,7 +821,7 @@ TEST_P(ColumnFamilyTest, BulkAddDrop) {
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, DropTest) {
|
||||
// first iteration - dont reopen DB before dropping
|
||||
// first iteration - don't reopen DB before dropping
|
||||
// second iteration - reopen DB before dropping
|
||||
for (int iter = 0; iter < 2; ++iter) {
|
||||
Open({"default"});
|
||||
@@ -1253,13 +1254,14 @@ TEST_P(ColumnFamilyTest, DifferentWriteBufferSizes) {
|
||||
// #endif // !ROCKSDB_LITE
|
||||
|
||||
class TestComparator : public Comparator {
|
||||
int Compare(const rocksdb::Slice& /*a*/,
|
||||
const rocksdb::Slice& /*b*/) const override {
|
||||
int Compare(const ROCKSDB_NAMESPACE::Slice& /*a*/,
|
||||
const ROCKSDB_NAMESPACE::Slice& /*b*/) const override {
|
||||
return 0;
|
||||
}
|
||||
const char* Name() const override { return "Test"; }
|
||||
void FindShortestSeparator(std::string* /*start*/,
|
||||
const rocksdb::Slice& /*limit*/) const override {}
|
||||
void FindShortestSeparator(
|
||||
std::string* /*start*/,
|
||||
const ROCKSDB_NAMESPACE::Slice& /*limit*/) const override {}
|
||||
void FindShortSuccessor(std::string* /*key*/) const override {}
|
||||
};
|
||||
|
||||
@@ -1427,11 +1429,11 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::MultiManual:4", "ColumnFamilyTest::MultiManual:1"},
|
||||
{"ColumnFamilyTest::MultiManual:2", "ColumnFamilyTest::MultiManual:5"},
|
||||
{"ColumnFamilyTest::MultiManual:2", "ColumnFamilyTest::MultiManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::MultiManual:4");
|
||||
@@ -1440,7 +1442,7 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
std::vector<port::Thread> threads;
|
||||
threads.emplace_back([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
@@ -1483,8 +1485,8 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -1523,11 +1525,11 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
dbfull()->TEST_write_controler().GetCompactionPressureToken();
|
||||
|
||||
bool cf_1_1 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::AutoManual:4", "ColumnFamilyTest::AutoManual:1"},
|
||||
{"ColumnFamilyTest::AutoManual:2", "ColumnFamilyTest::AutoManual:5"},
|
||||
{"ColumnFamilyTest::AutoManual:2", "ColumnFamilyTest::AutoManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
cf_1_1 = false;
|
||||
@@ -1535,7 +1537,7 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::AutoManual:3");
|
||||
}
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
// SETUP column family "one" -- universal style
|
||||
for (int i = 0; i < one.level0_file_num_compaction_trigger; ++i) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
@@ -1553,7 +1555,7 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
WaitForFlush(2);
|
||||
AssertFilesPerLevel(ToString(i + 1), 2);
|
||||
}
|
||||
rocksdb::port::Thread threads([&] {
|
||||
ROCKSDB_NAMESPACE::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(
|
||||
@@ -1580,8 +1582,8 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
@@ -1627,11 +1629,11 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::ManualAuto:4", "ColumnFamilyTest::ManualAuto:1"},
|
||||
{"ColumnFamilyTest::ManualAuto:5", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"ColumnFamilyTest::ManualAuto:2", "ColumnFamilyTest::ManualAuto:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:4");
|
||||
@@ -1643,8 +1645,8 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
rocksdb::port::Thread threads([&] {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(
|
||||
@@ -1679,8 +1681,8 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
@@ -1721,13 +1723,13 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::ManualManual:4", "ColumnFamilyTest::ManualManual:2"},
|
||||
{"ColumnFamilyTest::ManualManual:4", "ColumnFamilyTest::ManualManual:5"},
|
||||
{"ColumnFamilyTest::ManualManual:1", "ColumnFamilyTest::ManualManual:2"},
|
||||
{"ColumnFamilyTest::ManualManual:1",
|
||||
"ColumnFamilyTest::ManualManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualManual:4");
|
||||
@@ -1739,8 +1741,8 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
rocksdb::port::Thread threads([&] {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = true;
|
||||
ASSERT_OK(
|
||||
@@ -1760,7 +1762,7 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
1);
|
||||
}
|
||||
|
||||
rocksdb::port::Thread threads1([&] {
|
||||
ROCKSDB_NAMESPACE::port::Thread threads1([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(
|
||||
@@ -1781,8 +1783,8 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
@@ -1823,12 +1825,12 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::ManualAuto:4", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"ColumnFamilyTest::ManualAuto:4", "ColumnFamilyTest::ManualAuto:5"},
|
||||
{"ColumnFamilyTest::ManualAuto:1", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"ColumnFamilyTest::ManualAuto:1", "ColumnFamilyTest::ManualAuto:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:4");
|
||||
@@ -1840,8 +1842,8 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
rocksdb::port::Thread threads([&] {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(
|
||||
@@ -1874,8 +1876,8 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
@@ -1916,14 +1918,14 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::ManualAuto:4", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"ColumnFamilyTest::ManualAuto:4", "ColumnFamilyTest::ManualAuto:5"},
|
||||
{"ColumnFamilyTest::ManualAuto:3", "ColumnFamilyTest::ManualAuto:2"},
|
||||
{"LevelCompactionPicker::PickCompactionBySize:0",
|
||||
"ColumnFamilyTest::ManualAuto:3"},
|
||||
{"ColumnFamilyTest::ManualAuto:1", "ColumnFamilyTest::ManualAuto:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:4");
|
||||
@@ -1935,8 +1937,8 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
rocksdb::port::Thread threads([&] {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.exclusive_manual_compaction = false;
|
||||
ASSERT_OK(
|
||||
@@ -1967,8 +1969,8 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
// In this test, we generate enough files to trigger automatic compactions.
|
||||
@@ -2008,12 +2010,12 @@ TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
|
||||
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ColumnFamilyTest::AutoManual:4", "ColumnFamilyTest::AutoManual:2"},
|
||||
{"ColumnFamilyTest::AutoManual:4", "ColumnFamilyTest::AutoManual:5"},
|
||||
{"CompactionPicker::CompactRange:Conflict",
|
||||
"ColumnFamilyTest::AutoManual:3"}});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun", [&](void* /*arg*/) {
|
||||
if (cf_1_1) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::AutoManual:4");
|
||||
@@ -2025,7 +2027,7 @@ TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// SETUP column family "one" -- universal style
|
||||
for (int i = 0; i < one.level0_file_num_compaction_trigger; ++i) {
|
||||
@@ -2059,8 +2061,8 @@ TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
|
||||
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
|
||||
key_iter++;
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -2365,6 +2367,45 @@ TEST_P(ColumnFamilyTest, ReadDroppedColumnFamily) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, LiveIteratorWithDroppedColumnFamily) {
|
||||
db_options_.create_missing_column_families = true;
|
||||
db_options_.max_open_files = 20;
|
||||
// delete obsolete files always
|
||||
db_options_.delete_obsolete_files_period_micros = 0;
|
||||
Open({"default", "one", "two"});
|
||||
ColumnFamilyOptions options;
|
||||
options.level0_file_num_compaction_trigger = 100;
|
||||
options.level0_slowdown_writes_trigger = 200;
|
||||
options.level0_stop_writes_trigger = 200;
|
||||
options.write_buffer_size = 100000; // small write buffer size
|
||||
Reopen({options, options, options});
|
||||
|
||||
// 1MB should create ~10 files for each CF
|
||||
int kKeysNum = 10000;
|
||||
PutRandomData(1, kKeysNum, 100);
|
||||
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(
|
||||
db_->NewIterator(ReadOptions(), handles_[1]));
|
||||
iterator->SeekToFirst();
|
||||
|
||||
DropColumnFamilies({1});
|
||||
|
||||
// Make sure iterator created can still be used.
|
||||
int count = 0;
|
||||
for (; iterator->Valid(); iterator->Next()) {
|
||||
ASSERT_OK(iterator->status());
|
||||
++count;
|
||||
}
|
||||
ASSERT_OK(iterator->status());
|
||||
ASSERT_EQ(count, kKeysNum);
|
||||
}
|
||||
|
||||
Reopen();
|
||||
Close();
|
||||
Destroy();
|
||||
}
|
||||
|
||||
TEST_P(ColumnFamilyTest, FlushAndDropRaceCondition) {
|
||||
db_options_.create_missing_column_families = true;
|
||||
Open({"default", "one"});
|
||||
@@ -2376,7 +2417,7 @@ TEST_P(ColumnFamilyTest, FlushAndDropRaceCondition) {
|
||||
options.write_buffer_size = 100000; // small write buffer size
|
||||
Reopen({options, options});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"VersionSet::LogAndApply::ColumnFamilyDrop:0",
|
||||
"FlushJob::WriteLevel0Table"},
|
||||
{"VersionSet::LogAndApply::ColumnFamilyDrop:1",
|
||||
@@ -2384,7 +2425,7 @@ TEST_P(ColumnFamilyTest, FlushAndDropRaceCondition) {
|
||||
{"FlushJob::InstallResults",
|
||||
"VersionSet::LogAndApply::ColumnFamilyDrop:2"}});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
test::SleepingBackgroundTask sleeping_task;
|
||||
|
||||
env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task,
|
||||
@@ -2463,21 +2504,21 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
|
||||
|
||||
auto main_thread_id = std::this_thread::get_id();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack("PersistRocksDBOptions:start",
|
||||
[&](void* /*arg*/) {
|
||||
auto current_thread_id = std::this_thread::get_id();
|
||||
// If it's the main thread hitting this sync-point, then it
|
||||
// will be blocked until some other thread update the test_stage.
|
||||
if (main_thread_id == current_thread_id) {
|
||||
test_stage = kMainThreadStartPersistingOptionsFile;
|
||||
while (test_stage < kChildThreadFinishDroppingColumnFamily &&
|
||||
!ordered_by_writethread) {
|
||||
Env::Default()->SleepForMicroseconds(100);
|
||||
}
|
||||
}
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"PersistRocksDBOptions:start", [&](void* /*arg*/) {
|
||||
auto current_thread_id = std::this_thread::get_id();
|
||||
// If it's the main thread hitting this sync-point, then it
|
||||
// will be blocked until some other thread update the test_stage.
|
||||
if (main_thread_id == current_thread_id) {
|
||||
test_stage = kMainThreadStartPersistingOptionsFile;
|
||||
while (test_stage < kChildThreadFinishDroppingColumnFamily &&
|
||||
!ordered_by_writethread) {
|
||||
Env::Default()->SleepForMicroseconds(100);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteThread::EnterUnbatched:Wait", [&](void* /*arg*/) {
|
||||
// This means a thread doing DropColumnFamily() is waiting for
|
||||
// other thread to finish persisting options.
|
||||
@@ -2489,12 +2530,12 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
|
||||
Open({"default", "one", "two", "three"},
|
||||
{cf_opts[0], cf_opts[1], cf_opts[2], cf_opts[3]});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Start a thread that will drop the first column family
|
||||
// and its comparator
|
||||
rocksdb::port::Thread drop_cf_thread(DropSingleColumnFamily, this, 1,
|
||||
&comparators);
|
||||
ROCKSDB_NAMESPACE::port::Thread drop_cf_thread(DropSingleColumnFamily, this,
|
||||
1, &comparators);
|
||||
|
||||
DropColumnFamilies({2});
|
||||
|
||||
@@ -2507,8 +2548,8 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
|
||||
}
|
||||
}
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -2943,10 +2984,10 @@ TEST_P(ColumnFamilyTest, FlushCloseWALFiles) {
|
||||
ASSERT_OK(Put(0, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"DBImpl::BGWorkFlush:done", "FlushCloseWALFiles:0"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Block flush jobs from running
|
||||
test::SleepingBackgroundTask sleeping_task;
|
||||
@@ -2962,7 +3003,7 @@ TEST_P(ColumnFamilyTest, FlushCloseWALFiles) {
|
||||
sleeping_task.WakeUp();
|
||||
sleeping_task.WaitUntilDone();
|
||||
TEST_SYNC_POINT("FlushCloseWALFiles:0");
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ASSERT_EQ(1, env.num_open_wal_file_.load());
|
||||
|
||||
Reopen();
|
||||
@@ -3040,14 +3081,14 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
|
||||
ASSERT_OK(Put(0, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"ColumnFamilyTest::IteratorCloseWALFile2:0",
|
||||
"DBImpl::BGWorkPurge:start"},
|
||||
{"ColumnFamilyTest::IteratorCloseWALFile2:2",
|
||||
"DBImpl::BackgroundCallFlush:start"},
|
||||
{"DBImpl::BGWorkPurge:end", "ColumnFamilyTest::IteratorCloseWALFile2:1"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
WriteOptions wo;
|
||||
wo.sync = true;
|
||||
@@ -3065,7 +3106,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::IteratorCloseWALFile2:2");
|
||||
WaitForFlush(1);
|
||||
ASSERT_EQ(1, env.num_open_wal_file_.load());
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
Reopen();
|
||||
ASSERT_EQ("mirko", Get(0, "fodor"));
|
||||
@@ -3109,14 +3150,14 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
|
||||
ASSERT_OK(Put(0, "fodor", "mirko"));
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"ColumnFamilyTest::IteratorCloseWALFile2:0",
|
||||
"DBImpl::BGWorkPurge:start"},
|
||||
{"ColumnFamilyTest::IteratorCloseWALFile2:2",
|
||||
"DBImpl::BackgroundCallFlush:start"},
|
||||
{"DBImpl::BGWorkPurge:end", "ColumnFamilyTest::IteratorCloseWALFile2:1"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
WriteOptions wo;
|
||||
wo.sync = true;
|
||||
@@ -3140,7 +3181,7 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
|
||||
ASSERT_EQ(1, env.delete_count_.load());
|
||||
|
||||
delete it;
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
Reopen();
|
||||
ASSERT_EQ("mirko", Get(0, "fodor"));
|
||||
@@ -3160,15 +3201,15 @@ TEST_P(ColumnFamilyTest, LogSyncConflictFlush) {
|
||||
Put(0, "", "");
|
||||
Put(1, "foo", "bar");
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::SyncWAL:BeforeMarkLogsSynced:1",
|
||||
"ColumnFamilyTest::LogSyncConflictFlush:1"},
|
||||
{"ColumnFamilyTest::LogSyncConflictFlush:2",
|
||||
"DBImpl::SyncWAL:BeforeMarkLogsSynced:2"}});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
rocksdb::port::Thread thread([&] { db_->SyncWAL(); });
|
||||
ROCKSDB_NAMESPACE::port::Thread thread([&] { db_->SyncWAL(); });
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::LogSyncConflictFlush:1");
|
||||
Flush(1);
|
||||
@@ -3179,7 +3220,7 @@ TEST_P(ColumnFamilyTest, LogSyncConflictFlush) {
|
||||
|
||||
thread.join();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
Close();
|
||||
}
|
||||
#endif
|
||||
@@ -3328,7 +3369,7 @@ TEST_P(ColumnFamilyTest, MultipleCFPathsTest) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
@@ -3339,7 +3380,7 @@ void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
+16
-16
@@ -18,7 +18,7 @@
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class CompactFilesTest : public testing::Test {
|
||||
public:
|
||||
@@ -81,11 +81,11 @@ TEST_F(CompactFilesTest, L0ConflictsFiles) {
|
||||
assert(s.ok());
|
||||
assert(db);
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"CompactFilesImpl:0", "BackgroundCallCompaction:0"},
|
||||
{"BackgroundCallCompaction:1", "CompactFilesImpl:1"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// create couple files
|
||||
// Background compaction starts and waits in BackgroundCallCompaction:0
|
||||
@@ -95,7 +95,7 @@ TEST_F(CompactFilesTest, L0ConflictsFiles) {
|
||||
db->Flush(FlushOptions());
|
||||
}
|
||||
|
||||
rocksdb::ColumnFamilyMetaData meta;
|
||||
ROCKSDB_NAMESPACE::ColumnFamilyMetaData meta;
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
std::string file1;
|
||||
for (auto& file : meta.levels[0].files) {
|
||||
@@ -108,12 +108,12 @@ TEST_F(CompactFilesTest, L0ConflictsFiles) {
|
||||
// The background compaction then notices that there is an L0 compaction
|
||||
// already in progress and doesn't do an L0 compaction
|
||||
// Once the background compaction finishes, the compact files finishes
|
||||
ASSERT_OK(
|
||||
db->CompactFiles(rocksdb::CompactionOptions(), {file1, file2}, 0));
|
||||
ASSERT_OK(db->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(),
|
||||
{file1, file2}, 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
delete db;
|
||||
}
|
||||
|
||||
@@ -224,14 +224,14 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
EXPECT_EQ(5, l0_files.size());
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"CompactFilesImpl:2", "CompactFilesTest.CapturingPendingFiles:0"},
|
||||
{"CompactFilesTest.CapturingPendingFiles:1", "CompactFilesImpl:3"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Start compacting files.
|
||||
rocksdb::port::Thread compaction_thread(
|
||||
ROCKSDB_NAMESPACE::port::Thread compaction_thread(
|
||||
[&] { EXPECT_OK(db->CompactFiles(CompactionOptions(), l0_files, 1)); });
|
||||
|
||||
// In the meantime flush another file.
|
||||
@@ -242,7 +242,7 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
|
||||
compaction_thread.join();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
delete db;
|
||||
|
||||
@@ -296,12 +296,12 @@ TEST_F(CompactFilesTest, CompactionFilterWithGetSv) {
|
||||
db->Flush(FlushOptions());
|
||||
|
||||
// Compact all L0 files using CompactFiles
|
||||
rocksdb::ColumnFamilyMetaData meta;
|
||||
ROCKSDB_NAMESPACE::ColumnFamilyMetaData meta;
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
for (auto& file : meta.levels[0].files) {
|
||||
std::string fname = file.db_path + "/" + file.name;
|
||||
ASSERT_OK(
|
||||
db->CompactFiles(rocksdb::CompactionOptions(), {fname}, 0));
|
||||
db->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), {fname}, 0));
|
||||
}
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ TEST_F(CompactFilesTest, SentinelCompressionType) {
|
||||
compaction_opts.compression = CompressionType::kDisableCompressionOption;
|
||||
ASSERT_OK(db->CompactFiles(compaction_opts, l0_files, 1));
|
||||
|
||||
rocksdb::TablePropertiesCollection all_tables_props;
|
||||
ROCKSDB_NAMESPACE::TablePropertiesCollection all_tables_props;
|
||||
ASSERT_OK(db->GetPropertiesOfAllTables(&all_tables_props));
|
||||
for (const auto& name_and_table_props : all_tables_props) {
|
||||
ASSERT_EQ(CompressionTypeToString(CompressionType::kZlibCompression),
|
||||
@@ -387,7 +387,7 @@ TEST_F(CompactFilesTest, GetCompactionJobInfo) {
|
||||
auto l0_files_1 = collector->GetFlushedFiles();
|
||||
CompactionOptions co;
|
||||
co.compression = CompressionType::kLZ4Compression;
|
||||
CompactionJobInfo compaction_job_info;
|
||||
CompactionJobInfo compaction_job_info{};
|
||||
ASSERT_OK(
|
||||
db->CompactFiles(co, l0_files_1, 0, -1, nullptr, &compaction_job_info));
|
||||
ASSERT_EQ(compaction_job_info.base_input_level, 0);
|
||||
@@ -402,7 +402,7 @@ TEST_F(CompactFilesTest, GetCompactionJobInfo) {
|
||||
delete db;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "db/version_set.h"
|
||||
#include "table/get_context.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
extern void MarkKeyMayExist(void* arg);
|
||||
extern bool SaveValue(void* arg, const ParsedInternalKey& parsed_key,
|
||||
@@ -37,7 +37,7 @@ Status CompactedDBImpl::Get(const ReadOptions& options, ColumnFamilyHandle*,
|
||||
const Slice& key, PinnableSlice* value) {
|
||||
GetContext get_context(user_comparator_, nullptr, nullptr, nullptr,
|
||||
GetContext::kNotFound, key, value, nullptr, nullptr,
|
||||
true, nullptr, nullptr);
|
||||
nullptr, true, nullptr, nullptr);
|
||||
LookupKey lkey(key, kMaxSequenceNumber);
|
||||
files_.files[FindFile(key)].fd.table_reader->Get(options, lkey.internal_key(),
|
||||
&get_context, nullptr);
|
||||
@@ -70,7 +70,7 @@ std::vector<Status> CompactedDBImpl::MultiGet(const ReadOptions& options,
|
||||
std::string& value = (*values)[idx];
|
||||
GetContext get_context(user_comparator_, nullptr, nullptr, nullptr,
|
||||
GetContext::kNotFound, keys[idx], &pinnable_val,
|
||||
nullptr, nullptr, true, nullptr, nullptr);
|
||||
nullptr, nullptr, nullptr, true, nullptr, nullptr);
|
||||
LookupKey lkey(keys[idx], kMaxSequenceNumber);
|
||||
r->Get(options, lkey.internal_key(), &get_context, nullptr);
|
||||
value.assign(pinnable_val.data(), pinnable_val.size());
|
||||
@@ -156,5 +156,5 @@ Status CompactedDBImpl::Open(const Options& options,
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // ROCKSDB_LITE
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <vector>
|
||||
#include "db/db_impl/db_impl.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class CompactedDBImpl : public DBImpl {
|
||||
public:
|
||||
@@ -109,5 +109,5 @@ class CompactedDBImpl : public DBImpl {
|
||||
const Comparator* user_comparator_;
|
||||
LevelFilesBrief files_;
|
||||
};
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // ROCKSDB_LITE
|
||||
+13
-14
@@ -16,7 +16,7 @@
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
const uint64_t kRangeTombstoneSentinel =
|
||||
PackSequenceAndType(kMaxSequenceNumber, kTypeRangeDeletion);
|
||||
@@ -275,9 +275,7 @@ Compaction::~Compaction() {
|
||||
input_version_->Unref();
|
||||
}
|
||||
if (cfd_ != nullptr) {
|
||||
if (cfd_->Unref()) {
|
||||
delete cfd_;
|
||||
}
|
||||
cfd_->UnrefAndTryDelete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,21 +543,22 @@ bool Compaction::ShouldFormSubcompactions() const {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Compaction::MaxInputFileCreationTime() const {
|
||||
uint64_t max_creation_time = 0;
|
||||
for (const auto& file : inputs_[0].files) {
|
||||
if (file->fd.table_reader != nullptr &&
|
||||
file->fd.table_reader->GetTableProperties() != nullptr) {
|
||||
uint64_t creation_time =
|
||||
file->fd.table_reader->GetTableProperties()->creation_time;
|
||||
max_creation_time = std::max(max_creation_time, creation_time);
|
||||
uint64_t Compaction::MinInputFileOldestAncesterTime() const {
|
||||
uint64_t min_oldest_ancester_time = port::kMaxUint64;
|
||||
for (const auto& level_files : inputs_) {
|
||||
for (const auto& file : level_files.files) {
|
||||
uint64_t oldest_ancester_time = file->TryGetOldestAncesterTime();
|
||||
if (oldest_ancester_time != 0) {
|
||||
min_oldest_ancester_time =
|
||||
std::min(min_oldest_ancester_time, oldest_ancester_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
return max_creation_time;
|
||||
return min_oldest_ancester_time;
|
||||
}
|
||||
|
||||
int Compaction::GetInputBaseLevel() const {
|
||||
return input_vstorage_->base_level();
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "options/cf_options.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
// The file contains class Compaction, as well as some helper functions
|
||||
// and data structures used by the class.
|
||||
|
||||
@@ -291,7 +291,7 @@ class Compaction {
|
||||
|
||||
uint32_t max_subcompactions() const { return max_subcompactions_; }
|
||||
|
||||
uint64_t MaxInputFileCreationTime() const;
|
||||
uint64_t MinInputFileOldestAncesterTime() const;
|
||||
|
||||
private:
|
||||
// mark (or clear) all files that are being compacted
|
||||
@@ -381,4 +381,4 @@ class Compaction {
|
||||
// Return sum of sizes of all files in `files`.
|
||||
extern uint64_t TotalFileSize(const std::vector<FileMetaData*>& files);
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
struct CompactionIterationStats {
|
||||
// Compaction statistics
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
#include "db/compaction/compaction_iterator.h"
|
||||
#include "db/snapshot_checker.h"
|
||||
#include "port/likely.h"
|
||||
@@ -26,7 +28,7 @@
|
||||
((seq) <= earliest_snapshot_ && \
|
||||
(snapshot_checker_ == nullptr || LIKELY(IsInEarliestSnapshot(seq))))
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
CompactionIterator::CompactionIterator(
|
||||
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
|
||||
@@ -38,7 +40,8 @@ CompactionIterator::CompactionIterator(
|
||||
const CompactionFilter* compaction_filter,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum,
|
||||
const std::atomic<bool>* manual_compaction_paused)
|
||||
const std::atomic<bool>* manual_compaction_paused,
|
||||
const std::shared_ptr<Logger> info_log)
|
||||
: CompactionIterator(
|
||||
input, cmp, merge_helper, last_sequence, snapshots,
|
||||
earliest_write_conflict_snapshot, snapshot_checker, env,
|
||||
@@ -46,7 +49,7 @@ CompactionIterator::CompactionIterator(
|
||||
std::unique_ptr<CompactionProxy>(
|
||||
compaction ? new CompactionProxy(compaction) : nullptr),
|
||||
compaction_filter, shutting_down, preserve_deletes_seqnum,
|
||||
manual_compaction_paused) {}
|
||||
manual_compaction_paused, info_log) {}
|
||||
|
||||
CompactionIterator::CompactionIterator(
|
||||
InternalIterator* input, const Comparator* cmp, MergeHelper* merge_helper,
|
||||
@@ -59,7 +62,8 @@ CompactionIterator::CompactionIterator(
|
||||
const CompactionFilter* compaction_filter,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum,
|
||||
const std::atomic<bool>* manual_compaction_paused)
|
||||
const std::atomic<bool>* manual_compaction_paused,
|
||||
const std::shared_ptr<Logger> info_log)
|
||||
: input_(input),
|
||||
cmp_(cmp),
|
||||
merge_helper_(merge_helper),
|
||||
@@ -78,7 +82,8 @@ CompactionIterator::CompactionIterator(
|
||||
current_user_key_sequence_(0),
|
||||
current_user_key_snapshot_(0),
|
||||
merge_out_iter_(merge_helper_),
|
||||
current_key_committed_(false) {
|
||||
current_key_committed_(false),
|
||||
info_log_(info_log) {
|
||||
assert(compaction_filter_ == nullptr || compaction_ != nullptr);
|
||||
assert(snapshots_ != nullptr);
|
||||
bottommost_level_ =
|
||||
@@ -142,6 +147,11 @@ void CompactionIterator::Next() {
|
||||
// MergeUntil stops when it encounters a corrupt key and does not
|
||||
// include them in the result, so we expect the keys here to be valid.
|
||||
assert(valid_key);
|
||||
if (!valid_key) {
|
||||
ROCKS_LOG_FATAL(info_log_, "Invalid key (%s) in compaction",
|
||||
key_.ToString(true).c_str());
|
||||
}
|
||||
|
||||
// Keep current_key_ in sync.
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
key_ = current_key_.GetInternalKey();
|
||||
@@ -338,7 +348,18 @@ void CompactionIterator::NextFromInput() {
|
||||
// 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) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"Unexpected key type %d for compaction output",
|
||||
ikey_.type);
|
||||
}
|
||||
assert(current_user_key_snapshot_ == last_snapshot);
|
||||
if (current_user_key_snapshot_ != last_snapshot) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"current_user_key_snapshot_ (%" PRIu64
|
||||
") != last_snapshot (%" PRIu64 ")",
|
||||
current_user_key_snapshot_, last_snapshot);
|
||||
}
|
||||
|
||||
value_.clear();
|
||||
valid_ = true;
|
||||
@@ -480,6 +501,12 @@ void CompactionIterator::NextFromInput() {
|
||||
// checking since there has already been a record returned for this key
|
||||
// in this snapshot.
|
||||
assert(last_sequence >= current_user_key_sequence_);
|
||||
if (last_sequence < current_user_key_sequence_) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"last_sequence (%" PRIu64
|
||||
") < current_user_key_sequence_ (%" PRIu64 ")",
|
||||
last_sequence, current_user_key_sequence_);
|
||||
}
|
||||
|
||||
++iter_stats_.num_record_drop_hidden; // (A)
|
||||
input_->Next();
|
||||
@@ -563,6 +590,10 @@ void CompactionIterator::NextFromInput() {
|
||||
// MergeUntil stops when it encounters a corrupt key and does not
|
||||
// include them in the result, so we expect the keys here to valid.
|
||||
assert(valid_key);
|
||||
if (!valid_key) {
|
||||
ROCKS_LOG_FATAL(info_log_, "Invalid key (%s) in compaction",
|
||||
key_.ToString(true).c_str());
|
||||
}
|
||||
// Keep current_key_ in sync.
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
key_ = current_key_.GetInternalKey();
|
||||
@@ -608,29 +639,58 @@ void CompactionIterator::NextFromInput() {
|
||||
}
|
||||
|
||||
void CompactionIterator::PrepareOutput() {
|
||||
// Zeroing out the sequence number leads to better compression.
|
||||
// If this is the bottommost level (no files in lower levels)
|
||||
// and the earliest snapshot is larger than this seqno
|
||||
// and the userkey differs from the last userkey in compaction
|
||||
// then we can squash the seqno to zero.
|
||||
//
|
||||
// This is safe for TransactionDB write-conflict checking since transactions
|
||||
// only care about sequence number larger than any active snapshots.
|
||||
//
|
||||
// Can we do the same for levels above bottom level as long as
|
||||
// KeyNotExistsBeyondOutputLevel() return true?
|
||||
if ((compaction_ != nullptr && !compaction_->allow_ingest_behind()) &&
|
||||
ikeyNotNeededForIncrementalSnapshot() && bottommost_level_ && valid_ &&
|
||||
IN_EARLIEST_SNAPSHOT(ikey_.sequence) && ikey_.type != kTypeMerge) {
|
||||
assert(ikey_.type != kTypeDeletion && ikey_.type != kTypeSingleDeletion);
|
||||
ikey_.sequence = 0;
|
||||
current_key_.UpdateInternalKey(0, ikey_.type);
|
||||
if (valid_) {
|
||||
if (compaction_filter_ && ikey_.type == kTypeBlobIndex) {
|
||||
const auto blob_decision = compaction_filter_->PrepareBlobOutput(
|
||||
user_key(), value_, &compaction_filter_value_);
|
||||
|
||||
if (blob_decision == CompactionFilter::BlobDecision::kCorruption) {
|
||||
status_ = Status::Corruption(
|
||||
"Corrupted blob reference encountered during GC");
|
||||
valid_ = false;
|
||||
} else if (blob_decision == CompactionFilter::BlobDecision::kIOError) {
|
||||
status_ = Status::IOError("Could not relocate blob during GC");
|
||||
valid_ = false;
|
||||
} else if (blob_decision ==
|
||||
CompactionFilter::BlobDecision::kChangeValue) {
|
||||
value_ = compaction_filter_value_;
|
||||
}
|
||||
}
|
||||
|
||||
// Zeroing out the sequence number leads to better compression.
|
||||
// If this is the bottommost level (no files in lower levels)
|
||||
// and the earliest snapshot is larger than this seqno
|
||||
// and the userkey differs from the last userkey in compaction
|
||||
// then we can squash the seqno to zero.
|
||||
//
|
||||
// This is safe for TransactionDB write-conflict checking since transactions
|
||||
// only care about sequence number larger than any active snapshots.
|
||||
//
|
||||
// Can we do the same for levels above bottom level as long as
|
||||
// KeyNotExistsBeyondOutputLevel() return true?
|
||||
if (valid_ && compaction_ != nullptr &&
|
||||
!compaction_->allow_ingest_behind() &&
|
||||
ikeyNotNeededForIncrementalSnapshot() && bottommost_level_ &&
|
||||
IN_EARLIEST_SNAPSHOT(ikey_.sequence) && ikey_.type != kTypeMerge) {
|
||||
assert(ikey_.type != kTypeDeletion && ikey_.type != kTypeSingleDeletion);
|
||||
if (ikey_.type == kTypeDeletion || ikey_.type == kTypeSingleDeletion) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"Unexpected key type %d for seq-zero optimization",
|
||||
ikey_.type);
|
||||
}
|
||||
ikey_.sequence = 0;
|
||||
current_key_.UpdateInternalKey(0, ikey_.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline SequenceNumber CompactionIterator::findEarliestVisibleSnapshot(
|
||||
SequenceNumber in, SequenceNumber* prev_snapshot) {
|
||||
assert(snapshots_->size());
|
||||
if (snapshots_->size() == 0) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"No snapshot left in findEarliestVisibleSnapshot");
|
||||
}
|
||||
auto snapshots_iter = std::lower_bound(
|
||||
snapshots_->begin(), snapshots_->end(), in);
|
||||
if (snapshots_iter == snapshots_->begin()) {
|
||||
@@ -638,6 +698,10 @@ inline SequenceNumber CompactionIterator::findEarliestVisibleSnapshot(
|
||||
} else {
|
||||
*prev_snapshot = *std::prev(snapshots_iter);
|
||||
assert(*prev_snapshot < in);
|
||||
if (*prev_snapshot >= in) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"*prev_snapshot >= in in findEarliestVisibleSnapshot");
|
||||
}
|
||||
}
|
||||
if (snapshot_checker_ == nullptr) {
|
||||
return snapshots_iter != snapshots_->end()
|
||||
@@ -647,6 +711,9 @@ inline SequenceNumber CompactionIterator::findEarliestVisibleSnapshot(
|
||||
for (; snapshots_iter != snapshots_->end(); ++snapshots_iter) {
|
||||
auto cur = *snapshots_iter;
|
||||
assert(in <= cur);
|
||||
if (in > cur) {
|
||||
ROCKS_LOG_FATAL(info_log_, "in > cur in findEarliestVisibleSnapshot");
|
||||
}
|
||||
// Skip if cur is in released_snapshots.
|
||||
if (has_released_snapshot && released_snapshots_.count(cur) > 0) {
|
||||
continue;
|
||||
@@ -671,9 +738,14 @@ inline bool CompactionIterator::ikeyNotNeededForIncrementalSnapshot() {
|
||||
|
||||
bool CompactionIterator::IsInEarliestSnapshot(SequenceNumber sequence) {
|
||||
assert(snapshot_checker_ != nullptr);
|
||||
assert(earliest_snapshot_ == kMaxSequenceNumber ||
|
||||
(earliest_snapshot_iter_ != snapshots_->end() &&
|
||||
*earliest_snapshot_iter_ == earliest_snapshot_));
|
||||
bool pre_condition = (earliest_snapshot_ == kMaxSequenceNumber ||
|
||||
(earliest_snapshot_iter_ != snapshots_->end() &&
|
||||
*earliest_snapshot_iter_ == earliest_snapshot_));
|
||||
assert(pre_condition);
|
||||
if (!pre_condition) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"Pre-Condition is not hold in IsInEarliestSnapshot");
|
||||
}
|
||||
auto in_snapshot =
|
||||
snapshot_checker_->CheckInSnapshot(sequence, earliest_snapshot_);
|
||||
while (UNLIKELY(in_snapshot == SnapshotCheckerResult::kSnapshotReleased)) {
|
||||
@@ -692,7 +764,11 @@ bool CompactionIterator::IsInEarliestSnapshot(SequenceNumber sequence) {
|
||||
snapshot_checker_->CheckInSnapshot(sequence, earliest_snapshot_);
|
||||
}
|
||||
assert(in_snapshot != SnapshotCheckerResult::kSnapshotReleased);
|
||||
if (in_snapshot == SnapshotCheckerResult::kSnapshotReleased) {
|
||||
ROCKS_LOG_FATAL(info_log_,
|
||||
"Unexpected released snapshot in IsInEarliestSnapshot");
|
||||
}
|
||||
return in_snapshot == SnapshotCheckerResult::kInSnapshot;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "options/cf_options.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class CompactionIterator {
|
||||
public:
|
||||
@@ -70,7 +70,8 @@ class CompactionIterator {
|
||||
const CompactionFilter* compaction_filter = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr,
|
||||
const SequenceNumber preserve_deletes_seqnum = 0,
|
||||
const std::atomic<bool>* manual_compaction_paused = nullptr);
|
||||
const std::atomic<bool>* manual_compaction_paused = nullptr,
|
||||
const std::shared_ptr<Logger> info_log = nullptr);
|
||||
|
||||
// Constructor with custom CompactionProxy, used for tests.
|
||||
CompactionIterator(
|
||||
@@ -84,7 +85,8 @@ class CompactionIterator {
|
||||
const CompactionFilter* compaction_filter = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr,
|
||||
const SequenceNumber preserve_deletes_seqnum = 0,
|
||||
const std::atomic<bool>* manual_compaction_paused = nullptr);
|
||||
const std::atomic<bool>* manual_compaction_paused = nullptr,
|
||||
const std::shared_ptr<Logger> info_log = nullptr);
|
||||
|
||||
~CompactionIterator();
|
||||
|
||||
@@ -222,6 +224,7 @@ class CompactionIterator {
|
||||
// Used to avoid purging uncommitted values. The application can specify
|
||||
// uncommitted values by providing a SnapshotChecker object.
|
||||
bool current_key_committed_;
|
||||
std::shared_ptr<Logger> info_log_;
|
||||
|
||||
bool IsShuttingDown() {
|
||||
// This is a best-effort facility, so memory_order_relaxed is sufficient.
|
||||
@@ -234,4 +237,4 @@ class CompactionIterator {
|
||||
manual_compaction_paused_->load(std::memory_order_relaxed);
|
||||
}
|
||||
};
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Expects no merging attempts.
|
||||
class NoMergingMergeOp : public MergeOperator {
|
||||
@@ -184,7 +184,7 @@ class TestSnapshotChecker : public SnapshotChecker {
|
||||
public:
|
||||
explicit TestSnapshotChecker(
|
||||
SequenceNumber last_committed_sequence,
|
||||
const std::unordered_map<SequenceNumber, SequenceNumber>& snapshots = {})
|
||||
const std::unordered_map<SequenceNumber, SequenceNumber>& snapshots = {{}})
|
||||
: last_committed_sequence_(last_committed_sequence),
|
||||
snapshots_(snapshots) {}
|
||||
|
||||
@@ -494,7 +494,7 @@ TEST_P(CompactionIteratorTest, ShuttingDownInFilter) {
|
||||
compaction_proxy_->key_not_exists_beyond_output_level = true;
|
||||
|
||||
std::atomic<bool> seek_done{false};
|
||||
rocksdb::port::Thread compaction_thread([&] {
|
||||
ROCKSDB_NAMESPACE::port::Thread compaction_thread([&] {
|
||||
c_iter_->SeekToFirst();
|
||||
EXPECT_FALSE(c_iter_->Valid());
|
||||
EXPECT_TRUE(c_iter_->status().IsShutdownInProgress());
|
||||
@@ -531,7 +531,7 @@ TEST_P(CompactionIteratorTest, ShuttingDownInMerge) {
|
||||
compaction_proxy_->key_not_exists_beyond_output_level = true;
|
||||
|
||||
std::atomic<bool> seek_done{false};
|
||||
rocksdb::port::Thread compaction_thread([&] {
|
||||
ROCKSDB_NAMESPACE::port::Thread compaction_thread([&] {
|
||||
c_iter_->SeekToFirst();
|
||||
ASSERT_FALSE(c_iter_->Valid());
|
||||
ASSERT_TRUE(c_iter_->status().IsShutdownInProgress());
|
||||
@@ -968,7 +968,7 @@ TEST_F(CompactionIteratorWithSnapshotCheckerTest, CompactionFilter_FullMerge) {
|
||||
compaction_filter.get());
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
const char* GetCompactionReasonString(CompactionReason compaction_reason) {
|
||||
switch (compaction_reason) {
|
||||
@@ -144,7 +144,6 @@ struct CompactionJob::SubcompactionState {
|
||||
|
||||
// State during the subcompaction
|
||||
uint64_t total_bytes;
|
||||
uint64_t num_input_records;
|
||||
uint64_t num_output_records;
|
||||
CompactionJobStats compaction_job_stats;
|
||||
uint64_t approx_size;
|
||||
@@ -165,7 +164,6 @@ struct CompactionJob::SubcompactionState {
|
||||
builder(nullptr),
|
||||
current_output_file_size(0),
|
||||
total_bytes(0),
|
||||
num_input_records(0),
|
||||
num_output_records(0),
|
||||
approx_size(size),
|
||||
grandparent_index(0),
|
||||
@@ -186,7 +184,6 @@ struct CompactionJob::SubcompactionState {
|
||||
builder = std::move(o.builder);
|
||||
current_output_file_size = std::move(o.current_output_file_size);
|
||||
total_bytes = std::move(o.total_bytes);
|
||||
num_input_records = std::move(o.num_input_records);
|
||||
num_output_records = std::move(o.num_output_records);
|
||||
compaction_job_stats = std::move(o.compaction_job_stats);
|
||||
approx_size = std::move(o.approx_size);
|
||||
@@ -245,13 +242,11 @@ struct CompactionJob::CompactionState {
|
||||
Status status;
|
||||
|
||||
uint64_t total_bytes;
|
||||
uint64_t num_input_records;
|
||||
uint64_t num_output_records;
|
||||
|
||||
explicit CompactionState(Compaction* c)
|
||||
: compaction(c),
|
||||
total_bytes(0),
|
||||
num_input_records(0),
|
||||
num_output_records(0) {}
|
||||
|
||||
size_t NumOutputFiles() {
|
||||
@@ -289,7 +284,6 @@ struct CompactionJob::CompactionState {
|
||||
void CompactionJob::AggregateStatistics() {
|
||||
for (SubcompactionState& sc : compact_->sub_compact_states) {
|
||||
compact_->total_bytes += sc.total_bytes;
|
||||
compact_->num_input_records += sc.num_input_records;
|
||||
compact_->num_output_records += sc.num_output_records;
|
||||
}
|
||||
if (compaction_job_stats_) {
|
||||
@@ -301,10 +295,10 @@ void CompactionJob::AggregateStatistics() {
|
||||
|
||||
CompactionJob::CompactionJob(
|
||||
int job_id, Compaction* compaction, const ImmutableDBOptions& db_options,
|
||||
const EnvOptions env_options, VersionSet* versions,
|
||||
const FileOptions& file_options, VersionSet* versions,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum, LogBuffer* log_buffer,
|
||||
Directory* db_directory, Directory* output_directory, Statistics* stats,
|
||||
FSDirectory* db_directory, FSDirectory* output_directory, Statistics* stats,
|
||||
InstrumentedMutex* db_mutex, ErrorHandler* db_error_handler,
|
||||
std::vector<SequenceNumber> existing_snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
@@ -318,10 +312,11 @@ CompactionJob::CompactionJob(
|
||||
compaction_stats_(compaction->compaction_reason(), 1),
|
||||
dbname_(dbname),
|
||||
db_options_(db_options),
|
||||
env_options_(env_options),
|
||||
file_options_(file_options),
|
||||
env_(db_options.env),
|
||||
env_options_for_read_(
|
||||
env_->OptimizeForCompactionTableRead(env_options, db_options_)),
|
||||
fs_(db_options.fs.get()),
|
||||
file_options_for_read_(
|
||||
fs_->OptimizeForCompactionTableRead(file_options, db_options_)),
|
||||
versions_(versions),
|
||||
shutting_down_(shutting_down),
|
||||
manual_compaction_paused_(manual_compaction_paused),
|
||||
@@ -619,7 +614,7 @@ Status CompactionJob::Run() {
|
||||
}
|
||||
|
||||
if (status.ok() && output_directory_) {
|
||||
status = output_directory_->Fsync();
|
||||
status = output_directory_->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
|
||||
if (status.ok()) {
|
||||
@@ -647,7 +642,7 @@ Status CompactionJob::Run() {
|
||||
// we will regard this verification as user reads since the goal is
|
||||
// to cache it here for further user reads
|
||||
InternalIterator* iter = cfd->table_cache()->NewIterator(
|
||||
ReadOptions(), env_options_, cfd->internal_comparator(),
|
||||
ReadOptions(), file_options_, cfd->internal_comparator(),
|
||||
*files_meta[file_idx], /*range_del_agg=*/nullptr, prefix_extractor,
|
||||
/*table_reader_ptr=*/nullptr,
|
||||
cfd->internal_stats()->GetFileReadHist(
|
||||
@@ -769,12 +764,12 @@ Status CompactionJob::Install(const MutableCFOptions& mutable_cf_options) {
|
||||
auto stream = event_logger_->LogToBuffer(log_buffer_);
|
||||
stream << "job" << job_id_ << "event"
|
||||
<< "compaction_finished"
|
||||
<< "compaction_time_micros" << compaction_stats_.micros
|
||||
<< "compaction_time_cpu_micros" << compaction_stats_.cpu_micros
|
||||
<< "output_level" << compact_->compaction->output_level()
|
||||
<< "num_output_files" << compact_->NumOutputFiles()
|
||||
<< "total_output_size" << compact_->total_bytes << "num_input_records"
|
||||
<< compact_->num_input_records << "num_output_records"
|
||||
<< "compaction_time_micros" << stats.micros
|
||||
<< "compaction_time_cpu_micros" << stats.cpu_micros << "output_level"
|
||||
<< compact_->compaction->output_level() << "num_output_files"
|
||||
<< compact_->NumOutputFiles() << "total_output_size"
|
||||
<< compact_->total_bytes << "num_input_records"
|
||||
<< stats.num_input_records << "num_output_records"
|
||||
<< compact_->num_output_records << "num_subcompactions"
|
||||
<< compact_->sub_compact_states.size() << "output_compression"
|
||||
<< CompressionTypeToString(compact_->compaction->output_compression());
|
||||
@@ -836,7 +831,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
// Although the v2 aggregator is what the level iterator(s) know about,
|
||||
// the AddTombstones calls will be propagated down to the v1 aggregator.
|
||||
std::unique_ptr<InternalIterator> input(versions_->MakeInputIterator(
|
||||
sub_compact->compaction, &range_del_agg, env_options_for_read_));
|
||||
sub_compact->compaction, &range_del_agg, file_options_for_read_));
|
||||
|
||||
AutoThreadOperationStageUpdater stage_updater(
|
||||
ThreadStatus::STAGE_COMPACTION_PROCESS_KV);
|
||||
@@ -891,7 +886,8 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
&existing_snapshots_, earliest_write_conflict_snapshot_,
|
||||
snapshot_checker_, env_, ShouldReportDetailedTime(env_, stats_), false,
|
||||
&range_del_agg, sub_compact->compaction, compaction_filter,
|
||||
shutting_down_, preserve_deletes_seqnum_, manual_compaction_paused_));
|
||||
shutting_down_, preserve_deletes_seqnum_, manual_compaction_paused_,
|
||||
db_options_.info_log));
|
||||
auto c_iter = sub_compact->c_iter.get();
|
||||
c_iter->SeekToFirst();
|
||||
if (c_iter->Valid() && sub_compact->compaction->output_level() != 0) {
|
||||
@@ -989,7 +985,6 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
}
|
||||
}
|
||||
|
||||
sub_compact->num_input_records = c_iter_stats.num_input_records;
|
||||
sub_compact->compaction_job_stats.num_input_deletion_records =
|
||||
c_iter_stats.num_input_deletion_records;
|
||||
sub_compact->compaction_job_stats.num_corrupt_keys =
|
||||
@@ -1301,6 +1296,11 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
}
|
||||
const uint64_t current_bytes = sub_compact->builder->FileSize();
|
||||
if (s.ok()) {
|
||||
// Add the checksum information to file metadata.
|
||||
meta->file_checksum = sub_compact->builder->GetFileChecksum();
|
||||
meta->file_checksum_func_name =
|
||||
sub_compact->builder->GetFileChecksumFuncName();
|
||||
|
||||
meta->fd.file_size = current_bytes;
|
||||
}
|
||||
sub_compact->current_output()->finished = true;
|
||||
@@ -1456,13 +1456,13 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
TableFileCreationReason::kCompaction);
|
||||
#endif // !ROCKSDB_LITE
|
||||
// Make the output file
|
||||
std::unique_ptr<WritableFile> writable_file;
|
||||
std::unique_ptr<FSWritableFile> writable_file;
|
||||
#ifndef NDEBUG
|
||||
bool syncpoint_arg = env_options_.use_direct_writes;
|
||||
bool syncpoint_arg = file_options_.use_direct_writes;
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionJob::OpenCompactionOutputFile",
|
||||
&syncpoint_arg);
|
||||
#endif
|
||||
Status s = NewWritableFile(env_, fname, &writable_file, env_options_);
|
||||
Status s = NewWritableFile(fs_, fname, &writable_file, file_options_);
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_ERROR(
|
||||
db_options_.info_log,
|
||||
@@ -1478,28 +1478,7 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
return s;
|
||||
}
|
||||
|
||||
SubcompactionState::Output out;
|
||||
out.meta.fd =
|
||||
FileDescriptor(file_number, sub_compact->compaction->output_path_id(), 0);
|
||||
out.finished = false;
|
||||
|
||||
sub_compact->outputs.push_back(out);
|
||||
writable_file->SetIOPriority(Env::IO_LOW);
|
||||
writable_file->SetWriteLifeTimeHint(write_hint_);
|
||||
writable_file->SetPreallocationBlockSize(static_cast<size_t>(
|
||||
sub_compact->compaction->OutputFilePreallocationSize()));
|
||||
const auto& listeners =
|
||||
sub_compact->compaction->immutable_cf_options()->listeners;
|
||||
sub_compact->outfile.reset(
|
||||
new WritableFileWriter(std::move(writable_file), fname, env_options_,
|
||||
env_, db_options_.statistics.get(), listeners));
|
||||
|
||||
// If the Column family flag is to only optimize filters for hits,
|
||||
// we can skip creating filters if this is the bottommost_level where
|
||||
// data is going to be found
|
||||
bool skip_filters =
|
||||
cfd->ioptions()->optimize_filters_for_hits && bottommost_level_;
|
||||
|
||||
// Try to figure out the output file's oldest ancester time.
|
||||
int64_t temp_current_time = 0;
|
||||
auto get_time_status = env_->GetCurrentTime(&temp_current_time);
|
||||
// Safe to proceed even if GetCurrentTime fails. So, log and proceed.
|
||||
@@ -1509,13 +1488,40 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
get_time_status.ToString().c_str());
|
||||
}
|
||||
uint64_t current_time = static_cast<uint64_t>(temp_current_time);
|
||||
|
||||
uint64_t latest_key_time =
|
||||
sub_compact->compaction->MaxInputFileCreationTime();
|
||||
if (latest_key_time == 0) {
|
||||
latest_key_time = current_time;
|
||||
uint64_t oldest_ancester_time =
|
||||
sub_compact->compaction->MinInputFileOldestAncesterTime();
|
||||
if (oldest_ancester_time == port::kMaxUint64) {
|
||||
oldest_ancester_time = current_time;
|
||||
}
|
||||
|
||||
// Initialize a SubcompactionState::Output and add it to sub_compact->outputs
|
||||
{
|
||||
SubcompactionState::Output out;
|
||||
out.meta.fd = FileDescriptor(file_number,
|
||||
sub_compact->compaction->output_path_id(), 0);
|
||||
out.meta.oldest_ancester_time = oldest_ancester_time;
|
||||
out.meta.file_creation_time = current_time;
|
||||
out.finished = false;
|
||||
sub_compact->outputs.push_back(out);
|
||||
}
|
||||
|
||||
writable_file->SetIOPriority(Env::IOPriority::IO_LOW);
|
||||
writable_file->SetWriteLifeTimeHint(write_hint_);
|
||||
writable_file->SetPreallocationBlockSize(static_cast<size_t>(
|
||||
sub_compact->compaction->OutputFilePreallocationSize()));
|
||||
const auto& listeners =
|
||||
sub_compact->compaction->immutable_cf_options()->listeners;
|
||||
sub_compact->outfile.reset(
|
||||
new WritableFileWriter(std::move(writable_file), fname, file_options_,
|
||||
env_, db_options_.statistics.get(), listeners,
|
||||
db_options_.sst_file_checksum_func.get()));
|
||||
|
||||
// If the Column family flag is to only optimize filters for hits,
|
||||
// we can skip creating filters if this is the bottommost_level where
|
||||
// data is going to be found
|
||||
bool skip_filters =
|
||||
cfd->ioptions()->optimize_filters_for_hits && bottommost_level_;
|
||||
|
||||
sub_compact->builder.reset(NewTableBuilder(
|
||||
*cfd->ioptions(), *(sub_compact->compaction->mutable_cf_options()),
|
||||
cfd->internal_comparator(), cfd->int_tbl_prop_collector_factories(),
|
||||
@@ -1523,9 +1529,9 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
sub_compact->compaction->output_compression(),
|
||||
0 /*sample_for_compression */,
|
||||
sub_compact->compaction->output_compression_opts(),
|
||||
sub_compact->compaction->output_level(), skip_filters, latest_key_time,
|
||||
0 /* oldest_key_time */, sub_compact->compaction->max_output_file_size(),
|
||||
current_time));
|
||||
sub_compact->compaction->output_level(), skip_filters,
|
||||
oldest_ancester_time, 0 /* oldest_key_time */,
|
||||
sub_compact->compaction->max_output_file_size(), current_time));
|
||||
LogFlush(db_options_.info_log);
|
||||
return s;
|
||||
}
|
||||
@@ -1582,6 +1588,8 @@ void CompactionJob::UpdateCompactionStats() {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t num_output_records = 0;
|
||||
|
||||
for (const auto& sub_compact : compact_->sub_compact_states) {
|
||||
size_t num_output_files = sub_compact.outputs.size();
|
||||
if (sub_compact.builder != nullptr) {
|
||||
@@ -1591,13 +1599,16 @@ void CompactionJob::UpdateCompactionStats() {
|
||||
}
|
||||
compaction_stats_.num_output_files += static_cast<int>(num_output_files);
|
||||
|
||||
num_output_records += sub_compact.num_output_records;
|
||||
|
||||
for (const auto& out : sub_compact.outputs) {
|
||||
compaction_stats_.bytes_written += out.meta.fd.file_size;
|
||||
}
|
||||
if (sub_compact.num_input_records > sub_compact.num_output_records) {
|
||||
compaction_stats_.num_dropped_records +=
|
||||
sub_compact.num_input_records - sub_compact.num_output_records;
|
||||
}
|
||||
}
|
||||
|
||||
if (compaction_stats_.num_input_records > num_output_records) {
|
||||
compaction_stats_.num_dropped_records =
|
||||
compaction_stats_.num_input_records - num_output_records;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1625,7 +1636,7 @@ void CompactionJob::UpdateCompactionJobStats(
|
||||
// input information
|
||||
compaction_job_stats_->total_input_bytes =
|
||||
stats.bytes_read_non_output_levels + stats.bytes_read_output_level;
|
||||
compaction_job_stats_->num_input_records = compact_->num_input_records;
|
||||
compaction_job_stats_->num_input_records = stats.num_input_records;
|
||||
compaction_job_stats_->num_input_files =
|
||||
stats.num_input_files_in_non_output_levels +
|
||||
stats.num_input_files_in_output_level;
|
||||
@@ -1686,4 +1697,4 @@ void CompactionJob::LogCompaction() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -44,7 +44,7 @@
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/thread_local.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class Arena;
|
||||
class ErrorHandler;
|
||||
@@ -64,11 +64,11 @@ class CompactionJob {
|
||||
public:
|
||||
CompactionJob(int job_id, Compaction* compaction,
|
||||
const ImmutableDBOptions& db_options,
|
||||
const EnvOptions env_options, VersionSet* versions,
|
||||
const FileOptions& file_options, VersionSet* versions,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const SequenceNumber preserve_deletes_seqnum,
|
||||
LogBuffer* log_buffer, Directory* db_directory,
|
||||
Directory* output_directory, Statistics* stats,
|
||||
LogBuffer* log_buffer, FSDirectory* db_directory,
|
||||
FSDirectory* output_directory, Statistics* stats,
|
||||
InstrumentedMutex* db_mutex, ErrorHandler* db_error_handler,
|
||||
std::vector<SequenceNumber> existing_snapshots,
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
@@ -150,18 +150,19 @@ class CompactionJob {
|
||||
// DBImpl state
|
||||
const std::string& dbname_;
|
||||
const ImmutableDBOptions& db_options_;
|
||||
const EnvOptions env_options_;
|
||||
const FileOptions file_options_;
|
||||
|
||||
Env* env_;
|
||||
FileSystem* fs_;
|
||||
// env_option optimized for compaction table reads
|
||||
EnvOptions env_options_for_read_;
|
||||
FileOptions file_options_for_read_;
|
||||
VersionSet* versions_;
|
||||
const std::atomic<bool>* shutting_down_;
|
||||
const std::atomic<bool>* manual_compaction_paused_;
|
||||
const SequenceNumber preserve_deletes_seqnum_;
|
||||
LogBuffer* log_buffer_;
|
||||
Directory* db_directory_;
|
||||
Directory* output_directory_;
|
||||
FSDirectory* db_directory_;
|
||||
FSDirectory* output_directory_;
|
||||
Statistics* stats_;
|
||||
InstrumentedMutex* db_mutex_;
|
||||
ErrorHandler* db_error_handler_;
|
||||
@@ -194,4 +195,4 @@ class CompactionJob {
|
||||
Env::Priority thread_pri_;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
#if !defined(IOS_CROSS_COMPILE)
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
static std::string RandomString(Random* rnd, int len, double ratio) {
|
||||
std::string r;
|
||||
@@ -110,9 +110,9 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
}
|
||||
|
||||
~CompactionJobStatsTest() override {
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({});
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
Close();
|
||||
Options options;
|
||||
options.db_paths.emplace_back(dbname_, 0);
|
||||
@@ -801,7 +801,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
|
||||
stats_checker->set_verify_next_comp_io_stats(true);
|
||||
std::atomic<bool> first_prepare_write(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::Append:BeforePrepareWrite", [&](void* /*arg*/) {
|
||||
if (first_prepare_write.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
@@ -810,7 +810,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
});
|
||||
|
||||
std::atomic<bool> first_flush(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::Flush:BeforeAppend", [&](void* /*arg*/) {
|
||||
if (first_flush.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
@@ -819,7 +819,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
});
|
||||
|
||||
std::atomic<bool> first_sync(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::SyncInternal:0", [&](void* /*arg*/) {
|
||||
if (first_sync.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
@@ -828,14 +828,14 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
});
|
||||
|
||||
std::atomic<bool> first_range_sync(true);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::RangeSync:0", [&](void* /*arg*/) {
|
||||
if (first_range_sync.load()) {
|
||||
options.env->SleepForMicroseconds(3);
|
||||
first_range_sync.store(false);
|
||||
}
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Compact(1, smallest_key, largest_key);
|
||||
|
||||
@@ -844,7 +844,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
ASSERT_TRUE(!first_flush.load());
|
||||
ASSERT_TRUE(!first_sync.load());
|
||||
ASSERT_TRUE(!first_range_sync.load());
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
ASSERT_EQ(stats_checker->NumberOfUnverifiedStats(), 0U);
|
||||
}
|
||||
@@ -1019,10 +1019,10 @@ TEST_P(CompactionJobStatsTest, UniversalCompactionTest) {
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(CompactionJobStatsTest, CompactionJobStatsTest,
|
||||
::testing::Values(1, 4));
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "db/blob_index.h"
|
||||
#include "db/blob/blob_index.h"
|
||||
#include "db/column_family.h"
|
||||
#include "db/compaction/compaction_job.h"
|
||||
#include "db/db_impl/db_impl.h"
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -72,6 +72,7 @@ class CompactionJobTest : public testing::Test {
|
||||
public:
|
||||
CompactionJobTest()
|
||||
: env_(Env::Default()),
|
||||
fs_(std::make_shared<LegacyFileSystemWrapper>(env_)),
|
||||
dbname_(test::PerThreadDBPath("compaction_job_test")),
|
||||
db_options_(),
|
||||
mutable_cf_options_(cf_options_),
|
||||
@@ -86,6 +87,8 @@ class CompactionJobTest : public testing::Test {
|
||||
mock_table_factory_(new mock::MockTableFactory()),
|
||||
error_handler_(nullptr, db_options_, &mutex_) {
|
||||
EXPECT_OK(env_->CreateDirIfMissing(dbname_));
|
||||
db_options_.env = env_;
|
||||
db_options_.fs = fs_;
|
||||
db_options_.db_paths.emplace_back(dbname_,
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
@@ -183,7 +186,9 @@ class CompactionJobTest : public testing::Test {
|
||||
|
||||
VersionEdit edit;
|
||||
edit.AddFile(level, file_number, 0, 10, smallest_key, largest_key,
|
||||
smallest_seqno, largest_seqno, false, oldest_blob_file_number);
|
||||
smallest_seqno, largest_seqno, false, oldest_blob_file_number,
|
||||
kUnknownOldestAncesterTime, kUnknownFileCreationTime,
|
||||
kUnknownFileChecksum, kUnknownFileChecksumFuncName);
|
||||
|
||||
mutex_.Lock();
|
||||
versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(),
|
||||
@@ -266,8 +271,8 @@ class CompactionJobTest : public testing::Test {
|
||||
Status s = env_->NewWritableFile(
|
||||
manifest, &file, env_->OptimizeForManifestWrite(env_options_));
|
||||
ASSERT_OK(s);
|
||||
std::unique_ptr<WritableFileWriter> file_writer(
|
||||
new WritableFileWriter(std::move(file), manifest, env_options_));
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
NewLegacyWritableFileWrapper(std::move(file)), manifest, env_options_));
|
||||
{
|
||||
log::Writer log(std::move(file_writer), 0, false);
|
||||
std::string record;
|
||||
@@ -359,6 +364,7 @@ class CompactionJobTest : public testing::Test {
|
||||
}
|
||||
|
||||
Env* env_;
|
||||
std::shared_ptr<FileSystem> fs_;
|
||||
std::string dbname_;
|
||||
EnvOptions env_options_;
|
||||
ImmutableDBOptions db_options_;
|
||||
@@ -1057,7 +1063,7 @@ TEST_F(CompactionJobTest, OldestBlobFileNumber) {
|
||||
/* expected_oldest_blob_file_number */ 19);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "util/random.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
namespace {
|
||||
uint64_t TotalCompensatedFileSize(const std::vector<FileMetaData*>& files) {
|
||||
@@ -39,20 +39,41 @@ bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
|
||||
size_t min_files_to_compact,
|
||||
uint64_t max_compact_bytes_per_del_file,
|
||||
uint64_t max_compaction_bytes,
|
||||
CompactionInputFiles* comp_inputs) {
|
||||
size_t compact_bytes = static_cast<size_t>(level_files[0]->fd.file_size);
|
||||
uint64_t compensated_compact_bytes = level_files[0]->compensated_file_size;
|
||||
CompactionInputFiles* comp_inputs,
|
||||
SequenceNumber earliest_mem_seqno) {
|
||||
// Do not pick ingested file when there is at least one memtable not flushed
|
||||
// which of seqno is overlap with the sst.
|
||||
TEST_SYNC_POINT("FindIntraL0Compaction");
|
||||
size_t start = 0;
|
||||
for (; start < level_files.size(); start++) {
|
||||
if (level_files[start]->being_compacted) {
|
||||
return false;
|
||||
}
|
||||
// If there is no data in memtable, the earliest sequence number would the
|
||||
// largest sequence number in last memtable.
|
||||
// Because all files are sorted in descending order by largest_seqno, so we
|
||||
// only need to check the first one.
|
||||
if (level_files[start]->fd.largest_seqno <= earliest_mem_seqno) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start >= level_files.size()) {
|
||||
return false;
|
||||
}
|
||||
size_t compact_bytes = static_cast<size_t>(level_files[start]->fd.file_size);
|
||||
uint64_t compensated_compact_bytes =
|
||||
level_files[start]->compensated_file_size;
|
||||
size_t compact_bytes_per_del_file = port::kMaxSizet;
|
||||
// Compaction range will be [0, span_len).
|
||||
size_t span_len;
|
||||
// Compaction range will be [start, limit).
|
||||
size_t limit;
|
||||
// Pull in files until the amount of compaction work per deleted file begins
|
||||
// increasing or maximum total compaction size is reached.
|
||||
size_t new_compact_bytes_per_del_file = 0;
|
||||
for (span_len = 1; span_len < level_files.size(); ++span_len) {
|
||||
compact_bytes += static_cast<size_t>(level_files[span_len]->fd.file_size);
|
||||
compensated_compact_bytes += level_files[span_len]->compensated_file_size;
|
||||
new_compact_bytes_per_del_file = compact_bytes / span_len;
|
||||
if (level_files[span_len]->being_compacted ||
|
||||
for (limit = start + 1; limit < level_files.size(); ++limit) {
|
||||
compact_bytes += static_cast<size_t>(level_files[limit]->fd.file_size);
|
||||
compensated_compact_bytes += level_files[limit]->compensated_file_size;
|
||||
new_compact_bytes_per_del_file = compact_bytes / (limit - start);
|
||||
if (level_files[limit]->being_compacted ||
|
||||
new_compact_bytes_per_del_file > compact_bytes_per_del_file ||
|
||||
compensated_compact_bytes > max_compaction_bytes) {
|
||||
break;
|
||||
@@ -60,11 +81,11 @@ bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
|
||||
compact_bytes_per_del_file = new_compact_bytes_per_del_file;
|
||||
}
|
||||
|
||||
if (span_len >= min_files_to_compact &&
|
||||
if ((limit - start) >= min_files_to_compact &&
|
||||
compact_bytes_per_del_file < max_compact_bytes_per_del_file) {
|
||||
assert(comp_inputs != nullptr);
|
||||
comp_inputs->level = 0;
|
||||
for (size_t i = 0; i < span_len; ++i) {
|
||||
for (size_t i = start; i < limit; ++i) {
|
||||
comp_inputs->files.push_back(level_files[i]);
|
||||
}
|
||||
return true;
|
||||
@@ -1107,4 +1128,4 @@ bool CompactionPicker::GetOverlappingL0Files(
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// The file contains an abstract class CompactionPicker, and its two
|
||||
// sub-classes LevelCompactionPicker and NullCompactionPicker, as
|
||||
@@ -54,10 +54,10 @@ class CompactionPicker {
|
||||
// Returns nullptr if there is no compaction to be done.
|
||||
// Otherwise returns a pointer to a heap-allocated object that
|
||||
// describes the compaction. Caller should delete the result.
|
||||
virtual Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage,
|
||||
LogBuffer* log_buffer) = 0;
|
||||
virtual Compaction* PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
|
||||
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) = 0;
|
||||
|
||||
// Return a compaction object for compacting the range [begin,end] in
|
||||
// the specified level. Returns nullptr if there is nothing in that
|
||||
@@ -247,10 +247,11 @@ class NullCompactionPicker : public CompactionPicker {
|
||||
virtual ~NullCompactionPicker() {}
|
||||
|
||||
// Always return "nullptr"
|
||||
Compaction* PickCompaction(const std::string& /*cf_name*/,
|
||||
const MutableCFOptions& /*mutable_cf_options*/,
|
||||
VersionStorageInfo* /*vstorage*/,
|
||||
LogBuffer* /*log_buffer*/) override {
|
||||
Compaction* PickCompaction(
|
||||
const std::string& /*cf_name*/,
|
||||
const MutableCFOptions& /*mutable_cf_options*/,
|
||||
VersionStorageInfo* /*vstorage*/, LogBuffer* /* log_buffer */,
|
||||
SequenceNumber /* earliest_memtable_seqno */) override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -292,11 +293,11 @@ class NullCompactionPicker : public CompactionPicker {
|
||||
// files. Cannot be nullptr.
|
||||
//
|
||||
// @return true iff compaction was found.
|
||||
bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
|
||||
size_t min_files_to_compact,
|
||||
uint64_t max_compact_bytes_per_del_file,
|
||||
uint64_t max_compaction_bytes,
|
||||
CompactionInputFiles* comp_inputs);
|
||||
bool FindIntraL0Compaction(
|
||||
const std::vector<FileMetaData*>& level_files, size_t min_files_to_compact,
|
||||
uint64_t max_compact_bytes_per_del_file, uint64_t max_compaction_bytes,
|
||||
CompactionInputFiles* comp_inputs,
|
||||
SequenceNumber earliest_mem_seqno = kMaxSequenceNumber);
|
||||
|
||||
CompressionType GetCompressionType(const ImmutableCFOptions& ioptions,
|
||||
const VersionStorageInfo* vstorage,
|
||||
@@ -309,4 +310,4 @@ CompressionOptions GetCompressionOptions(const ImmutableCFOptions& ioptions,
|
||||
int level,
|
||||
const bool enable_compression = true);
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "logging/log_buffer.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
uint64_t GetTotalFilesSize(const std::vector<FileMetaData*>& files) {
|
||||
uint64_t total_size = 0;
|
||||
@@ -70,18 +70,14 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
// avoid underflow
|
||||
if (current_time > mutable_cf_options.ttl) {
|
||||
for (auto ritr = level_files.rbegin(); ritr != level_files.rend(); ++ritr) {
|
||||
auto f = *ritr;
|
||||
if (f->fd.table_reader != nullptr &&
|
||||
f->fd.table_reader->GetTableProperties() != nullptr) {
|
||||
auto creation_time =
|
||||
f->fd.table_reader->GetTableProperties()->creation_time;
|
||||
if (creation_time == 0 ||
|
||||
creation_time >= (current_time - mutable_cf_options.ttl)) {
|
||||
break;
|
||||
}
|
||||
total_size -= f->compensated_file_size;
|
||||
inputs[0].files.push_back(f);
|
||||
FileMetaData* f = *ritr;
|
||||
uint64_t creation_time = f->TryGetFileCreationTime();
|
||||
if (creation_time == kUnknownFileCreationTime ||
|
||||
creation_time >= (current_time - mutable_cf_options.ttl)) {
|
||||
break;
|
||||
}
|
||||
total_size -= f->compensated_file_size;
|
||||
inputs[0].files.push_back(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +96,7 @@ Compaction* FIFOCompactionPicker::PickTTLCompaction(
|
||||
"[%s] FIFO compaction: picking file %" PRIu64
|
||||
" with creation time %" PRIu64 " for deletion",
|
||||
cf_name.c_str(), f->fd.GetNumber(),
|
||||
f->fd.table_reader->GetTableProperties()->creation_time);
|
||||
f->TryGetFileCreationTime());
|
||||
}
|
||||
|
||||
Compaction* c = new Compaction(
|
||||
@@ -202,7 +198,8 @@ Compaction* FIFOCompactionPicker::PickSizeCompaction(
|
||||
|
||||
Compaction* FIFOCompactionPicker::PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer) {
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
|
||||
SequenceNumber /*earliest_memtable_seqno*/) {
|
||||
assert(vstorage->num_levels() == 1);
|
||||
|
||||
Compaction* c = nullptr;
|
||||
@@ -237,5 +234,5 @@ Compaction* FIFOCompactionPicker::CompactRange(
|
||||
return c;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // !ROCKSDB_LITE
|
||||
@@ -12,17 +12,17 @@
|
||||
|
||||
#include "db/compaction/compaction_picker.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class FIFOCompactionPicker : public CompactionPicker {
|
||||
public:
|
||||
FIFOCompactionPicker(const ImmutableCFOptions& ioptions,
|
||||
const InternalKeyComparator* icmp)
|
||||
: CompactionPicker(ioptions, icmp) {}
|
||||
|
||||
virtual Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* version,
|
||||
LogBuffer* log_buffer) override;
|
||||
virtual Compaction* PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* version, LogBuffer* log_buffer,
|
||||
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) override;
|
||||
|
||||
virtual Compaction* CompactRange(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
@@ -49,5 +49,5 @@ class FIFOCompactionPicker : public CompactionPicker {
|
||||
VersionStorageInfo* version,
|
||||
LogBuffer* log_buffer);
|
||||
};
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // !ROCKSDB_LITE
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "logging/log_buffer.h"
|
||||
#include "test_util/sync_point.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
bool LevelCompactionPicker::NeedsCompaction(
|
||||
const VersionStorageInfo* vstorage) const {
|
||||
@@ -45,12 +45,14 @@ class LevelCompactionBuilder {
|
||||
public:
|
||||
LevelCompactionBuilder(const std::string& cf_name,
|
||||
VersionStorageInfo* vstorage,
|
||||
SequenceNumber earliest_mem_seqno,
|
||||
CompactionPicker* compaction_picker,
|
||||
LogBuffer* log_buffer,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
const ImmutableCFOptions& ioptions)
|
||||
: cf_name_(cf_name),
|
||||
vstorage_(vstorage),
|
||||
earliest_mem_seqno_(earliest_mem_seqno),
|
||||
compaction_picker_(compaction_picker),
|
||||
log_buffer_(log_buffer),
|
||||
mutable_cf_options_(mutable_cf_options),
|
||||
@@ -97,6 +99,7 @@ class LevelCompactionBuilder {
|
||||
|
||||
const std::string& cf_name_;
|
||||
VersionStorageInfo* vstorage_;
|
||||
SequenceNumber earliest_mem_seqno_;
|
||||
CompactionPicker* compaction_picker_;
|
||||
LogBuffer* log_buffer_;
|
||||
int start_level_ = -1;
|
||||
@@ -537,17 +540,19 @@ bool LevelCompactionBuilder::PickIntraL0Compaction() {
|
||||
// resort to L0->L0 compaction yet.
|
||||
return false;
|
||||
}
|
||||
return FindIntraL0Compaction(
|
||||
level_files, kMinFilesForIntraL0Compaction, port::kMaxUint64,
|
||||
mutable_cf_options_.max_compaction_bytes, &start_level_inputs_);
|
||||
return FindIntraL0Compaction(level_files, kMinFilesForIntraL0Compaction,
|
||||
port::kMaxUint64,
|
||||
mutable_cf_options_.max_compaction_bytes,
|
||||
&start_level_inputs_, earliest_mem_seqno_);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Compaction* LevelCompactionPicker::PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer) {
|
||||
LevelCompactionBuilder builder(cf_name, vstorage, this, log_buffer,
|
||||
mutable_cf_options, ioptions_);
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
|
||||
SequenceNumber earliest_mem_seqno) {
|
||||
LevelCompactionBuilder builder(cf_name, vstorage, earliest_mem_seqno, this,
|
||||
log_buffer, mutable_cf_options, ioptions_);
|
||||
return builder.PickCompaction();
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "db/compaction/compaction_picker.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
// Picking compactions for leveled compaction. See wiki page
|
||||
// https://github.com/facebook/rocksdb/wiki/Leveled-Compaction
|
||||
// for description of Leveled compaction.
|
||||
@@ -20,13 +20,13 @@ class LevelCompactionPicker : public CompactionPicker {
|
||||
LevelCompactionPicker(const ImmutableCFOptions& ioptions,
|
||||
const InternalKeyComparator* icmp)
|
||||
: CompactionPicker(ioptions, icmp) {}
|
||||
virtual Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage,
|
||||
LogBuffer* log_buffer) override;
|
||||
virtual Compaction* PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
|
||||
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) override;
|
||||
|
||||
virtual bool NeedsCompaction(
|
||||
const VersionStorageInfo* vstorage) const override;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class CountingLogger : public Logger {
|
||||
public:
|
||||
@@ -57,6 +57,8 @@ class CompactionPickerTest : public testing::Test {
|
||||
log_buffer_(InfoLogLevel::INFO_LEVEL, &logger_),
|
||||
file_num_(1),
|
||||
vstorage_(nullptr) {
|
||||
mutable_cf_options_.ttl = 0;
|
||||
mutable_cf_options_.periodic_compaction_seconds = 0;
|
||||
// ioptions_.compaction_pri = kMinOverlappingRatio has its own set of
|
||||
// tests to cover.
|
||||
ioptions_.compaction_pri = kByCompensatedSize;
|
||||
@@ -92,7 +94,9 @@ class CompactionPickerTest : public testing::Test {
|
||||
file_number, path_id, file_size,
|
||||
InternalKey(smallest, smallest_seq, kTypeValue),
|
||||
InternalKey(largest, largest_seq, kTypeValue), smallest_seq,
|
||||
largest_seq, /* marked_for_compact */ false, kInvalidBlobFileNumber);
|
||||
largest_seq, /* marked_for_compact */ false, kInvalidBlobFileNumber,
|
||||
kUnknownOldestAncesterTime, kUnknownFileCreationTime,
|
||||
kUnknownFileChecksum, kUnknownFileChecksumFuncName);
|
||||
f->compensated_file_size =
|
||||
(compensated_file_size != 0) ? compensated_file_size : file_size;
|
||||
vstorage_->AddFile(level, f);
|
||||
@@ -499,6 +503,168 @@ TEST_F(CompactionPickerTest, AllowsTrivialMoveUniversal) {
|
||||
ASSERT_TRUE(compaction->is_trivial_move());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalPeriodicCompaction1) {
|
||||
// The case where universal periodic compaction can be picked
|
||||
// with some newer files being compacted.
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.periodic_compaction_seconds = 1000;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(5, kCompactionStyleUniversal);
|
||||
|
||||
Add(0, 1U, "150", "200", kFileSize, 0, 500, 550);
|
||||
Add(0, 2U, "201", "250", kFileSize, 0, 401, 450);
|
||||
Add(0, 4U, "260", "300", kFileSize, 0, 260, 300);
|
||||
Add(3, 5U, "010", "080", kFileSize, 0, 200, 251);
|
||||
Add(4, 3U, "301", "350", kFileSize, 0, 101, 150);
|
||||
Add(4, 6U, "501", "750", kFileSize, 0, 101, 150);
|
||||
|
||||
file_map_[2].first->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
vstorage_->TEST_AddFileMarkedForPeriodicCompaction(4, file_map_[3].first);
|
||||
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
|
||||
ASSERT_TRUE(compaction);
|
||||
ASSERT_EQ(4, compaction->output_level());
|
||||
ASSERT_EQ(0, compaction->start_level());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalPeriodicCompaction2) {
|
||||
// The case where universal periodic compaction does not
|
||||
// pick up only level to compact if it doesn't cover
|
||||
// any file marked as periodic compaction.
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.periodic_compaction_seconds = 1000;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(5, kCompactionStyleUniversal);
|
||||
|
||||
Add(0, 1U, "150", "200", kFileSize, 0, 500, 550);
|
||||
Add(3, 5U, "010", "080", kFileSize, 0, 200, 251);
|
||||
Add(4, 3U, "301", "350", kFileSize, 0, 101, 150);
|
||||
Add(4, 6U, "501", "750", kFileSize, 0, 101, 150);
|
||||
|
||||
file_map_[5].first->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
vstorage_->TEST_AddFileMarkedForPeriodicCompaction(0, file_map_[1].first);
|
||||
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
|
||||
ASSERT_FALSE(compaction);
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalPeriodicCompaction3) {
|
||||
// The case where universal periodic compaction does not
|
||||
// pick up only the last sorted run which is an L0 file if it isn't
|
||||
// marked as periodic compaction.
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.periodic_compaction_seconds = 1000;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(5, kCompactionStyleUniversal);
|
||||
|
||||
Add(0, 1U, "150", "200", kFileSize, 0, 500, 550);
|
||||
Add(0, 5U, "010", "080", kFileSize, 0, 200, 251);
|
||||
Add(0, 6U, "501", "750", kFileSize, 0, 101, 150);
|
||||
|
||||
file_map_[5].first->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
vstorage_->TEST_AddFileMarkedForPeriodicCompaction(0, file_map_[1].first);
|
||||
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
|
||||
ASSERT_FALSE(compaction);
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalPeriodicCompaction4) {
|
||||
// The case where universal periodic compaction couldn't form
|
||||
// a compaction that inlcudes any file marked for periodic compaction.
|
||||
// Right now we form the compaction anyway if it is more than one
|
||||
// sorted run. Just put the case here to validate that it doesn't
|
||||
// crash.
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.periodic_compaction_seconds = 1000;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(5, kCompactionStyleUniversal);
|
||||
|
||||
Add(0, 1U, "150", "200", kFileSize, 0, 500, 550);
|
||||
Add(2, 2U, "010", "080", kFileSize, 0, 200, 251);
|
||||
Add(3, 5U, "010", "080", kFileSize, 0, 200, 251);
|
||||
Add(4, 3U, "301", "350", kFileSize, 0, 101, 150);
|
||||
Add(4, 6U, "501", "750", kFileSize, 0, 101, 150);
|
||||
|
||||
file_map_[2].first->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
vstorage_->TEST_AddFileMarkedForPeriodicCompaction(0, file_map_[2].first);
|
||||
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(!compaction ||
|
||||
compaction->start_level() != compaction->output_level());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalPeriodicCompaction5) {
|
||||
// Test single L0 file periodic compaction triggering.
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.periodic_compaction_seconds = 1000;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(5, kCompactionStyleUniversal);
|
||||
|
||||
Add(0, 6U, "150", "200", kFileSize, 0, 500, 550);
|
||||
UpdateVersionStorageInfo();
|
||||
vstorage_->TEST_AddFileMarkedForPeriodicCompaction(0, file_map_[6].first);
|
||||
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction);
|
||||
ASSERT_EQ(0, compaction->start_level());
|
||||
ASSERT_EQ(1U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(6U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(4, compaction->output_level());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, UniversalPeriodicCompaction6) {
|
||||
// Test single sorted run non-L0 periodic compaction
|
||||
const uint64_t kFileSize = 100000;
|
||||
|
||||
mutable_cf_options_.periodic_compaction_seconds = 1000;
|
||||
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
||||
|
||||
NewVersionStorage(5, kCompactionStyleUniversal);
|
||||
|
||||
Add(4, 5U, "150", "200", kFileSize, 0, 500, 550);
|
||||
Add(4, 6U, "350", "400", kFileSize, 0, 500, 550);
|
||||
UpdateVersionStorageInfo();
|
||||
vstorage_->TEST_AddFileMarkedForPeriodicCompaction(4, file_map_[6].first);
|
||||
|
||||
std::unique_ptr<Compaction> compaction(
|
||||
universal_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
||||
ASSERT_TRUE(compaction);
|
||||
ASSERT_EQ(4, compaction->start_level());
|
||||
ASSERT_EQ(2U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(5U, compaction->input(0, 0)->fd.GetNumber());
|
||||
ASSERT_EQ(6U, compaction->input(0, 1)->fd.GetNumber());
|
||||
ASSERT_EQ(4, compaction->output_level());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, NeedsCompactionFIFO) {
|
||||
NewVersionStorage(1, kCompactionStyleFIFO);
|
||||
const int kFileCount =
|
||||
@@ -1486,12 +1652,12 @@ TEST_F(CompactionPickerTest, IntraL0MaxCompactionBytesNotHit) {
|
||||
// All 5 L0 files will be picked for intra L0 compaction. The one L1 file
|
||||
// spans entire L0 key range and is marked as being compacted to avoid
|
||||
// L0->L1 compaction.
|
||||
Add(0, 1U, "100", "150", 200000U);
|
||||
Add(0, 2U, "151", "200", 200000U);
|
||||
Add(0, 3U, "201", "250", 200000U);
|
||||
Add(0, 4U, "251", "300", 200000U);
|
||||
Add(0, 5U, "301", "350", 200000U);
|
||||
Add(1, 6U, "100", "350", 200000U);
|
||||
Add(0, 1U, "100", "150", 200000U, 0, 100, 101);
|
||||
Add(0, 2U, "151", "200", 200000U, 0, 102, 103);
|
||||
Add(0, 3U, "201", "250", 200000U, 0, 104, 105);
|
||||
Add(0, 4U, "251", "300", 200000U, 0, 106, 107);
|
||||
Add(0, 5U, "301", "350", 200000U, 0, 108, 109);
|
||||
Add(1, 6U, "100", "350", 200000U, 0, 110, 111);
|
||||
vstorage_->LevelFiles(1)[0]->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
@@ -1516,12 +1682,12 @@ TEST_F(CompactionPickerTest, IntraL0MaxCompactionBytesHit) {
|
||||
// max_compaction_bytes limit (the minimum number of files for triggering
|
||||
// intra L0 compaction is 4). The one L1 file spans entire L0 key range and
|
||||
// is marked as being compacted to avoid L0->L1 compaction.
|
||||
Add(0, 1U, "100", "150", 200000U);
|
||||
Add(0, 2U, "151", "200", 200000U);
|
||||
Add(0, 3U, "201", "250", 200000U);
|
||||
Add(0, 4U, "251", "300", 200000U);
|
||||
Add(0, 5U, "301", "350", 200000U);
|
||||
Add(1, 6U, "100", "350", 200000U);
|
||||
Add(0, 1U, "100", "150", 200000U, 0, 100, 101);
|
||||
Add(0, 2U, "151", "200", 200000U, 0, 102, 103);
|
||||
Add(0, 3U, "201", "250", 200000U, 0, 104, 105);
|
||||
Add(0, 4U, "251", "300", 200000U, 0, 106, 107);
|
||||
Add(0, 5U, "301", "350", 200000U, 0, 108, 109);
|
||||
Add(1, 6U, "100", "350", 200000U, 0, 109, 110);
|
||||
vstorage_->LevelFiles(1)[0]->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
@@ -1535,7 +1701,39 @@ TEST_F(CompactionPickerTest, IntraL0MaxCompactionBytesHit) {
|
||||
ASSERT_EQ(0, compaction->output_level());
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
TEST_F(CompactionPickerTest, IntraL0ForEarliestSeqno) {
|
||||
// Intra L0 compaction triggers only if there are at least
|
||||
// level0_file_num_compaction_trigger + 2 L0 files.
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = 3;
|
||||
mutable_cf_options_.max_compaction_bytes = 999999u;
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
|
||||
// 4 out of 6 L0 files will be picked for intra L0 compaction due to
|
||||
// being_compact limit. And the latest one L0 will be skipped due to earliest
|
||||
// seqno. The one L1 file spans entire L0 key range and is marked as being
|
||||
// compacted to avoid L0->L1 compaction.
|
||||
Add(1, 1U, "100", "350", 200000U, 0, 110, 111);
|
||||
Add(0, 2U, "301", "350", 1U, 0, 108, 109);
|
||||
Add(0, 3U, "251", "300", 1U, 0, 106, 107);
|
||||
Add(0, 4U, "201", "250", 1U, 0, 104, 105);
|
||||
Add(0, 5U, "151", "200", 1U, 0, 102, 103);
|
||||
Add(0, 6U, "100", "150", 1U, 0, 100, 101);
|
||||
Add(0, 7U, "100", "100", 1U, 0, 99, 100);
|
||||
vstorage_->LevelFiles(0)[5]->being_compacted = true;
|
||||
vstorage_->LevelFiles(1)[0]->being_compacted = true;
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
||||
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_, 107));
|
||||
ASSERT_TRUE(compaction.get() != nullptr);
|
||||
ASSERT_EQ(1U, compaction->num_input_levels());
|
||||
ASSERT_EQ(4U, compaction->num_input_files(0));
|
||||
ASSERT_EQ(CompactionReason::kLevelL0FilesNum,
|
||||
compaction->compaction_reason());
|
||||
ASSERT_EQ(0, compaction->output_level());
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "util/random.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
// A helper class that form universal compactions. The class is used by
|
||||
// UniversalCompactionPicker::PickCompaction().
|
||||
@@ -90,6 +90,19 @@ class UniversalCompactionBuilder {
|
||||
|
||||
Compaction* PickDeleteTriggeredCompaction();
|
||||
|
||||
// Form a compaction from the sorted run indicated by start_index to the
|
||||
// oldest sorted run.
|
||||
// The caller is responsible for making sure that those files are not in
|
||||
// compaction.
|
||||
Compaction* PickCompactionToOldest(size_t start_index,
|
||||
CompactionReason compaction_reason);
|
||||
|
||||
// Try to pick periodic compaction. The caller should only call it
|
||||
// if there is at least one file marked for periodic compaction.
|
||||
// null will be returned if no such a compaction can be formed
|
||||
// because some files are being compacted.
|
||||
Compaction* PickPeriodicCompaction();
|
||||
|
||||
// Used in universal compaction when the enabled_trivial_move
|
||||
// option is set. Checks whether there are any overlapping files
|
||||
// in the input. Returns true if the input files are non
|
||||
@@ -234,7 +247,8 @@ bool UniversalCompactionBuilder::IsInputFilesNonOverlapping(Compaction* c) {
|
||||
|
||||
next.f = nullptr;
|
||||
|
||||
if (curr.level != 0 && curr.index < c->num_input_files(curr.level) - 1) {
|
||||
if (c->level(curr.level) != 0 &&
|
||||
curr.index < c->num_input_files(curr.level) - 1) {
|
||||
next.f = c->input(curr.level, curr.index + 1);
|
||||
next.level = curr.level;
|
||||
next.index = curr.index + 1;
|
||||
@@ -253,6 +267,9 @@ bool UniversalCompactionPicker::NeedsCompaction(
|
||||
if (vstorage->CompactionScore(kLevel0) >= 1) {
|
||||
return true;
|
||||
}
|
||||
if (!vstorage->FilesMarkedForPeriodicCompaction().empty()) {
|
||||
return true;
|
||||
}
|
||||
if (!vstorage->FilesMarkedForCompaction().empty()) {
|
||||
return true;
|
||||
}
|
||||
@@ -261,7 +278,8 @@ bool UniversalCompactionPicker::NeedsCompaction(
|
||||
|
||||
Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer) {
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
|
||||
SequenceNumber /* earliest_memtable_seqno */) {
|
||||
UniversalCompactionBuilder builder(ioptions_, icmp_, cf_name,
|
||||
mutable_cf_options, vstorage, this,
|
||||
log_buffer);
|
||||
@@ -358,7 +376,8 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
CalculateSortedRuns(*vstorage_, ioptions_, mutable_cf_options_);
|
||||
|
||||
if (sorted_runs_.size() == 0 ||
|
||||
(vstorage_->FilesMarkedForCompaction().empty() &&
|
||||
(vstorage_->FilesMarkedForPeriodicCompaction().empty() &&
|
||||
vstorage_->FilesMarkedForCompaction().empty() &&
|
||||
sorted_runs_.size() < (unsigned int)mutable_cf_options_
|
||||
.level0_file_num_compaction_trigger)) {
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: nothing to do\n",
|
||||
@@ -373,11 +392,19 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
"[%s] Universal: sorted runs files(%" ROCKSDB_PRIszt "): %s\n",
|
||||
cf_name_.c_str(), sorted_runs_.size(), vstorage_->LevelSummary(&tmp));
|
||||
|
||||
// Check for size amplification first.
|
||||
Compaction* c = nullptr;
|
||||
if (sorted_runs_.size() >=
|
||||
static_cast<size_t>(
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger)) {
|
||||
// Periodic compaction has higher priority than other type of compaction
|
||||
// because it's a hard requirement.
|
||||
if (!vstorage_->FilesMarkedForPeriodicCompaction().empty()) {
|
||||
// Always need to do a full compaction for periodic compaction.
|
||||
c = PickPeriodicCompaction();
|
||||
}
|
||||
|
||||
// Check for size amplification.
|
||||
if (c == nullptr &&
|
||||
sorted_runs_.size() >=
|
||||
static_cast<size_t>(
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger)) {
|
||||
if ((c = PickCompactionToReduceSizeAmp()) != nullptr) {
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: compacting for size amp\n",
|
||||
cf_name_.c_str());
|
||||
@@ -441,7 +468,8 @@ Compaction* UniversalCompactionBuilder::PickCompaction() {
|
||||
}
|
||||
|
||||
if (mutable_cf_options_.compaction_options_universal.allow_trivial_move ==
|
||||
true) {
|
||||
true &&
|
||||
c->compaction_reason() != CompactionReason::kPeriodicCompaction) {
|
||||
c->set_is_trivial_move(IsInputFilesNonOverlapping(c));
|
||||
}
|
||||
|
||||
@@ -815,59 +843,8 @@ Compaction* UniversalCompactionBuilder::PickCompactionToReduceSizeAmp() {
|
||||
" earliest-file-size %" PRIu64,
|
||||
cf_name_.c_str(), candidate_size, earliest_file_size);
|
||||
}
|
||||
assert(start_index < sorted_runs_.size() - 1);
|
||||
|
||||
// Estimate total file size
|
||||
uint64_t estimated_total_size = 0;
|
||||
for (size_t loop = start_index; loop < sorted_runs_.size(); loop++) {
|
||||
estimated_total_size += sorted_runs_[loop].size;
|
||||
}
|
||||
uint32_t path_id =
|
||||
GetPathId(ioptions_, mutable_cf_options_, estimated_total_size);
|
||||
int start_level = sorted_runs_[start_index].level;
|
||||
|
||||
std::vector<CompactionInputFiles> inputs(vstorage_->num_levels());
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
inputs[i].level = start_level + static_cast<int>(i);
|
||||
}
|
||||
// We always compact all the files, so always compress.
|
||||
for (size_t loop = start_index; loop < sorted_runs_.size(); loop++) {
|
||||
auto& picking_sr = sorted_runs_[loop];
|
||||
if (picking_sr.level == 0) {
|
||||
FileMetaData* f = picking_sr.file;
|
||||
inputs[0].files.push_back(f);
|
||||
} else {
|
||||
auto& files = inputs[picking_sr.level - start_level].files;
|
||||
for (auto* f : vstorage_->LevelFiles(picking_sr.level)) {
|
||||
files.push_back(f);
|
||||
}
|
||||
}
|
||||
char file_num_buf[256];
|
||||
picking_sr.DumpSizeInfo(file_num_buf, sizeof(file_num_buf), loop);
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: size amp picking %s",
|
||||
cf_name_.c_str(), file_num_buf);
|
||||
}
|
||||
|
||||
// output files at the bottom most level, unless it's reserved
|
||||
int output_level = vstorage_->num_levels() - 1;
|
||||
// last level is reserved for the files ingested behind
|
||||
if (ioptions_.allow_ingest_behind) {
|
||||
assert(output_level > 1);
|
||||
output_level--;
|
||||
}
|
||||
|
||||
return new Compaction(
|
||||
vstorage_, ioptions_, mutable_cf_options_, std::move(inputs),
|
||||
output_level,
|
||||
MaxFileSizeForLevel(mutable_cf_options_, output_level,
|
||||
kCompactionStyleUniversal),
|
||||
/* max_grandparent_overlap_bytes */ LLONG_MAX, path_id,
|
||||
GetCompressionType(ioptions_, vstorage_, mutable_cf_options_,
|
||||
output_level, 1),
|
||||
GetCompressionOptions(ioptions_, vstorage_, output_level),
|
||||
/* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false,
|
||||
score_, false /* deletion_compaction */,
|
||||
CompactionReason::kUniversalSizeAmplification);
|
||||
return PickCompactionToOldest(start_index,
|
||||
CompactionReason::kUniversalSizeAmplification);
|
||||
}
|
||||
|
||||
// Pick files marked for compaction. Typically, files are marked by
|
||||
@@ -987,6 +964,142 @@ Compaction* UniversalCompactionBuilder::PickDeleteTriggeredCompaction() {
|
||||
score_, false /* deletion_compaction */,
|
||||
CompactionReason::kFilesMarkedForCompaction);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
Compaction* UniversalCompactionBuilder::PickCompactionToOldest(
|
||||
size_t start_index, CompactionReason compaction_reason) {
|
||||
assert(start_index < sorted_runs_.size());
|
||||
|
||||
// Estimate total file size
|
||||
uint64_t estimated_total_size = 0;
|
||||
for (size_t loop = start_index; loop < sorted_runs_.size(); loop++) {
|
||||
estimated_total_size += sorted_runs_[loop].size;
|
||||
}
|
||||
uint32_t path_id =
|
||||
GetPathId(ioptions_, mutable_cf_options_, estimated_total_size);
|
||||
int start_level = sorted_runs_[start_index].level;
|
||||
|
||||
std::vector<CompactionInputFiles> inputs(vstorage_->num_levels());
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
inputs[i].level = start_level + static_cast<int>(i);
|
||||
}
|
||||
for (size_t loop = start_index; loop < sorted_runs_.size(); loop++) {
|
||||
auto& picking_sr = sorted_runs_[loop];
|
||||
if (picking_sr.level == 0) {
|
||||
FileMetaData* f = picking_sr.file;
|
||||
inputs[0].files.push_back(f);
|
||||
} else {
|
||||
auto& files = inputs[picking_sr.level - start_level].files;
|
||||
for (auto* f : vstorage_->LevelFiles(picking_sr.level)) {
|
||||
files.push_back(f);
|
||||
}
|
||||
}
|
||||
std::string comp_reason_print_string;
|
||||
if (compaction_reason == CompactionReason::kPeriodicCompaction) {
|
||||
comp_reason_print_string = "periodic compaction";
|
||||
} else if (compaction_reason ==
|
||||
CompactionReason::kUniversalSizeAmplification) {
|
||||
comp_reason_print_string = "size amp";
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
char file_num_buf[256];
|
||||
picking_sr.DumpSizeInfo(file_num_buf, sizeof(file_num_buf), loop);
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: %s picking %s",
|
||||
cf_name_.c_str(), comp_reason_print_string.c_str(),
|
||||
file_num_buf);
|
||||
}
|
||||
|
||||
// output files at the bottom most level, unless it's reserved
|
||||
int output_level = vstorage_->num_levels() - 1;
|
||||
// last level is reserved for the files ingested behind
|
||||
if (ioptions_.allow_ingest_behind) {
|
||||
assert(output_level > 1);
|
||||
output_level--;
|
||||
}
|
||||
|
||||
// We never check size for
|
||||
// compaction_options_universal.compression_size_percent,
|
||||
// because we always compact all the files, so always compress.
|
||||
return new Compaction(
|
||||
vstorage_, ioptions_, mutable_cf_options_, std::move(inputs),
|
||||
output_level,
|
||||
MaxFileSizeForLevel(mutable_cf_options_, output_level,
|
||||
kCompactionStyleUniversal),
|
||||
LLONG_MAX, path_id,
|
||||
GetCompressionType(ioptions_, vstorage_, mutable_cf_options_, start_level,
|
||||
1, true /* enable_compression */),
|
||||
GetCompressionOptions(ioptions_, vstorage_, start_level,
|
||||
true /* enable_compression */),
|
||||
/* max_subcompactions */ 0, /* grandparents */ {}, /* is manual */ false,
|
||||
score_, false /* deletion_compaction */, compaction_reason);
|
||||
}
|
||||
|
||||
Compaction* UniversalCompactionBuilder::PickPeriodicCompaction() {
|
||||
ROCKS_LOG_BUFFER(log_buffer_, "[%s] Universal: Periodic Compaction",
|
||||
cf_name_.c_str());
|
||||
|
||||
// In universal compaction, sorted runs contain older data are almost always
|
||||
// generated earlier too. To simplify the problem, we just try to trigger
|
||||
// a full compaction. We start from the oldest sorted run and include
|
||||
// all sorted runs, until we hit a sorted already being compacted.
|
||||
// Since usually the largest (which is usually the oldest) sorted run is
|
||||
// included anyway, doing a full compaction won't increase write
|
||||
// amplification much.
|
||||
|
||||
// Get some information from marked files to check whether a file is
|
||||
// included in the compaction.
|
||||
|
||||
size_t start_index = sorted_runs_.size();
|
||||
while (start_index > 0 && !sorted_runs_[start_index - 1].being_compacted) {
|
||||
start_index--;
|
||||
}
|
||||
if (start_index == sorted_runs_.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// There is a rare corner case where we can't pick up all the files
|
||||
// because some files are being compacted and we end up with picking files
|
||||
// but none of them need periodic compaction. Unless we simply recompact
|
||||
// the last sorted run (either the last level or last L0 file), we would just
|
||||
// execute the compaction, in order to simplify the logic.
|
||||
if (start_index == sorted_runs_.size() - 1) {
|
||||
bool included_file_marked = false;
|
||||
int start_level = sorted_runs_[start_index].level;
|
||||
FileMetaData* start_file = sorted_runs_[start_index].file;
|
||||
for (const std::pair<int, FileMetaData*>& level_file_pair :
|
||||
vstorage_->FilesMarkedForPeriodicCompaction()) {
|
||||
if (start_level != 0) {
|
||||
// Last sorted run is a level
|
||||
if (start_level == level_file_pair.first) {
|
||||
included_file_marked = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Last sorted run is a L0 file.
|
||||
if (start_file == level_file_pair.second) {
|
||||
included_file_marked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!included_file_marked) {
|
||||
ROCKS_LOG_BUFFER(log_buffer_,
|
||||
"[%s] Universal: Cannot form a compaction covering file "
|
||||
"marked for periodic compaction",
|
||||
cf_name_.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Compaction* c = PickCompactionToOldest(start_index,
|
||||
CompactionReason::kPeriodicCompaction);
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"UniversalCompactionPicker::PickPeriodicCompaction:Return", c);
|
||||
|
||||
return c;
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
@@ -12,21 +12,20 @@
|
||||
|
||||
#include "db/compaction/compaction_picker.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class UniversalCompactionPicker : public CompactionPicker {
|
||||
public:
|
||||
UniversalCompactionPicker(const ImmutableCFOptions& ioptions,
|
||||
const InternalKeyComparator* icmp)
|
||||
: CompactionPicker(ioptions, icmp) {}
|
||||
virtual Compaction* PickCompaction(const std::string& cf_name,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage,
|
||||
LogBuffer* log_buffer) override;
|
||||
|
||||
virtual Compaction* PickCompaction(
|
||||
const std::string& cf_name, const MutableCFOptions& mutable_cf_options,
|
||||
VersionStorageInfo* vstorage, LogBuffer* log_buffer,
|
||||
SequenceNumber earliest_memtable_seqno = kMaxSequenceNumber) override;
|
||||
virtual int MaxOutputLevel() const override { return NumberLevels() - 1; }
|
||||
|
||||
virtual bool NeedsCompaction(
|
||||
const VersionStorageInfo* vstorage) const override;
|
||||
};
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // !ROCKSDB_LITE
|
||||
+13
-13
@@ -18,10 +18,10 @@
|
||||
|
||||
using std::unique_ptr;
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
|
||||
static const Comparator* comparator;
|
||||
static const Comparator* kTestComparator = nullptr;
|
||||
|
||||
class KVIter : public Iterator {
|
||||
public:
|
||||
@@ -74,7 +74,7 @@ void AssertItersEqual(Iterator* iter1, Iterator* iter2) {
|
||||
void DoRandomIteraratorTest(DB* db, std::vector<std::string> source_strings,
|
||||
Random* rnd, int num_writes, int num_iter_ops,
|
||||
int num_trigger_flush) {
|
||||
stl_wrappers::KVMap map((stl_wrappers::LessOfComparator(comparator)));
|
||||
stl_wrappers::KVMap map((stl_wrappers::LessOfComparator(kTestComparator)));
|
||||
|
||||
for (int i = 0; i < num_writes; i++) {
|
||||
if (num_trigger_flush > 0 && i != 0 && i % num_trigger_flush == 0) {
|
||||
@@ -263,19 +263,19 @@ class ComparatorDBTest
|
||||
|
||||
public:
|
||||
ComparatorDBTest() : env_(Env::Default()), db_(nullptr) {
|
||||
comparator = BytewiseComparator();
|
||||
kTestComparator = BytewiseComparator();
|
||||
dbname_ = test::PerThreadDBPath("comparator_db_test");
|
||||
BlockBasedTableOptions toptions;
|
||||
toptions.format_version = GetParam();
|
||||
last_options_.table_factory.reset(
|
||||
rocksdb::NewBlockBasedTableFactory(toptions));
|
||||
ROCKSDB_NAMESPACE::NewBlockBasedTableFactory(toptions));
|
||||
EXPECT_OK(DestroyDB(dbname_, last_options_));
|
||||
}
|
||||
|
||||
~ComparatorDBTest() override {
|
||||
delete db_;
|
||||
EXPECT_OK(DestroyDB(dbname_, last_options_));
|
||||
comparator = BytewiseComparator();
|
||||
kTestComparator = BytewiseComparator();
|
||||
}
|
||||
|
||||
DB* GetDB() { return db_; }
|
||||
@@ -286,7 +286,7 @@ class ComparatorDBTest
|
||||
} else {
|
||||
comparator_guard.reset();
|
||||
}
|
||||
comparator = cmp;
|
||||
kTestComparator = cmp;
|
||||
last_options_.comparator = cmp;
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ TEST_P(ComparatorDBTest, SimpleSuffixReverseComparator) {
|
||||
|
||||
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
|
||||
Options* opt = GetOptions();
|
||||
opt->comparator = comparator;
|
||||
opt->comparator = kTestComparator;
|
||||
DestroyAndReopen();
|
||||
Random rnd(rnd_seed);
|
||||
|
||||
@@ -360,7 +360,7 @@ TEST_P(ComparatorDBTest, Uint64Comparator) {
|
||||
|
||||
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
|
||||
Options* opt = GetOptions();
|
||||
opt->comparator = comparator;
|
||||
opt->comparator = kTestComparator;
|
||||
DestroyAndReopen();
|
||||
Random rnd(rnd_seed);
|
||||
Random64 rnd64(rnd_seed);
|
||||
@@ -384,7 +384,7 @@ TEST_P(ComparatorDBTest, DoubleComparator) {
|
||||
|
||||
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
|
||||
Options* opt = GetOptions();
|
||||
opt->comparator = comparator;
|
||||
opt->comparator = kTestComparator;
|
||||
DestroyAndReopen();
|
||||
Random rnd(rnd_seed);
|
||||
|
||||
@@ -409,7 +409,7 @@ TEST_P(ComparatorDBTest, HashComparator) {
|
||||
|
||||
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
|
||||
Options* opt = GetOptions();
|
||||
opt->comparator = comparator;
|
||||
opt->comparator = kTestComparator;
|
||||
DestroyAndReopen();
|
||||
Random rnd(rnd_seed);
|
||||
|
||||
@@ -428,7 +428,7 @@ TEST_P(ComparatorDBTest, TwoStrComparator) {
|
||||
|
||||
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
|
||||
Options* opt = GetOptions();
|
||||
opt->comparator = comparator;
|
||||
opt->comparator = kTestComparator;
|
||||
DestroyAndReopen();
|
||||
Random rnd(rnd_seed);
|
||||
|
||||
@@ -652,7 +652,7 @@ TEST_P(ComparatorDBTest, SeparatorSuccessorRandomizeTest) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
+7
-5
@@ -11,7 +11,7 @@
|
||||
#include "db/db_impl/db_impl.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
void CancelAllBackgroundWork(DB* db, bool wait) {
|
||||
(static_cast_with_check<DBImpl, DB>(db->GetRootDB()))
|
||||
@@ -41,14 +41,16 @@ Status VerifySstFileChecksum(const Options& options,
|
||||
const EnvOptions& env_options,
|
||||
const ReadOptions& read_options,
|
||||
const std::string& file_path) {
|
||||
std::unique_ptr<RandomAccessFile> file;
|
||||
std::unique_ptr<FSRandomAccessFile> file;
|
||||
uint64_t file_size;
|
||||
InternalKeyComparator internal_comparator(options.comparator);
|
||||
ImmutableCFOptions ioptions(options);
|
||||
|
||||
Status s = ioptions.env->NewRandomAccessFile(file_path, &file, env_options);
|
||||
Status s = ioptions.fs->NewRandomAccessFile(file_path,
|
||||
FileOptions(env_options),
|
||||
&file, nullptr);
|
||||
if (s.ok()) {
|
||||
s = ioptions.env->GetFileSize(file_path, &file_size);
|
||||
s = ioptions.fs->GetFileSize(file_path, IOOptions(), &file_size, nullptr);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
@@ -70,6 +72,6 @@ Status VerifySstFileChecksum(const Options& options,
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
+24
-15
@@ -20,6 +20,7 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "db/log_format.h"
|
||||
#include "db/version_set.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/filename.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
@@ -32,7 +33,7 @@
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
static const int kValueSize = 1000;
|
||||
|
||||
@@ -97,7 +98,7 @@ class CorruptionTest : public testing::Test {
|
||||
void RepairDB() {
|
||||
delete db_;
|
||||
db_ = nullptr;
|
||||
ASSERT_OK(::rocksdb::RepairDB(dbname_, options_));
|
||||
ASSERT_OK(::ROCKSDB_NAMESPACE::RepairDB(dbname_, options_));
|
||||
}
|
||||
|
||||
void Build(int n, int flush_every = 0) {
|
||||
@@ -189,6 +190,7 @@ class CorruptionTest : public testing::Test {
|
||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||
Options options;
|
||||
EnvOptions env_options;
|
||||
options.file_system.reset(new LegacyFileSystemWrapper(options.env));
|
||||
ASSERT_NOK(VerifySstFileChecksum(options, env_options, fname));
|
||||
}
|
||||
|
||||
@@ -369,6 +371,13 @@ TEST_F(CorruptionTest, VerifyChecksumReadahead) {
|
||||
ASSERT_GE(senv.random_read_counter_.Read(), 213);
|
||||
ASSERT_LE(senv.random_read_counter_.Read(), 447);
|
||||
|
||||
// Test readahead shouldn't break mmap mode (where it should be
|
||||
// disabled).
|
||||
options.allow_mmap_reads = true;
|
||||
Reopen(&options);
|
||||
dbi = static_cast<DBImpl*>(db_);
|
||||
ASSERT_OK(dbi->VerifyChecksum(ro));
|
||||
|
||||
CloseDb();
|
||||
}
|
||||
|
||||
@@ -384,12 +393,16 @@ TEST_F(CorruptionTest, TableFileIndexData) {
|
||||
|
||||
// corrupt an index block of an entire file
|
||||
Corrupt(kTableFile, -2000, 500);
|
||||
Reopen();
|
||||
options.paranoid_checks = false;
|
||||
Reopen(&options);
|
||||
dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
// one full file may be readable, since only one was corrupted
|
||||
// the other file should be fully non-readable, since index was corrupted
|
||||
Check(0, 5000);
|
||||
ASSERT_NOK(dbi->VerifyChecksum());
|
||||
|
||||
// In paranoid mode, the db cannot be opened due to the corrupted file.
|
||||
ASSERT_TRUE(TryReopen().IsCorruption());
|
||||
}
|
||||
|
||||
TEST_F(CorruptionTest, MissingDescriptor) {
|
||||
@@ -532,7 +545,8 @@ TEST_F(CorruptionTest, RangeDeletionCorrupted) {
|
||||
std::unique_ptr<RandomAccessFile> file;
|
||||
ASSERT_OK(options_.env->NewRandomAccessFile(filename, &file, EnvOptions()));
|
||||
std::unique_ptr<RandomAccessFileReader> file_reader(
|
||||
new RandomAccessFileReader(std::move(file), filename));
|
||||
new RandomAccessFileReader(NewLegacyRandomAccessFileWrapper(file),
|
||||
filename));
|
||||
|
||||
uint64_t file_size;
|
||||
ASSERT_OK(options_.env->GetFileSize(filename, &file_size));
|
||||
@@ -544,13 +558,7 @@ TEST_F(CorruptionTest, RangeDeletionCorrupted) {
|
||||
|
||||
ASSERT_OK(TryReopen());
|
||||
CorruptFile(filename, static_cast<int>(range_del_handle.offset()), 1);
|
||||
// The test case does not fail on TryReopen because failure to preload table
|
||||
// handlers is not considered critical.
|
||||
ASSERT_OK(TryReopen());
|
||||
std::string val;
|
||||
// However, it does fail on any read involving that file since that file
|
||||
// cannot be opened with a corrupt range deletion meta-block.
|
||||
ASSERT_TRUE(db_->Get(ReadOptions(), "a", &val).IsCorruption());
|
||||
ASSERT_TRUE(TryReopen().IsCorruption());
|
||||
}
|
||||
|
||||
TEST_F(CorruptionTest, FileSystemStateCorrupted) {
|
||||
@@ -575,18 +583,19 @@ TEST_F(CorruptionTest, FileSystemStateCorrupted) {
|
||||
env_.NewWritableFile(filename, &file, EnvOptions());
|
||||
file->Append(Slice("corrupted sst"));
|
||||
file.reset();
|
||||
Status x = TryReopen(&options);
|
||||
ASSERT_TRUE(x.IsCorruption());
|
||||
} else { // delete the file
|
||||
env_.DeleteFile(filename);
|
||||
Status x = TryReopen(&options);
|
||||
ASSERT_TRUE(x.IsPathNotFound());
|
||||
}
|
||||
|
||||
Status x = TryReopen(&options);
|
||||
ASSERT_TRUE(x.IsCorruption());
|
||||
DestroyDB(dbname_, options_);
|
||||
Reopen(&options);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class CuckooTableDBTest : public testing::Test {
|
||||
private:
|
||||
@@ -285,6 +285,9 @@ TEST_F(CuckooTableDBTest, SameKeyInsertedInTwoDifferentFilesAndCompacted) {
|
||||
TEST_F(CuckooTableDBTest, AdaptiveTable) {
|
||||
Options options = CurrentOptions();
|
||||
|
||||
// Ensure options compatible with PlainTable
|
||||
options.prefix_extractor.reset(NewCappedPrefixTransform(8));
|
||||
|
||||
// Write some keys using cuckoo table.
|
||||
options.table_factory.reset(NewCuckooTableFactory());
|
||||
Reopen(&options);
|
||||
@@ -295,17 +298,25 @@ TEST_F(CuckooTableDBTest, AdaptiveTable) {
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
|
||||
// Write some keys using plain table.
|
||||
std::shared_ptr<TableFactory> block_based_factory(
|
||||
NewBlockBasedTableFactory());
|
||||
std::shared_ptr<TableFactory> plain_table_factory(
|
||||
NewPlainTableFactory());
|
||||
std::shared_ptr<TableFactory> cuckoo_table_factory(
|
||||
NewCuckooTableFactory());
|
||||
options.create_if_missing = false;
|
||||
options.table_factory.reset(NewPlainTableFactory());
|
||||
options.table_factory.reset(NewAdaptiveTableFactory(
|
||||
plain_table_factory, block_based_factory, plain_table_factory,
|
||||
cuckoo_table_factory));
|
||||
Reopen(&options);
|
||||
ASSERT_OK(Put("key4", "v4"));
|
||||
ASSERT_OK(Put("key1", "v5"));
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
|
||||
// Write some keys using block based table.
|
||||
std::shared_ptr<TableFactory> block_based_factory(
|
||||
NewBlockBasedTableFactory());
|
||||
options.table_factory.reset(NewAdaptiveTableFactory(block_based_factory));
|
||||
options.table_factory.reset(NewAdaptiveTableFactory(
|
||||
block_based_factory, block_based_factory, plain_table_factory,
|
||||
cuckoo_table_factory));
|
||||
Reopen(&options);
|
||||
ASSERT_OK(Put("key5", "v6"));
|
||||
ASSERT_OK(Put("key2", "v7"));
|
||||
@@ -317,14 +328,13 @@ TEST_F(CuckooTableDBTest, AdaptiveTable) {
|
||||
ASSERT_EQ("v4", Get("key4"));
|
||||
ASSERT_EQ("v6", Get("key5"));
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (rocksdb::port::kLittleEndian) {
|
||||
if (ROCKSDB_NAMESPACE::port::kLittleEndian) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fprintf(stderr, "SKIPPED as Cuckoo table doesn't support Big Endian\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
+434
-208
@@ -6,18 +6,18 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
// #include <iostream>
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "rocksdb/utilities/debug.h"
|
||||
#include "table/block_based/block_based_table_reader.h"
|
||||
#include "table/block_based/block_builder.h"
|
||||
#include "test_util/fault_injection_test_env.h"
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "test_util/sync_point.h"
|
||||
#endif
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DBBasicTest : public DBTestBase {
|
||||
public:
|
||||
@@ -27,8 +27,8 @@ class DBBasicTest : public DBTestBase {
|
||||
TEST_F(DBBasicTest, OpenWhenOpen) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
rocksdb::DB* db2 = nullptr;
|
||||
rocksdb::Status s = DB::Open(options, dbname_, &db2);
|
||||
ROCKSDB_NAMESPACE::DB* db2 = nullptr;
|
||||
ROCKSDB_NAMESPACE::Status s = DB::Open(options, dbname_, &db2);
|
||||
|
||||
ASSERT_EQ(Status::Code::kIOError, s.code());
|
||||
ASSERT_EQ(Status::SubCode::kNone, s.subcode());
|
||||
@@ -324,7 +324,12 @@ TEST_F(DBBasicTest, CheckLock) {
|
||||
ASSERT_OK(TryReopen(options));
|
||||
|
||||
// second open should fail
|
||||
ASSERT_TRUE(!(DB::Open(options, dbname_, &localdb)).ok());
|
||||
Status s = DB::Open(options, dbname_, &localdb);
|
||||
ASSERT_NOK(s);
|
||||
#ifdef OS_LINUX
|
||||
ASSERT_TRUE(s.ToString().find("lock hold by current process") !=
|
||||
std::string::npos);
|
||||
#endif // OS_LINUX
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
@@ -392,7 +397,7 @@ TEST_F(DBBasicTest, FlushEmptyColumnFamily) {
|
||||
sleeping_task_low.WaitUntilDone();
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, FLUSH) {
|
||||
TEST_F(DBBasicTest, Flush) {
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
WriteOptions writeOpt = WriteOptions();
|
||||
@@ -524,6 +529,7 @@ TEST_F(DBBasicTest, Snapshot) {
|
||||
ASSERT_EQ(1U, GetNumSnapshots());
|
||||
uint64_t time_snap1 = GetTimeOldestSnapshots();
|
||||
ASSERT_GT(time_snap1, 0U);
|
||||
ASSERT_EQ(GetSequenceOldestSnapshots(), s1->GetSequenceNumber());
|
||||
Put(0, "foo", "0v2");
|
||||
Put(1, "foo", "1v2");
|
||||
|
||||
@@ -532,6 +538,7 @@ TEST_F(DBBasicTest, Snapshot) {
|
||||
const Snapshot* s2 = db_->GetSnapshot();
|
||||
ASSERT_EQ(2U, GetNumSnapshots());
|
||||
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
|
||||
ASSERT_EQ(GetSequenceOldestSnapshots(), s1->GetSequenceNumber());
|
||||
Put(0, "foo", "0v3");
|
||||
Put(1, "foo", "1v3");
|
||||
|
||||
@@ -539,6 +546,7 @@ TEST_F(DBBasicTest, Snapshot) {
|
||||
ManagedSnapshot s3(db_);
|
||||
ASSERT_EQ(3U, GetNumSnapshots());
|
||||
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
|
||||
ASSERT_EQ(GetSequenceOldestSnapshots(), s1->GetSequenceNumber());
|
||||
|
||||
Put(0, "foo", "0v4");
|
||||
Put(1, "foo", "1v4");
|
||||
@@ -554,6 +562,7 @@ TEST_F(DBBasicTest, Snapshot) {
|
||||
|
||||
ASSERT_EQ(2U, GetNumSnapshots());
|
||||
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
|
||||
ASSERT_EQ(GetSequenceOldestSnapshots(), s1->GetSequenceNumber());
|
||||
ASSERT_EQ("0v1", Get(0, "foo", s1));
|
||||
ASSERT_EQ("1v1", Get(1, "foo", s1));
|
||||
ASSERT_EQ("0v2", Get(0, "foo", s2));
|
||||
@@ -568,9 +577,11 @@ TEST_F(DBBasicTest, Snapshot) {
|
||||
ASSERT_EQ("1v4", Get(1, "foo"));
|
||||
ASSERT_EQ(1U, GetNumSnapshots());
|
||||
ASSERT_LT(time_snap1, GetTimeOldestSnapshots());
|
||||
ASSERT_EQ(GetSequenceOldestSnapshots(), s2->GetSequenceNumber());
|
||||
|
||||
db_->ReleaseSnapshot(s2);
|
||||
ASSERT_EQ(0U, GetNumSnapshots());
|
||||
ASSERT_EQ(GetSequenceOldestSnapshots(), 0);
|
||||
ASSERT_EQ("0v4", Get(0, "foo"));
|
||||
ASSERT_EQ("1v4", Get(1, "foo"));
|
||||
} while (ChangeOptions());
|
||||
@@ -871,11 +882,12 @@ TEST_F(DBBasicTest, ChecksumTest) {
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
// verify data with each type of checksum
|
||||
for (int i = 0; i <= kxxHash64; ++i) {
|
||||
// with each valid checksum type setting...
|
||||
for (int i = 0; i <= max_checksum; ++i) {
|
||||
table_options.checksum = static_cast<ChecksumType>(i);
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
// verify every type of checksum (should be regardless of that setting)
|
||||
for (int j = 0; j < (max_checksum + 1) * kNumPerFile; ++j) {
|
||||
ASSERT_EQ(Key(j), Get(Key(j)));
|
||||
}
|
||||
@@ -1017,28 +1029,44 @@ TEST_F(DBBasicTest, DBCloseFlushError) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetMultiCF) {
|
||||
class DBMultiGetTestWithParam : public DBBasicTest,
|
||||
public testing::WithParamInterface<bool> {};
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
|
||||
"alyosha", "popovich"},
|
||||
options);
|
||||
// <CF, key, value> tuples
|
||||
std::vector<std::tuple<int, std::string, std::string>> cf_kv_vec;
|
||||
static const int num_keys = 24;
|
||||
cf_kv_vec.reserve(num_keys);
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key",
|
||||
"cf" + std::to_string(i) + "_val"));
|
||||
for (int i = 0; i < num_keys; ++i) {
|
||||
int cf = i / 3;
|
||||
int cf_key = 1 % 3;
|
||||
cf_kv_vec.emplace_back(std::make_tuple(
|
||||
cf, "cf" + std::to_string(cf) + "_key_" + std::to_string(cf_key),
|
||||
"cf" + std::to_string(cf) + "_val_" + std::to_string(cf_key)));
|
||||
ASSERT_OK(Put(std::get<0>(cf_kv_vec[i]), std::get<1>(cf_kv_vec[i]),
|
||||
std::get<2>(cf_kv_vec[i])));
|
||||
}
|
||||
|
||||
int get_sv_count = 0;
|
||||
rocksdb::DBImpl* db = reinterpret_cast<DBImpl*>(db_);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::DBImpl* db = reinterpret_cast<DBImpl*>(db_);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::MultiGet::AfterRefSV", [&](void* /*arg*/) {
|
||||
if (++get_sv_count == 2) {
|
||||
// After MultiGet refs a couple of CFs, flush all CFs so MultiGet
|
||||
// is forced to repeat the process
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
ASSERT_OK(Flush(i));
|
||||
ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key",
|
||||
"cf" + std::to_string(i) + "_val2"));
|
||||
for (int i = 0; i < num_keys; ++i) {
|
||||
int cf = i / 3;
|
||||
int cf_key = i % 8;
|
||||
if (cf_key == 0) {
|
||||
ASSERT_OK(Flush(cf));
|
||||
}
|
||||
ASSERT_OK(Put(std::get<0>(cf_kv_vec[i]), std::get<1>(cf_kv_vec[i]),
|
||||
std::get<2>(cf_kv_vec[i]) + "_2"));
|
||||
}
|
||||
}
|
||||
if (get_sv_count == 11) {
|
||||
@@ -1050,32 +1078,59 @@ TEST_F(DBBasicTest, MultiGetMultiCF) {
|
||||
}
|
||||
}
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::vector<int> cfs;
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
cfs.push_back(i);
|
||||
keys.push_back("cf" + std::to_string(i) + "_key");
|
||||
for (int i = 0; i < num_keys; ++i) {
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[i]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[i]));
|
||||
}
|
||||
|
||||
values = MultiGet(cfs, keys, nullptr);
|
||||
ASSERT_EQ(values.size(), 8);
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_EQ(values.size(), num_keys);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
ASSERT_EQ(values[j], "cf" + std::to_string(j) + "_val2");
|
||||
ASSERT_EQ(values[j], std::get<2>(cf_kv_vec[j]) + "_2");
|
||||
}
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
|
||||
keys.clear();
|
||||
cfs.clear();
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[0]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[0]));
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[3]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[3]));
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[4]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[4]));
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_EQ(values[0], std::get<2>(cf_kv_vec[0]) + "_2");
|
||||
ASSERT_EQ(values[1], std::get<2>(cf_kv_vec[3]) + "_2");
|
||||
ASSERT_EQ(values[2], std::get<2>(cf_kv_vec[4]) + "_2");
|
||||
|
||||
keys.clear();
|
||||
cfs.clear();
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[7]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[7]));
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[6]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[6]));
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[1]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[1]));
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_EQ(values[0], std::get<2>(cf_kv_vec[7]) + "_2");
|
||||
ASSERT_EQ(values[1], std::get<2>(cf_kv_vec[6]) + "_2");
|
||||
ASSERT_EQ(values[2], std::get<2>(cf_kv_vec[1]) + "_2");
|
||||
|
||||
for (int cf = 0; cf < 8; ++cf) {
|
||||
auto* cfd = reinterpret_cast<ColumnFamilyHandleImpl*>(
|
||||
reinterpret_cast<DBImpl*>(db_)->GetColumnFamilyHandle(i))
|
||||
reinterpret_cast<DBImpl*>(db_)->GetColumnFamilyHandle(cf))
|
||||
->cfd();
|
||||
ASSERT_NE(cfd->TEST_GetLocalSV()->Get(), SuperVersion::kSVInUse);
|
||||
ASSERT_NE(cfd->TEST_GetLocalSV()->Get(), SuperVersion::kSVObsolete);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFMutex) {
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
|
||||
"alyosha", "popovich"},
|
||||
@@ -1089,12 +1144,12 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
|
||||
int get_sv_count = 0;
|
||||
int retries = 0;
|
||||
bool last_try = false;
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::MultiGet::LastTry", [&](void* /*arg*/) {
|
||||
last_try = true;
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::MultiGet::AfterRefSV", [&](void* /*arg*/) {
|
||||
if (last_try) {
|
||||
return;
|
||||
@@ -1110,7 +1165,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
|
||||
}
|
||||
}
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::vector<int> cfs;
|
||||
std::vector<std::string> keys;
|
||||
@@ -1121,7 +1176,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
|
||||
keys.push_back("cf" + std::to_string(i) + "_key");
|
||||
}
|
||||
|
||||
values = MultiGet(cfs, keys, nullptr);
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_TRUE(last_try);
|
||||
ASSERT_EQ(values.size(), 8);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
@@ -1136,7 +1191,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFSnapshot) {
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
|
||||
"alyosha", "popovich"},
|
||||
@@ -1148,8 +1203,8 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
|
||||
}
|
||||
|
||||
int get_sv_count = 0;
|
||||
rocksdb::DBImpl* db = reinterpret_cast<DBImpl*>(db_);
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::DBImpl* db = reinterpret_cast<DBImpl*>(db_);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::MultiGet::AfterRefSV", [&](void* /*arg*/) {
|
||||
if (++get_sv_count == 2) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
@@ -1169,7 +1224,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
|
||||
}
|
||||
}
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::vector<int> cfs;
|
||||
std::vector<std::string> keys;
|
||||
@@ -1181,7 +1236,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
|
||||
}
|
||||
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
values = MultiGet(cfs, keys, snapshot);
|
||||
values = MultiGet(cfs, keys, snapshot, GetParam());
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
ASSERT_EQ(values.size(), 8);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
@@ -1195,6 +1250,9 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBMultiGetTestWithParam, DBMultiGetTestWithParam,
|
||||
testing::Bool());
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetBatchedSimpleUnsorted) {
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
@@ -1352,6 +1410,91 @@ TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetBatchedMultiLevelMerge) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
Reopen(options);
|
||||
int num_keys = 0;
|
||||
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
ASSERT_OK(Put("key_" + std::to_string(i), "val_l2_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(2);
|
||||
|
||||
for (int i = 0; i < 128; i += 3) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_l1_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(1);
|
||||
|
||||
for (int i = 0; i < 128; i += 5) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_l0_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
Flush();
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
Flush();
|
||||
num_keys = 0;
|
||||
}
|
||||
ASSERT_EQ(0, num_keys);
|
||||
|
||||
for (int i = 0; i < 128; i += 9) {
|
||||
ASSERT_OK(Merge("key_" + std::to_string(i), "val_mem_" + std::to_string(i)));
|
||||
}
|
||||
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
|
||||
for (int i = 32; i < 80; ++i) {
|
||||
keys.push_back("key_" + std::to_string(i));
|
||||
}
|
||||
|
||||
values = MultiGet(keys, nullptr);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (unsigned int j = 0; j < 48; ++j) {
|
||||
int key = j + 32;
|
||||
std::string value;
|
||||
value.append("val_l2_" + std::to_string(key));
|
||||
if (key % 3 == 0) {
|
||||
value.append(",");
|
||||
value.append("val_l1_" + std::to_string(key));
|
||||
}
|
||||
if (key % 5 == 0) {
|
||||
value.append(",");
|
||||
value.append("val_l0_" + std::to_string(key));
|
||||
}
|
||||
if (key % 9 == 0) {
|
||||
value.append(",");
|
||||
value.append("val_mem_" + std::to_string(key));
|
||||
}
|
||||
ASSERT_EQ(values[j], value);
|
||||
}
|
||||
}
|
||||
|
||||
// Test class for batched MultiGet with prefix extractor
|
||||
// Param bool - If true, use partitioned filters
|
||||
// If false, use full filter block
|
||||
@@ -1420,7 +1563,7 @@ TEST_P(DBMultiGetRowCacheTest, MultiGetBatched) {
|
||||
do {
|
||||
option_config_ = kRowCache;
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
SetPerfLevel(kEnableCount);
|
||||
ASSERT_OK(Put(1, "k1", "v1"));
|
||||
@@ -1526,13 +1669,13 @@ TEST_F(DBBasicTest, GetAllKeyVersions) {
|
||||
ASSERT_OK(Delete(std::to_string(i)));
|
||||
}
|
||||
std::vector<KeyVersion> key_versions;
|
||||
ASSERT_OK(rocksdb::GetAllKeyVersions(db_, Slice(), Slice(),
|
||||
std::numeric_limits<size_t>::max(),
|
||||
&key_versions));
|
||||
ASSERT_OK(ROCKSDB_NAMESPACE::GetAllKeyVersions(
|
||||
db_, Slice(), Slice(), std::numeric_limits<size_t>::max(),
|
||||
&key_versions));
|
||||
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates, key_versions.size());
|
||||
ASSERT_OK(rocksdb::GetAllKeyVersions(db_, handles_[0], Slice(), Slice(),
|
||||
std::numeric_limits<size_t>::max(),
|
||||
&key_versions));
|
||||
ASSERT_OK(ROCKSDB_NAMESPACE::GetAllKeyVersions(
|
||||
db_, handles_[0], Slice(), Slice(), std::numeric_limits<size_t>::max(),
|
||||
&key_versions));
|
||||
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates, key_versions.size());
|
||||
|
||||
// Check non-default column family
|
||||
@@ -1545,13 +1688,52 @@ TEST_F(DBBasicTest, GetAllKeyVersions) {
|
||||
for (size_t i = 0; i != kNumDeletes - 1; ++i) {
|
||||
ASSERT_OK(Delete(1, std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(rocksdb::GetAllKeyVersions(db_, handles_[1], Slice(), Slice(),
|
||||
std::numeric_limits<size_t>::max(),
|
||||
&key_versions));
|
||||
ASSERT_OK(ROCKSDB_NAMESPACE::GetAllKeyVersions(
|
||||
db_, handles_[1], Slice(), Slice(), std::numeric_limits<size_t>::max(),
|
||||
&key_versions));
|
||||
ASSERT_EQ(kNumInserts + kNumDeletes + kNumUpdates - 3, key_versions.size());
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetIOBufferOverrun) {
|
||||
Options options = CurrentOptions();
|
||||
Random rnd(301);
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
|
||||
table_options.block_size = 16 * 1024;
|
||||
assert(table_options.block_size >
|
||||
BlockBasedTable::kMultiGetReadStackBufSize);
|
||||
options.table_factory.reset(new BlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
|
||||
std::string zero_str(128, '\0');
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
// Make the value compressible. A purely random string doesn't compress
|
||||
// and the resultant data block will not be compressed
|
||||
std::string value(RandomString(&rnd, 128) + zero_str);
|
||||
assert(Put(Key(i), value) == Status::OK());
|
||||
}
|
||||
Flush();
|
||||
|
||||
std::vector<std::string> key_data(10);
|
||||
std::vector<Slice> keys;
|
||||
// We cannot resize a PinnableSlice vector, so just set initial size to
|
||||
// largest we think we will need
|
||||
std::vector<PinnableSlice> values(10);
|
||||
std::vector<Status> statuses;
|
||||
ReadOptions ro;
|
||||
|
||||
// Warm up the cache first
|
||||
key_data.emplace_back(Key(0));
|
||||
keys.emplace_back(Slice(key_data.back()));
|
||||
key_data.emplace_back(Key(50));
|
||||
keys.emplace_back(Slice(key_data.back()));
|
||||
statuses.resize(keys.size());
|
||||
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data(), true);
|
||||
}
|
||||
|
||||
class DBBasicTestWithParallelIO
|
||||
: public DBTestBase,
|
||||
public testing::WithParamInterface<std::tuple<bool, bool, bool, bool>> {
|
||||
@@ -1576,8 +1758,32 @@ class DBBasicTestWithParallelIO
|
||||
Options options = CurrentOptions();
|
||||
Random rnd(301);
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (compression_enabled_) {
|
||||
std::vector<CompressionType> compression_types;
|
||||
compression_types = GetSupportedCompressions();
|
||||
// Not every platform may have compression libraries available, so
|
||||
// dynamically pick based on what's available
|
||||
if (compression_types.size() == 0) {
|
||||
compression_enabled_ = false;
|
||||
} else {
|
||||
options.compression = compression_types[0];
|
||||
}
|
||||
}
|
||||
#else
|
||||
// GetSupportedCompressions() is not available in LITE build
|
||||
if (!Snappy_Supported()) {
|
||||
compression_enabled_ = false;
|
||||
}
|
||||
#endif //ROCKSDB_LITE
|
||||
|
||||
table_options.block_cache = uncompressed_cache_;
|
||||
if (table_options.block_cache == nullptr) {
|
||||
table_options.no_block_cache = true;
|
||||
} else {
|
||||
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
|
||||
}
|
||||
table_options.block_cache_compressed = compressed_cache_;
|
||||
table_options.flush_block_policy_factory.reset(
|
||||
new MyFlushBlockPolicyFactory());
|
||||
@@ -1595,6 +1801,14 @@ class DBBasicTestWithParallelIO
|
||||
assert(Put(Key(i), values_[i]) == Status::OK());
|
||||
}
|
||||
Flush();
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
// block cannot gain space by compression
|
||||
uncompressable_values_.emplace_back(RandomString(&rnd, 256) + '\0');
|
||||
std::string tmp_key = "a" + Key(i);
|
||||
assert(Put(tmp_key, uncompressable_values_[i]) == Status::OK());
|
||||
}
|
||||
Flush();
|
||||
}
|
||||
|
||||
bool CheckValue(int i, const std::string& value) {
|
||||
@@ -1604,6 +1818,13 @@ class DBBasicTestWithParallelIO
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckUncompressableValue(int i, const std::string& value) {
|
||||
if (uncompressable_values_[i].compare(value) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int num_lookups() { return uncompressed_cache_->num_lookups(); }
|
||||
int num_found() { return uncompressed_cache_->num_found(); }
|
||||
int num_inserts() { return uncompressed_cache_->num_inserts(); }
|
||||
@@ -1613,6 +1834,9 @@ class DBBasicTestWithParallelIO
|
||||
int num_inserts_compressed() { return compressed_cache_->num_inserts(); }
|
||||
|
||||
bool fill_cache() { return fill_cache_; }
|
||||
bool compression_enabled() { return compression_enabled_; }
|
||||
bool has_compressed_cache() { return compressed_cache_ != nullptr; }
|
||||
bool has_uncompressed_cache() { return uncompressed_cache_ != nullptr; }
|
||||
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase() {}
|
||||
@@ -1750,9 +1974,12 @@ class DBBasicTestWithParallelIO
|
||||
std::shared_ptr<MyBlockCache> uncompressed_cache_;
|
||||
bool compression_enabled_;
|
||||
std::vector<std::string> values_;
|
||||
std::vector<std::string> uncompressable_values_;
|
||||
bool fill_cache_;
|
||||
};
|
||||
|
||||
// TODO: fails on CircleCI's Windows env
|
||||
#ifndef OS_WIN
|
||||
TEST_P(DBBasicTestWithParallelIO, MultiGet) {
|
||||
std::vector<std::string> key_data(10);
|
||||
std::vector<Slice> keys;
|
||||
@@ -1787,7 +2014,16 @@ TEST_P(DBBasicTestWithParallelIO, MultiGet) {
|
||||
ASSERT_TRUE(CheckValue(1, values[0].ToString()));
|
||||
ASSERT_TRUE(CheckValue(51, values[1].ToString()));
|
||||
|
||||
int expected_reads = random_reads + (fill_cache() ? 0 : 2);
|
||||
bool read_from_cache = false;
|
||||
if (fill_cache()) {
|
||||
if (has_uncompressed_cache()) {
|
||||
read_from_cache = true;
|
||||
} else if (has_compressed_cache() && compression_enabled()) {
|
||||
read_from_cache = true;
|
||||
}
|
||||
}
|
||||
|
||||
int expected_reads = random_reads + (read_from_cache ? 0 : 2);
|
||||
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
|
||||
|
||||
keys.resize(10);
|
||||
@@ -1805,8 +2041,151 @@ TEST_P(DBBasicTestWithParallelIO, MultiGet) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
ASSERT_TRUE(CheckValue(key_ints[i], values[i].ToString()));
|
||||
}
|
||||
expected_reads += (fill_cache() ? 2 : 4);
|
||||
if (compression_enabled() && !has_compressed_cache()) {
|
||||
expected_reads += (read_from_cache ? 2 : 3);
|
||||
} else {
|
||||
expected_reads += (read_from_cache ? 2 : 4);
|
||||
}
|
||||
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
|
||||
|
||||
keys.resize(10);
|
||||
statuses.resize(10);
|
||||
std::vector<int> key_uncmp{1, 2, 15, 16, 55, 81, 82, 83, 84, 85};
|
||||
for (size_t i = 0; i < key_uncmp.size(); ++i) {
|
||||
key_data[i] = "a" + Key(key_uncmp[i]);
|
||||
keys[i] = Slice(key_data[i]);
|
||||
statuses[i] = Status::OK();
|
||||
values[i].Reset();
|
||||
}
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data(), true);
|
||||
for (size_t i = 0; i < key_uncmp.size(); ++i) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
ASSERT_TRUE(CheckUncompressableValue(key_uncmp[i], values[i].ToString()));
|
||||
}
|
||||
if (compression_enabled() && !has_compressed_cache()) {
|
||||
expected_reads += (read_from_cache ? 3 : 3);
|
||||
} else {
|
||||
expected_reads += (read_from_cache ? 4 : 4);
|
||||
}
|
||||
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
|
||||
|
||||
keys.resize(5);
|
||||
statuses.resize(5);
|
||||
std::vector<int> key_tr{1, 2, 15, 16, 55};
|
||||
for (size_t i = 0; i < key_tr.size(); ++i) {
|
||||
key_data[i] = "a" + Key(key_tr[i]);
|
||||
keys[i] = Slice(key_data[i]);
|
||||
statuses[i] = Status::OK();
|
||||
values[i].Reset();
|
||||
}
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data(), true);
|
||||
for (size_t i = 0; i < key_tr.size(); ++i) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
ASSERT_TRUE(CheckUncompressableValue(key_tr[i], values[i].ToString()));
|
||||
}
|
||||
if (compression_enabled() && !has_compressed_cache()) {
|
||||
expected_reads += (read_from_cache ? 0 : 2);
|
||||
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
|
||||
} else {
|
||||
if (has_uncompressed_cache()) {
|
||||
expected_reads += (read_from_cache ? 0 : 3);
|
||||
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
|
||||
} else {
|
||||
// A rare case, even we enable the block compression but some of data
|
||||
// blocks are not compressed due to content. If user only enable the
|
||||
// compressed cache, the uncompressed blocks will not tbe cached, and
|
||||
// block reads will be triggered. The number of reads is related to
|
||||
// the compression algorithm.
|
||||
ASSERT_TRUE(env_->random_read_counter_.Read() >= expected_reads);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
TEST_P(DBBasicTestWithParallelIO, MultiGetWithChecksumMismatch) {
|
||||
std::vector<std::string> key_data(10);
|
||||
std::vector<Slice> keys;
|
||||
// We cannot resize a PinnableSlice vector, so just set initial size to
|
||||
// largest we think we will need
|
||||
std::vector<PinnableSlice> values(10);
|
||||
std::vector<Status> statuses;
|
||||
int read_count = 0;
|
||||
ReadOptions ro;
|
||||
ro.fill_cache = fill_cache();
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"RetrieveMultipleBlocks:VerifyChecksum", [&](void *status) {
|
||||
Status* s = static_cast<Status*>(status);
|
||||
read_count++;
|
||||
if (read_count == 2) {
|
||||
*s = Status::Corruption();
|
||||
}
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Warm up the cache first
|
||||
key_data.emplace_back(Key(0));
|
||||
keys.emplace_back(Slice(key_data.back()));
|
||||
key_data.emplace_back(Key(50));
|
||||
keys.emplace_back(Slice(key_data.back()));
|
||||
statuses.resize(keys.size());
|
||||
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data(), true);
|
||||
ASSERT_TRUE(CheckValue(0, values[0].ToString()));
|
||||
//ASSERT_TRUE(CheckValue(50, values[1].ToString()));
|
||||
ASSERT_EQ(statuses[0], Status::OK());
|
||||
ASSERT_EQ(statuses[1], Status::Corruption());
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
TEST_P(DBBasicTestWithParallelIO, MultiGetWithMissingFile) {
|
||||
std::vector<std::string> key_data(10);
|
||||
std::vector<Slice> keys;
|
||||
// We cannot resize a PinnableSlice vector, so just set initial size to
|
||||
// largest we think we will need
|
||||
std::vector<PinnableSlice> values(10);
|
||||
std::vector<Status> statuses;
|
||||
ReadOptions ro;
|
||||
ro.fill_cache = fill_cache();
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"TableCache::MultiGet:FindTable", [&](void *status) {
|
||||
Status* s = static_cast<Status*>(status);
|
||||
*s = Status::IOError();
|
||||
});
|
||||
// DB open will create table readers unless we reduce the table cache
|
||||
// capacity.
|
||||
// SanitizeOptions will set max_open_files to minimum of 20. Table cache
|
||||
// is allocated with max_open_files - 10 as capacity. So override
|
||||
// max_open_files to 11 so table cache capacity will become 1. This will
|
||||
// prevent file open during DB open and force the file to be opened
|
||||
// during MultiGet
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"SanitizeOptions::AfterChangeMaxOpenFiles", [&](void *arg) {
|
||||
int* max_open_files = (int*)arg;
|
||||
*max_open_files = 11;
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Reopen(CurrentOptions());
|
||||
|
||||
// Warm up the cache first
|
||||
key_data.emplace_back(Key(0));
|
||||
keys.emplace_back(Slice(key_data.back()));
|
||||
key_data.emplace_back(Key(50));
|
||||
keys.emplace_back(Slice(key_data.back()));
|
||||
statuses.resize(keys.size());
|
||||
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data(), true);
|
||||
ASSERT_EQ(statuses[0], Status::IOError());
|
||||
ASSERT_EQ(statuses[1], Status::IOError());
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
@@ -1816,164 +2195,11 @@ INSTANTIATE_TEST_CASE_P(
|
||||
// Param 1 - Uncompressed cache enabled
|
||||
// Param 2 - Data compression enabled
|
||||
// Param 3 - ReadOptions::fill_cache
|
||||
::testing::Values(std::make_tuple(false, true, true, true),
|
||||
std::make_tuple(true, true, true, true),
|
||||
std::make_tuple(false, true, false, true),
|
||||
std::make_tuple(false, true, true, false),
|
||||
std::make_tuple(true, true, true, false),
|
||||
std::make_tuple(false, true, false, false)));
|
||||
::testing::Combine(::testing::Bool(), ::testing::Bool(),
|
||||
::testing::Bool(), ::testing::Bool()));
|
||||
|
||||
class DBBasicTestWithTimestampWithParam
|
||||
: public DBTestBase,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
DBBasicTestWithTimestampWithParam()
|
||||
: DBTestBase("/db_basic_test_with_timestamp") {}
|
||||
|
||||
protected:
|
||||
class TestComparator : public Comparator {
|
||||
private:
|
||||
const Comparator* cmp_without_ts_;
|
||||
|
||||
public:
|
||||
explicit TestComparator(size_t ts_sz)
|
||||
: Comparator(ts_sz), cmp_without_ts_(nullptr) {
|
||||
cmp_without_ts_ = BytewiseComparator();
|
||||
}
|
||||
|
||||
const char* Name() const override { return "TestComparator"; }
|
||||
|
||||
void FindShortSuccessor(std::string*) const override {}
|
||||
|
||||
void FindShortestSeparator(std::string*, const Slice&) const override {}
|
||||
|
||||
int Compare(const Slice& a, const Slice& b) const override {
|
||||
int r = CompareWithoutTimestamp(a, b);
|
||||
if (r != 0 || 0 == timestamp_size()) {
|
||||
return r;
|
||||
}
|
||||
return CompareTimestamp(
|
||||
Slice(a.data() + a.size() - timestamp_size(), timestamp_size()),
|
||||
Slice(b.data() + b.size() - timestamp_size(), timestamp_size()));
|
||||
}
|
||||
|
||||
int CompareWithoutTimestamp(const Slice& a, const Slice& b) const override {
|
||||
assert(a.size() >= timestamp_size());
|
||||
assert(b.size() >= timestamp_size());
|
||||
Slice k1 = StripTimestampFromUserKey(a, timestamp_size());
|
||||
Slice k2 = StripTimestampFromUserKey(b, timestamp_size());
|
||||
|
||||
return cmp_without_ts_->Compare(k1, k2);
|
||||
}
|
||||
|
||||
int CompareTimestamp(const Slice& ts1, const Slice& ts2) const override {
|
||||
if (!ts1.data() && !ts2.data()) {
|
||||
return 0;
|
||||
} else if (ts1.data() && !ts2.data()) {
|
||||
return 1;
|
||||
} else if (!ts1.data() && ts2.data()) {
|
||||
return -1;
|
||||
}
|
||||
assert(ts1.size() == ts2.size());
|
||||
uint64_t low1 = 0;
|
||||
uint64_t low2 = 0;
|
||||
uint64_t high1 = 0;
|
||||
uint64_t high2 = 0;
|
||||
auto* ptr1 = const_cast<Slice*>(&ts1);
|
||||
auto* ptr2 = const_cast<Slice*>(&ts2);
|
||||
if (!GetFixed64(ptr1, &low1) || !GetFixed64(ptr1, &high1) ||
|
||||
!GetFixed64(ptr2, &low2) || !GetFixed64(ptr2, &high2)) {
|
||||
assert(false);
|
||||
}
|
||||
if (high1 < high2) {
|
||||
return 1;
|
||||
} else if (high1 > high2) {
|
||||
return -1;
|
||||
}
|
||||
if (low1 < low2) {
|
||||
return 1;
|
||||
} else if (low1 > low2) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
Slice EncodeTimestamp(uint64_t low, uint64_t high, std::string* ts) {
|
||||
assert(nullptr != ts);
|
||||
ts->clear();
|
||||
PutFixed64(ts, low);
|
||||
PutFixed64(ts, high);
|
||||
assert(ts->size() == sizeof(low) + sizeof(high));
|
||||
return Slice(*ts);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(DBBasicTestWithTimestampWithParam, PutAndGet) {
|
||||
const int kNumKeysPerFile = 8192;
|
||||
const size_t kNumTimestamps = 6;
|
||||
bool memtable_only = GetParam();
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.env = env_;
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
std::string tmp;
|
||||
size_t ts_sz = EncodeTimestamp(0, 0, &tmp).size();
|
||||
TestComparator test_cmp(ts_sz);
|
||||
options.comparator = &test_cmp;
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy.reset(NewBloomFilterPolicy(
|
||||
10 /*bits_per_key*/, false /*use_block_based_builder*/));
|
||||
bbto.whole_key_filtering = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
size_t num_cfs = handles_.size();
|
||||
ASSERT_EQ(2, num_cfs);
|
||||
std::vector<std::string> write_ts_strs(kNumTimestamps);
|
||||
std::vector<std::string> read_ts_strs(kNumTimestamps);
|
||||
std::vector<Slice> write_ts_list;
|
||||
std::vector<Slice> read_ts_list;
|
||||
|
||||
for (size_t i = 0; i != kNumTimestamps; ++i) {
|
||||
write_ts_list.emplace_back(EncodeTimestamp(i * 2, 0, &write_ts_strs[i]));
|
||||
read_ts_list.emplace_back(EncodeTimestamp(1 + i * 2, 0, &read_ts_strs[i]));
|
||||
const Slice& write_ts = write_ts_list.back();
|
||||
WriteOptions wopts;
|
||||
wopts.timestamp = &write_ts;
|
||||
for (int cf = 0; cf != static_cast<int>(num_cfs); ++cf) {
|
||||
for (size_t j = 0; j != (kNumKeysPerFile - 1) / kNumTimestamps; ++j) {
|
||||
ASSERT_OK(Put(cf, "key" + std::to_string(j),
|
||||
"value_" + std::to_string(j) + "_" + std::to_string(i),
|
||||
wopts));
|
||||
}
|
||||
if (!memtable_only) {
|
||||
ASSERT_OK(Flush(cf));
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto& verify_db_func = [&]() {
|
||||
for (size_t i = 0; i != kNumTimestamps; ++i) {
|
||||
ReadOptions ropts;
|
||||
ropts.timestamp = &read_ts_list[i];
|
||||
for (int cf = 0; cf != static_cast<int>(num_cfs); ++cf) {
|
||||
ColumnFamilyHandle* cfh = handles_[cf];
|
||||
for (size_t j = 0; j != (kNumKeysPerFile - 1) / kNumTimestamps; ++j) {
|
||||
std::string value;
|
||||
ASSERT_OK(db_->Get(ropts, cfh, "key" + std::to_string(j), &value));
|
||||
ASSERT_EQ("value_" + std::to_string(j) + "_" + std::to_string(i),
|
||||
value);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
verify_db_func();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Timestamp, DBBasicTestWithTimestampWithParam,
|
||||
::testing::Bool());
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
@@ -1984,7 +2210,7 @@ void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
||||
+23
-20
@@ -10,8 +10,9 @@
|
||||
#include "cache/lru_cache.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "util/compression.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DBBlockCacheTest : public DBTestBase {
|
||||
private:
|
||||
@@ -45,7 +46,7 @@ class DBBlockCacheTest : public DBTestBase {
|
||||
options.create_if_missing = true;
|
||||
options.avoid_flush_during_recovery = false;
|
||||
// options.compression = kNoCompression;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
options.table_factory.reset(new BlockBasedTableFactory(table_options));
|
||||
return options;
|
||||
}
|
||||
@@ -291,7 +292,7 @@ TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) {
|
||||
TEST_F(DBBlockCacheTest, IndexAndFilterBlocksOfNewTableAddedToCache) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
table_options.filter_policy.reset(NewBloomFilterPolicy(20));
|
||||
@@ -377,7 +378,7 @@ TEST_F(DBBlockCacheTest, FillCacheAndIterateDB) {
|
||||
TEST_F(DBBlockCacheTest, IndexAndFilterBlocksStats) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
LRUCacheOptions co;
|
||||
@@ -463,7 +464,7 @@ TEST_F(DBBlockCacheTest, IndexAndFilterBlocksCachePriority) {
|
||||
for (auto priority : {Cache::Priority::LOW, Cache::Priority::HIGH}) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
table_options.block_cache.reset(new MockCache());
|
||||
@@ -519,7 +520,7 @@ TEST_F(DBBlockCacheTest, IndexAndFilterBlocksCachePriority) {
|
||||
TEST_F(DBBlockCacheTest, ParanoidFileChecks) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.paranoid_file_checks = true;
|
||||
BlockBasedTableOptions table_options;
|
||||
@@ -575,7 +576,7 @@ TEST_F(DBBlockCacheTest, CompressedCache) {
|
||||
for (int iter = 0; iter < 4; iter++) {
|
||||
Options options = CurrentOptions();
|
||||
options.write_buffer_size = 64 * 1024; // small write buffer
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
|
||||
BlockBasedTableOptions table_options;
|
||||
switch (iter) {
|
||||
@@ -685,16 +686,18 @@ TEST_F(DBBlockCacheTest, CacheCompressionDict) {
|
||||
|
||||
// Try all the available libraries that support dictionary compression
|
||||
std::vector<CompressionType> compression_types;
|
||||
#ifdef ZLIB
|
||||
compression_types.push_back(kZlibCompression);
|
||||
#endif // ZLIB
|
||||
#if LZ4_VERSION_NUMBER >= 10400
|
||||
compression_types.push_back(kLZ4Compression);
|
||||
compression_types.push_back(kLZ4HCCompression);
|
||||
#endif // LZ4_VERSION_NUMBER >= 10400
|
||||
#if ZSTD_VERSION_NUMBER >= 500
|
||||
compression_types.push_back(kZSTD);
|
||||
#endif // ZSTD_VERSION_NUMBER >= 500
|
||||
if (Zlib_Supported()) {
|
||||
compression_types.push_back(kZlibCompression);
|
||||
}
|
||||
if (LZ4_Supported()) {
|
||||
compression_types.push_back(kLZ4Compression);
|
||||
compression_types.push_back(kLZ4HCCompression);
|
||||
}
|
||||
if (ZSTD_Supported()) {
|
||||
compression_types.push_back(kZSTD);
|
||||
} else if (ZSTDNotFinal_Supported()) {
|
||||
compression_types.push_back(kZSTDNotFinalCompression);
|
||||
}
|
||||
Random rnd(301);
|
||||
for (auto compression_type : compression_types) {
|
||||
Options options = CurrentOptions();
|
||||
@@ -702,7 +705,7 @@ TEST_F(DBBlockCacheTest, CacheCompressionDict) {
|
||||
options.compression_opts.max_dict_bytes = 4096;
|
||||
options.create_if_missing = true;
|
||||
options.num_levels = 2;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
options.target_file_size_base = kNumEntriesPerFile * kNumBytesPerEntry;
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
@@ -749,10 +752,10 @@ TEST_F(DBBlockCacheTest, CacheCompressionDict) {
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+285
-109
@@ -10,8 +10,13 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "table/block_based/filter_policy_internal.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
namespace {
|
||||
using BFP = BloomFilterPolicy;
|
||||
} // namespace
|
||||
|
||||
// DB tests related to bloom filter.
|
||||
|
||||
@@ -20,12 +25,12 @@ class DBBloomFilterTest : public DBTestBase {
|
||||
DBBloomFilterTest() : DBTestBase("/db_bloom_filter_test") {}
|
||||
};
|
||||
|
||||
class DBBloomFilterTestWithParam
|
||||
: public DBTestBase,
|
||||
public testing::WithParamInterface<std::tuple<bool, bool, uint32_t>> {
|
||||
class DBBloomFilterTestWithParam : public DBTestBase,
|
||||
public testing::WithParamInterface<
|
||||
std::tuple<BFP::Mode, bool, uint32_t>> {
|
||||
// public testing::WithParamInterface<bool> {
|
||||
protected:
|
||||
bool use_block_based_filter_;
|
||||
BFP::Mode bfp_impl_;
|
||||
bool partition_filters_;
|
||||
uint32_t format_version_;
|
||||
|
||||
@@ -35,7 +40,7 @@ class DBBloomFilterTestWithParam
|
||||
~DBBloomFilterTestWithParam() override {}
|
||||
|
||||
void SetUp() override {
|
||||
use_block_based_filter_ = std::get<0>(GetParam());
|
||||
bfp_impl_ = std::get<0>(GetParam());
|
||||
partition_filters_ = std::get<1>(GetParam());
|
||||
format_version_ = std::get<2>(GetParam());
|
||||
}
|
||||
@@ -71,8 +76,7 @@ TEST_P(DBBloomFilterTestDefFormatVersion, KeyMayExist) {
|
||||
ReadOptions ropts;
|
||||
std::string value;
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.filter_policy.reset(
|
||||
NewBloomFilterPolicy(20, use_block_based_filter_));
|
||||
options_override.filter_policy.reset(new BFP(20, bfp_impl_));
|
||||
options_override.partition_filters = partition_filters_;
|
||||
options_override.metadata_block_size = 32;
|
||||
Options options = CurrentOptions(options_override);
|
||||
@@ -84,7 +88,7 @@ TEST_P(DBBloomFilterTestDefFormatVersion, KeyMayExist) {
|
||||
// indexes
|
||||
continue;
|
||||
}
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
ASSERT_TRUE(!db_->KeyMayExist(ropts, handles_[1], "a", &value));
|
||||
@@ -146,7 +150,7 @@ TEST_F(DBBloomFilterTest, GetFilterByPrefixBloomCustomPrefixExtractor) {
|
||||
Options options = last_options_;
|
||||
options.prefix_extractor =
|
||||
std::make_shared<SliceTransformLimitedDomainGeneric>();
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
get_perf_context()->EnablePerLevelPerfContext();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||
@@ -212,7 +216,7 @@ TEST_F(DBBloomFilterTest, GetFilterByPrefixBloom) {
|
||||
for (bool partition_filters : {true, false}) {
|
||||
Options options = last_options_;
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(8));
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
get_perf_context()->EnablePerLevelPerfContext();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||
@@ -263,7 +267,7 @@ TEST_F(DBBloomFilterTest, WholeKeyFilterProp) {
|
||||
for (bool partition_filters : {true, false}) {
|
||||
Options options = last_options_;
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(3));
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
get_perf_context()->EnablePerLevelPerfContext();
|
||||
|
||||
BlockBasedTableOptions bbto;
|
||||
@@ -432,8 +436,7 @@ TEST_P(DBBloomFilterTestWithParam, BloomFilter) {
|
||||
// trigger reset of table_factory
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.no_block_cache = true;
|
||||
table_options.filter_policy.reset(
|
||||
NewBloomFilterPolicy(10, use_block_based_filter_));
|
||||
table_options.filter_policy.reset(new BFP(10, bfp_impl_));
|
||||
table_options.partition_filters = partition_filters_;
|
||||
if (partition_filters_) {
|
||||
table_options.index_type =
|
||||
@@ -502,30 +505,33 @@ TEST_P(DBBloomFilterTestWithParam, BloomFilter) {
|
||||
#ifndef ROCKSDB_VALGRIND_RUN
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FormatDef, DBBloomFilterTestDefFormatVersion,
|
||||
::testing::Values(std::make_tuple(true, false, test::kDefaultFormatVersion),
|
||||
std::make_tuple(false, true, test::kDefaultFormatVersion),
|
||||
std::make_tuple(false, false,
|
||||
test::kDefaultFormatVersion)));
|
||||
::testing::Values(
|
||||
std::make_tuple(BFP::kDeprecatedBlock, false,
|
||||
test::kDefaultFormatVersion),
|
||||
std::make_tuple(BFP::kAuto, true, test::kDefaultFormatVersion),
|
||||
std::make_tuple(BFP::kAuto, false, test::kDefaultFormatVersion)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FormatDef, DBBloomFilterTestWithParam,
|
||||
::testing::Values(std::make_tuple(true, false, test::kDefaultFormatVersion),
|
||||
std::make_tuple(false, true, test::kDefaultFormatVersion),
|
||||
std::make_tuple(false, false,
|
||||
test::kDefaultFormatVersion)));
|
||||
::testing::Values(
|
||||
std::make_tuple(BFP::kDeprecatedBlock, false,
|
||||
test::kDefaultFormatVersion),
|
||||
std::make_tuple(BFP::kAuto, true, test::kDefaultFormatVersion),
|
||||
std::make_tuple(BFP::kAuto, false, test::kDefaultFormatVersion)));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FormatLatest, DBBloomFilterTestWithParam,
|
||||
::testing::Values(std::make_tuple(true, false, test::kLatestFormatVersion),
|
||||
std::make_tuple(false, true, test::kLatestFormatVersion),
|
||||
std::make_tuple(false, false,
|
||||
test::kLatestFormatVersion)));
|
||||
::testing::Values(
|
||||
std::make_tuple(BFP::kDeprecatedBlock, false,
|
||||
test::kLatestFormatVersion),
|
||||
std::make_tuple(BFP::kAuto, true, test::kLatestFormatVersion),
|
||||
std::make_tuple(BFP::kAuto, false, test::kLatestFormatVersion)));
|
||||
#endif // ROCKSDB_VALGRIND_RUN
|
||||
|
||||
TEST_F(DBBloomFilterTest, BloomFilterRate) {
|
||||
while (ChangeFilterOptions()) {
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
get_perf_context()->EnablePerLevelPerfContext();
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
@@ -557,7 +563,7 @@ TEST_F(DBBloomFilterTest, BloomFilterRate) {
|
||||
|
||||
TEST_F(DBBloomFilterTest, BloomFilterCompatibility) {
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.filter_policy.reset(NewBloomFilterPolicy(10, true));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
@@ -601,7 +607,7 @@ TEST_F(DBBloomFilterTest, BloomFilterCompatibility) {
|
||||
TEST_F(DBBloomFilterTest, BloomFilterReverseCompatibility) {
|
||||
for (bool partition_filters : {true, false}) {
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
BlockBasedTableOptions table_options;
|
||||
if (partition_filters) {
|
||||
table_options.partition_filters = true;
|
||||
@@ -636,27 +642,30 @@ TEST_F(DBBloomFilterTest, BloomFilterReverseCompatibility) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
// A wrapped bloom over default FilterPolicy
|
||||
class WrappedBloom : public FilterPolicy {
|
||||
// A wrapped bloom over block-based FilterPolicy
|
||||
class TestingWrappedBlockBasedFilterPolicy : public FilterPolicy {
|
||||
public:
|
||||
explicit WrappedBloom(int bits_per_key)
|
||||
: filter_(NewBloomFilterPolicy(bits_per_key)), counter_(0) {}
|
||||
explicit TestingWrappedBlockBasedFilterPolicy(int bits_per_key)
|
||||
: filter_(NewBloomFilterPolicy(bits_per_key, true)), counter_(0) {}
|
||||
|
||||
~WrappedBloom() override { delete filter_; }
|
||||
~TestingWrappedBlockBasedFilterPolicy() override { delete filter_; }
|
||||
|
||||
const char* Name() const override { return "WrappedRocksDbFilterPolicy"; }
|
||||
const char* Name() const override {
|
||||
return "TestingWrappedBlockBasedFilterPolicy";
|
||||
}
|
||||
|
||||
void CreateFilter(const rocksdb::Slice* keys, int n,
|
||||
void CreateFilter(const ROCKSDB_NAMESPACE::Slice* keys, int n,
|
||||
std::string* dst) const override {
|
||||
std::unique_ptr<rocksdb::Slice[]> user_keys(new rocksdb::Slice[n]);
|
||||
std::unique_ptr<ROCKSDB_NAMESPACE::Slice[]> user_keys(
|
||||
new ROCKSDB_NAMESPACE::Slice[n]);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
user_keys[i] = convertKey(keys[i]);
|
||||
}
|
||||
return filter_->CreateFilter(user_keys.get(), n, dst);
|
||||
}
|
||||
|
||||
bool KeyMayMatch(const rocksdb::Slice& key,
|
||||
const rocksdb::Slice& filter) const override {
|
||||
bool KeyMayMatch(const ROCKSDB_NAMESPACE::Slice& key,
|
||||
const ROCKSDB_NAMESPACE::Slice& filter) const override {
|
||||
counter_++;
|
||||
return filter_->KeyMayMatch(convertKey(key), filter);
|
||||
}
|
||||
@@ -667,16 +676,20 @@ class WrappedBloom : public FilterPolicy {
|
||||
const FilterPolicy* filter_;
|
||||
mutable uint32_t counter_;
|
||||
|
||||
rocksdb::Slice convertKey(const rocksdb::Slice& key) const { return key; }
|
||||
ROCKSDB_NAMESPACE::Slice convertKey(
|
||||
const ROCKSDB_NAMESPACE::Slice& key) const {
|
||||
return key;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_F(DBBloomFilterTest, BloomFilterWrapper) {
|
||||
TEST_F(DBBloomFilterTest, WrappedBlockBasedFilterPolicy) {
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
|
||||
BlockBasedTableOptions table_options;
|
||||
WrappedBloom* policy = new WrappedBloom(10);
|
||||
TestingWrappedBlockBasedFilterPolicy* policy =
|
||||
new TestingWrappedBlockBasedFilterPolicy(10);
|
||||
table_options.filter_policy.reset(policy);
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
|
||||
@@ -706,6 +719,166 @@ TEST_F(DBBloomFilterTest, BloomFilterWrapper) {
|
||||
ASSERT_EQ(2U * maxKey, policy->GetCounter());
|
||||
}
|
||||
|
||||
namespace {
|
||||
// NOTE: This class is referenced by HISTORY.md as a model for a wrapper
|
||||
// FilterPolicy selecting among configurations based on context.
|
||||
class LevelAndStyleCustomFilterPolicy : public FilterPolicy {
|
||||
public:
|
||||
explicit LevelAndStyleCustomFilterPolicy(int bpk_fifo, int bpk_l0_other,
|
||||
int bpk_otherwise)
|
||||
: policy_fifo_(NewBloomFilterPolicy(bpk_fifo)),
|
||||
policy_l0_other_(NewBloomFilterPolicy(bpk_l0_other)),
|
||||
policy_otherwise_(NewBloomFilterPolicy(bpk_otherwise)) {}
|
||||
|
||||
// OK to use built-in policy name because we are deferring to a
|
||||
// built-in builder. We aren't changing the serialized format.
|
||||
const char* Name() const override { return policy_fifo_->Name(); }
|
||||
|
||||
FilterBitsBuilder* GetBuilderWithContext(
|
||||
const FilterBuildingContext& context) const override {
|
||||
if (context.compaction_style == kCompactionStyleFIFO) {
|
||||
return policy_fifo_->GetBuilderWithContext(context);
|
||||
} else if (context.level_at_creation == 0) {
|
||||
return policy_l0_other_->GetBuilderWithContext(context);
|
||||
} else {
|
||||
return policy_otherwise_->GetBuilderWithContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
FilterBitsReader* GetFilterBitsReader(const Slice& contents) const override {
|
||||
// OK to defer to any of them; they all can parse built-in filters
|
||||
// from any settings.
|
||||
return policy_fifo_->GetFilterBitsReader(contents);
|
||||
}
|
||||
|
||||
// Defer just in case configuration uses block-based filter
|
||||
void CreateFilter(const Slice* keys, int n, std::string* dst) const override {
|
||||
policy_otherwise_->CreateFilter(keys, n, dst);
|
||||
}
|
||||
bool KeyMayMatch(const Slice& key, const Slice& filter) const override {
|
||||
return policy_otherwise_->KeyMayMatch(key, filter);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::unique_ptr<const FilterPolicy> policy_fifo_;
|
||||
const std::unique_ptr<const FilterPolicy> policy_l0_other_;
|
||||
const std::unique_ptr<const FilterPolicy> policy_otherwise_;
|
||||
};
|
||||
|
||||
class TestingContextCustomFilterPolicy
|
||||
: public LevelAndStyleCustomFilterPolicy {
|
||||
public:
|
||||
explicit TestingContextCustomFilterPolicy(int bpk_fifo, int bpk_l0_other,
|
||||
int bpk_otherwise)
|
||||
: LevelAndStyleCustomFilterPolicy(bpk_fifo, bpk_l0_other, bpk_otherwise) {
|
||||
}
|
||||
|
||||
FilterBitsBuilder* GetBuilderWithContext(
|
||||
const FilterBuildingContext& context) const override {
|
||||
test_report_ += "cf=";
|
||||
test_report_ += context.column_family_name;
|
||||
test_report_ += ",cs=";
|
||||
test_report_ +=
|
||||
OptionsHelper::compaction_style_to_string[context.compaction_style];
|
||||
test_report_ += ",lv=";
|
||||
test_report_ += std::to_string(context.level_at_creation);
|
||||
test_report_ += "\n";
|
||||
|
||||
return LevelAndStyleCustomFilterPolicy::GetBuilderWithContext(context);
|
||||
}
|
||||
|
||||
std::string DumpTestReport() {
|
||||
std::string rv;
|
||||
std::swap(rv, test_report_);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::string test_report_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_F(DBBloomFilterTest, ContextCustomFilterPolicy) {
|
||||
for (bool fifo : {true, false}) {
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
options.compaction_style =
|
||||
fifo ? kCompactionStyleFIFO : kCompactionStyleLevel;
|
||||
|
||||
BlockBasedTableOptions table_options;
|
||||
auto policy = std::make_shared<TestingContextCustomFilterPolicy>(15, 8, 5);
|
||||
table_options.filter_policy = policy;
|
||||
table_options.format_version = 5;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
|
||||
CreateAndReopenWithCF({fifo ? "abe" : "bob"}, options);
|
||||
|
||||
const int maxKey = 10000;
|
||||
for (int i = 0; i < maxKey / 2; i++) {
|
||||
ASSERT_OK(Put(1, Key(i), Key(i)));
|
||||
}
|
||||
// Add a large key to make the file contain wide range
|
||||
ASSERT_OK(Put(1, Key(maxKey + 55555), Key(maxKey + 55555)));
|
||||
Flush(1);
|
||||
EXPECT_EQ(policy->DumpTestReport(),
|
||||
fifo ? "cf=abe,cs=kCompactionStyleFIFO,lv=0\n"
|
||||
: "cf=bob,cs=kCompactionStyleLevel,lv=0\n");
|
||||
|
||||
for (int i = maxKey / 2; i < maxKey; i++) {
|
||||
ASSERT_OK(Put(1, Key(i), Key(i)));
|
||||
}
|
||||
Flush(1);
|
||||
EXPECT_EQ(policy->DumpTestReport(),
|
||||
fifo ? "cf=abe,cs=kCompactionStyleFIFO,lv=0\n"
|
||||
: "cf=bob,cs=kCompactionStyleLevel,lv=0\n");
|
||||
|
||||
// Check that they can be found
|
||||
for (int i = 0; i < maxKey; i++) {
|
||||
ASSERT_EQ(Key(i), Get(1, Key(i)));
|
||||
}
|
||||
// Since we have two tables / two filters, we might have Bloom checks on
|
||||
// our queries, but no more than one "useful" per query on a found key.
|
||||
EXPECT_LE(TestGetAndResetTickerCount(options, BLOOM_FILTER_USEFUL), maxKey);
|
||||
|
||||
// Check that we have two filters, each about
|
||||
// fifo: 0.12% FP rate (15 bits per key)
|
||||
// level: 2.3% FP rate (8 bits per key)
|
||||
for (int i = 0; i < maxKey; i++) {
|
||||
ASSERT_EQ("NOT_FOUND", Get(1, Key(i + 33333)));
|
||||
}
|
||||
{
|
||||
auto useful_count =
|
||||
TestGetAndResetTickerCount(options, BLOOM_FILTER_USEFUL);
|
||||
EXPECT_GE(useful_count, maxKey * 2 * (fifo ? 0.9980 : 0.975));
|
||||
EXPECT_LE(useful_count, maxKey * 2 * (fifo ? 0.9995 : 0.98));
|
||||
}
|
||||
|
||||
if (!fifo) { // FIFO only has L0
|
||||
// Full compaction
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), handles_[1], nullptr,
|
||||
nullptr));
|
||||
EXPECT_EQ(policy->DumpTestReport(),
|
||||
"cf=bob,cs=kCompactionStyleLevel,lv=1\n");
|
||||
|
||||
// Check that we now have one filter, about 9.2% FP rate (5 bits per key)
|
||||
for (int i = 0; i < maxKey; i++) {
|
||||
ASSERT_EQ("NOT_FOUND", Get(1, Key(i + 33333)));
|
||||
}
|
||||
{
|
||||
auto useful_count =
|
||||
TestGetAndResetTickerCount(options, BLOOM_FILTER_USEFUL);
|
||||
EXPECT_GE(useful_count, maxKey * 0.90);
|
||||
EXPECT_LE(useful_count, maxKey * 0.91);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy
|
||||
ASSERT_OK(dbfull()->DropColumnFamily(handles_[1]));
|
||||
dbfull()->DestroyColumnFamilyHandle(handles_[1]);
|
||||
handles_[1] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
class SliceTransformLimitedDomain : public SliceTransform {
|
||||
const char* Name() const override { return "SliceTransformLimitedDomain"; }
|
||||
|
||||
@@ -727,7 +900,7 @@ class SliceTransformLimitedDomain : public SliceTransform {
|
||||
TEST_F(DBBloomFilterTest, PrefixExtractorFullFilter) {
|
||||
BlockBasedTableOptions bbto;
|
||||
// Full Filter Block
|
||||
bbto.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, false));
|
||||
bbto.filter_policy.reset(ROCKSDB_NAMESPACE::NewBloomFilterPolicy(10, false));
|
||||
bbto.whole_key_filtering = false;
|
||||
|
||||
Options options = CurrentOptions();
|
||||
@@ -756,7 +929,7 @@ TEST_F(DBBloomFilterTest, PrefixExtractorFullFilter) {
|
||||
TEST_F(DBBloomFilterTest, PrefixExtractorBlockFilter) {
|
||||
BlockBasedTableOptions bbto;
|
||||
// Block Filter Block
|
||||
bbto.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, true));
|
||||
bbto.filter_policy.reset(ROCKSDB_NAMESPACE::NewBloomFilterPolicy(10, true));
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.prefix_extractor = std::make_shared<SliceTransformLimitedDomain>();
|
||||
@@ -795,7 +968,8 @@ TEST_F(DBBloomFilterTest, MemtableWholeKeyBloomFilter) {
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_prefix_bloom_size_ratio =
|
||||
static_cast<double>(kMemtablePrefixFilterSize) / kMemtableSize;
|
||||
options.prefix_extractor.reset(rocksdb::NewFixedPrefixTransform(kPrefixLen));
|
||||
options.prefix_extractor.reset(
|
||||
ROCKSDB_NAMESPACE::NewFixedPrefixTransform(kPrefixLen));
|
||||
options.write_buffer_size = kMemtableSize;
|
||||
options.memtable_whole_key_filtering = false;
|
||||
Reopen(options);
|
||||
@@ -856,35 +1030,43 @@ TEST_F(DBBloomFilterTest, MemtablePrefixBloomOutOfDomain) {
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace {
|
||||
namespace BFP2 {
|
||||
// Extends BFP::Mode with option to use Plain table
|
||||
using PseudoMode = int;
|
||||
static constexpr PseudoMode kPlainTable = -1;
|
||||
} // namespace BFP2
|
||||
} // namespace
|
||||
|
||||
class BloomStatsTestWithParam
|
||||
: public DBBloomFilterTest,
|
||||
public testing::WithParamInterface<std::tuple<bool, bool, bool>> {
|
||||
public testing::WithParamInterface<std::tuple<BFP2::PseudoMode, bool>> {
|
||||
public:
|
||||
BloomStatsTestWithParam() {
|
||||
use_block_table_ = std::get<0>(GetParam());
|
||||
use_block_based_builder_ = std::get<1>(GetParam());
|
||||
partition_filters_ = std::get<2>(GetParam());
|
||||
bfp_impl_ = std::get<0>(GetParam());
|
||||
partition_filters_ = std::get<1>(GetParam());
|
||||
|
||||
options_.create_if_missing = true;
|
||||
options_.prefix_extractor.reset(rocksdb::NewFixedPrefixTransform(4));
|
||||
options_.prefix_extractor.reset(
|
||||
ROCKSDB_NAMESPACE::NewFixedPrefixTransform(4));
|
||||
options_.memtable_prefix_bloom_size_ratio =
|
||||
8.0 * 1024.0 / static_cast<double>(options_.write_buffer_size);
|
||||
if (use_block_table_) {
|
||||
if (bfp_impl_ == BFP2::kPlainTable) {
|
||||
assert(!partition_filters_); // not supported in plain table
|
||||
PlainTableOptions table_options;
|
||||
options_.table_factory.reset(NewPlainTableFactory(table_options));
|
||||
} else {
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.hash_index_allow_collision = false;
|
||||
if (partition_filters_) {
|
||||
assert(!use_block_based_builder_);
|
||||
assert(bfp_impl_ != BFP::kDeprecatedBlock);
|
||||
table_options.partition_filters = partition_filters_;
|
||||
table_options.index_type =
|
||||
BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch;
|
||||
}
|
||||
table_options.filter_policy.reset(
|
||||
NewBloomFilterPolicy(10, use_block_based_builder_));
|
||||
new BFP(10, static_cast<BFP::Mode>(bfp_impl_)));
|
||||
options_.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
} else {
|
||||
assert(!partition_filters_); // not supported in plain table
|
||||
PlainTableOptions table_options;
|
||||
options_.table_factory.reset(NewPlainTableFactory(table_options));
|
||||
}
|
||||
options_.env = env_;
|
||||
|
||||
@@ -901,8 +1083,7 @@ class BloomStatsTestWithParam
|
||||
static void SetUpTestCase() {}
|
||||
static void TearDownTestCase() {}
|
||||
|
||||
bool use_block_table_;
|
||||
bool use_block_based_builder_;
|
||||
BFP2::PseudoMode bfp_impl_;
|
||||
bool partition_filters_;
|
||||
Options options_;
|
||||
};
|
||||
@@ -1006,7 +1187,7 @@ TEST_P(BloomStatsTestWithParam, BloomStatsTestWithIter) {
|
||||
ASSERT_EQ(value3, iter->value().ToString());
|
||||
// The seek doesn't check block-based bloom filter because last index key
|
||||
// starts with the same prefix we're seeking to.
|
||||
uint64_t expected_hits = use_block_based_builder_ ? 1 : 2;
|
||||
uint64_t expected_hits = bfp_impl_ == BFP::kDeprecatedBlock ? 1 : 2;
|
||||
ASSERT_EQ(expected_hits, get_perf_context()->bloom_sst_hit_count);
|
||||
|
||||
iter->Seek(key2);
|
||||
@@ -1016,12 +1197,14 @@ TEST_P(BloomStatsTestWithParam, BloomStatsTestWithIter) {
|
||||
ASSERT_EQ(expected_hits, get_perf_context()->bloom_sst_hit_count);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BloomStatsTestWithParam, BloomStatsTestWithParam,
|
||||
::testing::Values(std::make_tuple(true, true, false),
|
||||
std::make_tuple(true, false, false),
|
||||
std::make_tuple(true, false, true),
|
||||
std::make_tuple(false, false,
|
||||
false)));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
BloomStatsTestWithParam, BloomStatsTestWithParam,
|
||||
::testing::Values(std::make_tuple(BFP::kDeprecatedBlock, false),
|
||||
std::make_tuple(BFP::kLegacyBloom, false),
|
||||
std::make_tuple(BFP::kLegacyBloom, true),
|
||||
std::make_tuple(BFP::kFastLocalBloom, false),
|
||||
std::make_tuple(BFP::kFastLocalBloom, true),
|
||||
std::make_tuple(BFP2::kPlainTable, false)));
|
||||
|
||||
namespace {
|
||||
void PrefixScanInit(DBBloomFilterTest* dbtest) {
|
||||
@@ -1146,7 +1329,8 @@ TEST_F(DBBloomFilterTest, OptimizeFiltersForHits) {
|
||||
bbto.whole_key_filtering = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
options.optimize_filters_for_hits = true;
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
get_perf_context()->Reset();
|
||||
get_perf_context()->EnablePerLevelPerfContext();
|
||||
CreateAndReopenWithCF({"mypikachu"}, options);
|
||||
|
||||
@@ -1271,13 +1455,13 @@ TEST_F(DBBloomFilterTest, OptimizeFiltersForHits) {
|
||||
|
||||
int32_t trivial_move = 0;
|
||||
int32_t non_trivial_move = 0;
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:TrivialMove",
|
||||
[&](void* /*arg*/) { trivial_move++; });
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial",
|
||||
[&](void* /*arg*/) { non_trivial_move++; });
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.bottommost_level_compaction =
|
||||
@@ -1328,8 +1512,8 @@ int CountIter(std::unique_ptr<Iterator>& iter, const Slice& key) {
|
||||
// into the same string, or 2) the transformed seek key is of the same length
|
||||
// as the upper bound and two keys are adjacent according to the comparator.
|
||||
TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
int iteration = 0;
|
||||
for (bool use_block_based_builder : {true, false}) {
|
||||
for (auto bfp_impl : BFP::kAllFixedImpls) {
|
||||
int using_full_builder = bfp_impl != BFP::kDeprecatedBlock;
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.prefix_extractor.reset(NewCappedPrefixTransform(4));
|
||||
@@ -1338,8 +1522,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
// Enable prefix bloom for SST files
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
table_options.filter_policy.reset(
|
||||
NewBloomFilterPolicy(10, use_block_based_builder));
|
||||
table_options.filter_policy.reset(new BFP(10, bfp_impl));
|
||||
table_options.index_shortening = BlockBasedTableOptions::
|
||||
IndexShorteningMode::kShortenSeparatorsAndSuccessor;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
@@ -1382,7 +1565,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
ASSERT_EQ(CountIter(iter, "abcdxx00"), 4);
|
||||
// should check bloom filter since upper bound meets requirement
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
2 + iteration);
|
||||
2 + using_full_builder);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
}
|
||||
{
|
||||
@@ -1396,7 +1579,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
ASSERT_EQ(CountIter(iter, "abcdxx01"), 4);
|
||||
// should skip bloom filter since upper bound is too long
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
2 + iteration);
|
||||
2 + using_full_builder);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
}
|
||||
{
|
||||
@@ -1410,7 +1593,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
// should check bloom filter since upper bound matches transformed seek
|
||||
// key
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
2 + iteration * 2);
|
||||
2 + using_full_builder * 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
}
|
||||
{
|
||||
@@ -1424,7 +1607,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
ASSERT_EQ(CountIter(iter, "aaaaaaaa"), 0);
|
||||
// should skip bloom filter since mismatch is found
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
2 + iteration * 2);
|
||||
2 + using_full_builder * 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
}
|
||||
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "fixed:3"}}));
|
||||
@@ -1438,7 +1621,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_EQ(CountIter(iter, "abc"), 4);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
2 + iteration * 2);
|
||||
2 + using_full_builder * 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
}
|
||||
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "capped:4"}}));
|
||||
@@ -1451,18 +1634,17 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterUpperBound) {
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_EQ(CountIter(iter, "abc"), 0);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
3 + iteration * 2);
|
||||
3 + using_full_builder * 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 1);
|
||||
}
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create multiple SST files each with a different prefix_extractor config,
|
||||
// verify iterators can read all SST files using the latest config.
|
||||
TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
int iteration = 0;
|
||||
for (bool use_block_based_builder : {true, false}) {
|
||||
for (auto bfp_impl : BFP::kAllFixedImpls) {
|
||||
int using_full_builder = bfp_impl != BFP::kDeprecatedBlock;
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
|
||||
@@ -1470,8 +1652,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
options.statistics = CreateDBStatistics();
|
||||
// Enable prefix bloom for SST files
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.filter_policy.reset(
|
||||
NewBloomFilterPolicy(10, use_block_based_builder));
|
||||
table_options.filter_policy.reset(new BFP(10, bfp_impl));
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
DestroyAndReopen(options);
|
||||
@@ -1497,10 +1678,10 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_EQ(CountIter(iter, "foo"), 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
1 + iteration);
|
||||
1 + using_full_builder);
|
||||
ASSERT_EQ(CountIter(iter, "gpk"), 0);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
1 + iteration);
|
||||
1 + using_full_builder);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
|
||||
// second SST with capped:3 BF
|
||||
@@ -1514,13 +1695,13 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
std::unique_ptr<Iterator> iter_tmp(db_->NewIterator(read_options));
|
||||
ASSERT_EQ(CountIter(iter_tmp, "foo"), 4);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
2 + iteration * 2);
|
||||
2 + using_full_builder * 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 0);
|
||||
ASSERT_EQ(CountIter(iter_tmp, "gpk"), 0);
|
||||
// both counters are incremented because BF is "not changed" for 1 of the
|
||||
// 2 SST files, so filter is checked once and found no match.
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
3 + iteration * 2);
|
||||
3 + using_full_builder * 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 1);
|
||||
}
|
||||
|
||||
@@ -1539,24 +1720,24 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
ASSERT_EQ(CountIter(iter_tmp, "foo"), 9);
|
||||
// the first and last BF are checked
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
4 + iteration * 3);
|
||||
4 + using_full_builder * 3);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 1);
|
||||
ASSERT_EQ(CountIter(iter_tmp, "gpk"), 0);
|
||||
// only last BF is checked and not found
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
5 + iteration * 3);
|
||||
5 + using_full_builder * 3);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 2);
|
||||
}
|
||||
|
||||
// iter_old can only see the first SST, so checked plus 1
|
||||
ASSERT_EQ(CountIter(iter_old, "foo"), 4);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
6 + iteration * 3);
|
||||
6 + using_full_builder * 3);
|
||||
// iter was created after the first setoptions call so only full filter
|
||||
// will check the filter
|
||||
ASSERT_EQ(CountIter(iter, "foo"), 2);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
6 + iteration * 4);
|
||||
6 + using_full_builder * 4);
|
||||
|
||||
{
|
||||
// keys in all three SSTs are visible to iterator
|
||||
@@ -1565,11 +1746,11 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
std::unique_ptr<Iterator> iter_all(db_->NewIterator(read_options));
|
||||
ASSERT_EQ(CountIter(iter_all, "foo"), 9);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
7 + iteration * 5);
|
||||
7 + using_full_builder * 5);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 2);
|
||||
ASSERT_EQ(CountIter(iter_all, "gpk"), 0);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
8 + iteration * 5);
|
||||
8 + using_full_builder * 5);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 3);
|
||||
}
|
||||
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "capped:3"}}));
|
||||
@@ -1581,15 +1762,14 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
// all three SST are checked because the current options has the same as
|
||||
// the remaining SST (capped:3)
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
9 + iteration * 7);
|
||||
9 + using_full_builder * 7);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 3);
|
||||
ASSERT_EQ(CountIter(iter_all, "gpk"), 0);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED),
|
||||
10 + iteration * 7);
|
||||
10 + using_full_builder * 7);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 4);
|
||||
}
|
||||
// TODO(Zhongyi): Maybe also need to add Get calls to test point look up?
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1598,7 +1778,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterMultipleSST) {
|
||||
// as expected
|
||||
TEST_F(DBBloomFilterTest, DynamicBloomFilterNewColumnFamily) {
|
||||
int iteration = 0;
|
||||
for (bool use_block_based_builder : {true, false}) {
|
||||
for (auto bfp_impl : BFP::kAllFixedImpls) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
|
||||
@@ -1607,8 +1787,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterNewColumnFamily) {
|
||||
// Enable prefix bloom for SST files
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
table_options.filter_policy.reset(
|
||||
NewBloomFilterPolicy(10, use_block_based_builder));
|
||||
table_options.filter_policy.reset(new BFP(10, bfp_impl));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
CreateAndReopenWithCF({"pikachu" + std::to_string(iteration)}, options);
|
||||
ReadOptions read_options;
|
||||
@@ -1657,8 +1836,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterNewColumnFamily) {
|
||||
// Verify it's possible to change prefix_extractor at runtime and iterators
|
||||
// behaves as expected
|
||||
TEST_F(DBBloomFilterTest, DynamicBloomFilterOptions) {
|
||||
int iteration = 0;
|
||||
for (bool use_block_based_builder : {true, false}) {
|
||||
for (auto bfp_impl : BFP::kAllFixedImpls) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
|
||||
@@ -1667,8 +1845,7 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterOptions) {
|
||||
// Enable prefix bloom for SST files
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.cache_index_and_filter_blocks = true;
|
||||
table_options.filter_policy.reset(
|
||||
NewBloomFilterPolicy(10, use_block_based_builder));
|
||||
table_options.filter_policy.reset(new BFP(10, bfp_impl));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
DestroyAndReopen(options);
|
||||
|
||||
@@ -1719,16 +1896,15 @@ TEST_F(DBBloomFilterTest, DynamicBloomFilterOptions) {
|
||||
ASSERT_EQ(CountIter(iter_old, "abc"), 0);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED), 12);
|
||||
ASSERT_EQ(TestGetTickerCount(options, BLOOM_FILTER_PREFIX_USEFUL), 3);
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
static int cfilter_count = 0;
|
||||
static int cfilter_skips = 0;
|
||||
@@ -47,8 +47,7 @@ class DBTestCompactionFilterWithCompactParam
|
||||
|
||||
#ifndef ROCKSDB_VALGRIND_RUN
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
DBTestCompactionFilterWithCompactOption,
|
||||
DBTestCompactionFilterWithCompactParam,
|
||||
CompactionFilterWithOption, DBTestCompactionFilterWithCompactParam,
|
||||
::testing::Values(DBTestBase::OptionConfig::kDefault,
|
||||
DBTestBase::OptionConfig::kUniversalCompaction,
|
||||
DBTestBase::OptionConfig::kUniversalCompactionMultiLevel,
|
||||
@@ -56,7 +55,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
DBTestBase::OptionConfig::kUniversalSubcompactions));
|
||||
#else
|
||||
// Run fewer cases in valgrind
|
||||
INSTANTIATE_TEST_CASE_P(DBTestCompactionFilterWithCompactOption,
|
||||
INSTANTIATE_TEST_CASE_P(CompactionFilterWithOption,
|
||||
DBTestCompactionFilterWithCompactParam,
|
||||
::testing::Values(DBTestBase::OptionConfig::kDefault));
|
||||
#endif // ROCKSDB_VALGRIND_RUN
|
||||
@@ -864,10 +863,10 @@ TEST_F(DBTestCompactionFilter, IgnoreSnapshotsFalse) {
|
||||
delete options.compaction_filter;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+694
-201
File diff suppressed because it is too large.
Load diff
+20
-20
@@ -16,7 +16,7 @@
|
||||
#include "port/port.h"
|
||||
#include "port/stack_trace.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class DBTestDynamicLevel : public DBTestBase {
|
||||
public:
|
||||
DBTestDynamicLevel() : DBTestBase("/db_dynamic_level_test") {}
|
||||
@@ -221,10 +221,10 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
|
||||
// Make sure that the compaction starts before the last bit of data is
|
||||
// flushed, so that the base level isn't raised to L1.
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"CompactionJob::Run():Start", "DynamicLevelMaxBytesBase2:0"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
@@ -235,20 +235,20 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(2U, int_prop);
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
// Write more data until the base level changes to L1. There will be
|
||||
// a manual compaction going on at the same time.
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"CompactionJob::Run():Start", "DynamicLevelMaxBytesBase2:1"},
|
||||
{"DynamicLevelMaxBytesBase2:2", "CompactionJob::Run():End"},
|
||||
{"DynamicLevelMaxBytesBase2:compact_range_finish",
|
||||
"FlushJob::WriteLevel0Table"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
rocksdb::port::Thread thread([this] {
|
||||
ROCKSDB_NAMESPACE::port::Thread thread([this] {
|
||||
TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:compact_range_start");
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:compact_range_finish");
|
||||
@@ -265,8 +265,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
|
||||
thread.join();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(1U, int_prop);
|
||||
@@ -329,16 +329,16 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level2", &str_prop));
|
||||
ASSERT_EQ("0", str_prop);
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
std::set<int> output_levels;
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"CompactionPicker::CompactRange:Return", [&](void* arg) {
|
||||
Compaction* compaction = reinterpret_cast<Compaction*>(arg);
|
||||
output_levels.insert(compaction->output_level());
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_EQ(output_levels.size(), 2);
|
||||
@@ -373,10 +373,10 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBaseInc) {
|
||||
DestroyAndReopen(options);
|
||||
|
||||
int non_trivial = 0;
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:NonTrivial",
|
||||
[&](void* /*arg*/) { non_trivial++; });
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Random rnd(301);
|
||||
const int total_keys = 3000;
|
||||
@@ -388,7 +388,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBaseInc) {
|
||||
}
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
ASSERT_EQ(non_trivial, 0);
|
||||
|
||||
@@ -457,7 +457,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
compaction_finished = false;
|
||||
// Issue manual compaction in one thread and still verify DB state
|
||||
// in main thread.
|
||||
rocksdb::port::Thread t([&]() {
|
||||
ROCKSDB_NAMESPACE::port::Thread t([&]() {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = options.num_levels - 1;
|
||||
@@ -488,13 +488,13 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1), 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(2), 0);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // !defined(ROCKSDB_LITE)
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DBEncryptionTest : public DBTestBase {
|
||||
public:
|
||||
@@ -113,10 +113,10 @@ TEST_F(DBEncryptionTest, ReadEmptyFile) {
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
Status DBImpl::DisableFileDeletions() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
@@ -102,7 +102,7 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
|
||||
TEST_SYNC_POINT("DBImpl::GetLiveFiles:1");
|
||||
TEST_SYNC_POINT("DBImpl::GetLiveFiles:2");
|
||||
mutex_.Lock();
|
||||
cfd->Unref();
|
||||
cfd->UnrefAndTryDelete();
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
@@ -172,6 +172,6 @@ Status DBImpl::GetCurrentWalFile(std::unique_ptr<LogFile>* current_log_file) {
|
||||
|
||||
return wal_manager_.GetLiveWalFile(current_logfile_number, current_log_file);
|
||||
}
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
+152
-3
@@ -7,12 +7,18 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "db/db_impl/db_impl.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/port.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/fault_injection_test_env.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DBFlushTest : public DBTestBase {
|
||||
public:
|
||||
@@ -206,6 +212,30 @@ TEST_F(DBFlushTest, ManualFlushWithMinWriteBufferNumberToMerge) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
TEST_F(DBFlushTest, ScheduleOnlyOneBgThread) {
|
||||
Options options = CurrentOptions();
|
||||
Reopen(options);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
int called = 0;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::MaybeScheduleFlushOrCompaction:AfterSchedule:0", [&](void* arg) {
|
||||
ASSERT_NE(nullptr, arg);
|
||||
auto unscheduled_flushes = *reinterpret_cast<int*>(arg);
|
||||
ASSERT_EQ(0, unscheduled_flushes);
|
||||
++called;
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(Put("a", "foo"));
|
||||
FlushOptions flush_opts;
|
||||
ASSERT_OK(dbfull()->Flush(flush_opts));
|
||||
ASSERT_EQ(1, called);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(DBFlushDirectIOTest, DirectIO) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
@@ -323,6 +353,96 @@ TEST_F(DBFlushTest, CFDropRaceWithWaitForFlushMemTables) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBFlushTest, FireOnFlushCompletedAfterCommittedResult) {
|
||||
class TestListener : public EventListener {
|
||||
public:
|
||||
void OnFlushCompleted(DB* db, const FlushJobInfo& info) override {
|
||||
// There's only one key in each flush.
|
||||
ASSERT_EQ(info.smallest_seqno, info.largest_seqno);
|
||||
ASSERT_NE(0, info.smallest_seqno);
|
||||
if (info.smallest_seqno == seq1) {
|
||||
// First flush completed
|
||||
ASSERT_FALSE(completed1);
|
||||
completed1 = true;
|
||||
CheckFlushResultCommitted(db, seq1);
|
||||
} else {
|
||||
// Second flush completed
|
||||
ASSERT_FALSE(completed2);
|
||||
completed2 = true;
|
||||
ASSERT_EQ(info.smallest_seqno, seq2);
|
||||
CheckFlushResultCommitted(db, seq2);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckFlushResultCommitted(DB* db, SequenceNumber seq) {
|
||||
DBImpl* db_impl = static_cast_with_check<DBImpl>(db);
|
||||
InstrumentedMutex* mutex = db_impl->mutex();
|
||||
mutex->Lock();
|
||||
auto* cfd =
|
||||
reinterpret_cast<ColumnFamilyHandleImpl*>(db->DefaultColumnFamily())
|
||||
->cfd();
|
||||
ASSERT_LT(seq, cfd->imm()->current()->GetEarliestSequenceNumber());
|
||||
mutex->Unlock();
|
||||
}
|
||||
|
||||
std::atomic<SequenceNumber> seq1{0};
|
||||
std::atomic<SequenceNumber> seq2{0};
|
||||
std::atomic<bool> completed1{false};
|
||||
std::atomic<bool> completed2{false};
|
||||
};
|
||||
std::shared_ptr<TestListener> listener = std::make_shared<TestListener>();
|
||||
|
||||
SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::BackgroundCallFlush:start",
|
||||
"DBFlushTest::FireOnFlushCompletedAfterCommittedResult:WaitFirst"},
|
||||
{"DBImpl::FlushMemTableToOutputFile:Finish",
|
||||
"DBFlushTest::FireOnFlushCompletedAfterCommittedResult:WaitSecond"}});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"FlushJob::WriteLevel0Table", [&listener](void* arg) {
|
||||
// Wait for the second flush finished, out of mutex.
|
||||
auto* mems = reinterpret_cast<autovector<MemTable*>*>(arg);
|
||||
if (mems->front()->GetEarliestSequenceNumber() == listener->seq1 - 1) {
|
||||
TEST_SYNC_POINT(
|
||||
"DBFlushTest::FireOnFlushCompletedAfterCommittedResult:"
|
||||
"WaitSecond");
|
||||
}
|
||||
});
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.listeners.push_back(listener);
|
||||
// Setting max_flush_jobs = max_background_jobs / 4 = 2.
|
||||
options.max_background_jobs = 8;
|
||||
// Allow 2 immutable memtables.
|
||||
options.max_write_buffer_number = 3;
|
||||
Reopen(options);
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
ASSERT_OK(Put("foo", "v"));
|
||||
listener->seq1 = db_->GetLatestSequenceNumber();
|
||||
// t1 will wait for the second flush complete before committing flush result.
|
||||
auto t1 = port::Thread([&]() {
|
||||
// flush_opts.wait = true
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
});
|
||||
// Wait for first flush started.
|
||||
TEST_SYNC_POINT(
|
||||
"DBFlushTest::FireOnFlushCompletedAfterCommittedResult:WaitFirst");
|
||||
// The second flush will exit early without commit its result. The work
|
||||
// is delegated to the first flush.
|
||||
ASSERT_OK(Put("bar", "v"));
|
||||
listener->seq2 = db_->GetLatestSequenceNumber();
|
||||
FlushOptions flush_opts;
|
||||
flush_opts.wait = false;
|
||||
ASSERT_OK(db_->Flush(flush_opts));
|
||||
t1.join();
|
||||
ASSERT_TRUE(listener->completed1);
|
||||
ASSERT_TRUE(listener->completed2);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
TEST_P(DBAtomicFlushTest, ManualAtomicFlush) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -621,15 +741,44 @@ TEST_P(DBAtomicFlushTest, CFDropRaceWithWaitForFlushMemTables) {
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
TEST_P(DBAtomicFlushTest, RollbackAfterFailToInstallResults) {
|
||||
bool atomic_flush = GetParam();
|
||||
if (!atomic_flush) {
|
||||
return;
|
||||
}
|
||||
auto fault_injection_env = std::make_shared<FaultInjectionTestEnv>(env_);
|
||||
Options options = CurrentOptions();
|
||||
options.env = fault_injection_env.get();
|
||||
options.create_if_missing = true;
|
||||
options.atomic_flush = atomic_flush;
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
ASSERT_EQ(2, handles_.size());
|
||||
for (size_t cf = 0; cf < handles_.size(); ++cf) {
|
||||
ASSERT_OK(Put(static_cast<int>(cf), "a", "value"));
|
||||
}
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionSet::ProcessManifestWrites:BeforeWriteLastVersionEdit:0",
|
||||
[&](void* /*arg*/) { fault_injection_env->SetFilesystemActive(false); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
FlushOptions flush_opts;
|
||||
Status s = db_->Flush(flush_opts, handles_);
|
||||
ASSERT_NOK(s);
|
||||
fault_injection_env->SetFilesystemActive(true);
|
||||
Close();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBFlushDirectIOTest, DBFlushDirectIOTest,
|
||||
testing::Bool());
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBAtomicFlushTest, DBAtomicFlushTest, testing::Bool());
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+635
-351
File diff suppressed because it is too large.
Load diff
+150
-39
@@ -62,7 +62,7 @@
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/thread_local.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class Arena;
|
||||
class ArenaWrappedDBIter;
|
||||
@@ -82,13 +82,13 @@ struct MemTableInfo;
|
||||
// Class to maintain directories for all database paths other than main one.
|
||||
class Directories {
|
||||
public:
|
||||
Status SetDirectories(Env* env, const std::string& dbname,
|
||||
const std::string& wal_dir,
|
||||
const std::vector<DbPath>& data_paths);
|
||||
IOStatus SetDirectories(FileSystem* fs, const std::string& dbname,
|
||||
const std::string& wal_dir,
|
||||
const std::vector<DbPath>& data_paths);
|
||||
|
||||
Directory* GetDataDir(size_t path_id) const {
|
||||
FSDirectory* GetDataDir(size_t path_id) const {
|
||||
assert(path_id < data_dirs_.size());
|
||||
Directory* ret_dir = data_dirs_[path_id].get();
|
||||
FSDirectory* ret_dir = data_dirs_[path_id].get();
|
||||
if (ret_dir == nullptr) {
|
||||
// Should use db_dir_
|
||||
return db_dir_.get();
|
||||
@@ -96,19 +96,19 @@ class Directories {
|
||||
return ret_dir;
|
||||
}
|
||||
|
||||
Directory* GetWalDir() {
|
||||
FSDirectory* GetWalDir() {
|
||||
if (wal_dir_) {
|
||||
return wal_dir_.get();
|
||||
}
|
||||
return db_dir_.get();
|
||||
}
|
||||
|
||||
Directory* GetDbDir() { return db_dir_.get(); }
|
||||
FSDirectory* GetDbDir() { return db_dir_.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Directory> db_dir_;
|
||||
std::vector<std::unique_ptr<Directory>> data_dirs_;
|
||||
std::unique_ptr<Directory> wal_dir_;
|
||||
std::unique_ptr<FSDirectory> db_dir_;
|
||||
std::vector<std::unique_ptr<FSDirectory>> data_dirs_;
|
||||
std::unique_ptr<FSDirectory> wal_dir_;
|
||||
};
|
||||
|
||||
// While DB is the public interface of RocksDB, and DBImpl is the actual
|
||||
@@ -163,6 +163,9 @@ class DBImpl : public DB {
|
||||
virtual Status Get(const ReadOptions& options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
PinnableSlice* value) override;
|
||||
virtual Status Get(const ReadOptions& options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
PinnableSlice* value, std::string* timestamp) override;
|
||||
|
||||
using DB::GetMergeOperands;
|
||||
Status GetMergeOperands(const ReadOptions& options,
|
||||
@@ -199,11 +202,15 @@ class DBImpl : public DB {
|
||||
PinnableSlice* values, Status* statuses,
|
||||
const bool sorted_input = false) override;
|
||||
|
||||
void MultiGetImpl(
|
||||
virtual void MultiGet(const ReadOptions& options, const size_t num_keys,
|
||||
ColumnFamilyHandle** column_families, const Slice* keys,
|
||||
PinnableSlice* values, Status* statuses,
|
||||
const bool sorted_input = false) override;
|
||||
|
||||
virtual void MultiGetWithCallback(
|
||||
const ReadOptions& options, ColumnFamilyHandle* column_family,
|
||||
autovector<KeyContext, MultiGetContext::MAX_BATCH_SIZE>& key_context,
|
||||
bool sorted_input, ReadCallback* callback = nullptr,
|
||||
bool* is_blob_index = nullptr);
|
||||
ReadCallback* callback,
|
||||
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* sorted_keys);
|
||||
|
||||
virtual Status CreateColumnFamily(const ColumnFamilyOptions& cf_options,
|
||||
const std::string& column_family,
|
||||
@@ -226,7 +233,7 @@ class DBImpl : public DB {
|
||||
using DB::KeyMayExist;
|
||||
virtual bool KeyMayExist(const ReadOptions& options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
std::string* value,
|
||||
std::string* value, std::string* timestamp,
|
||||
bool* value_found = nullptr) override;
|
||||
|
||||
using DB::NewIterator;
|
||||
@@ -302,6 +309,7 @@ class DBImpl : public DB {
|
||||
ColumnFamilyHandle* column_family) override;
|
||||
virtual const std::string& GetName() const override;
|
||||
virtual Env* GetEnv() const override;
|
||||
virtual FileSystem* GetFileSystem() const override;
|
||||
using DB::GetOptions;
|
||||
virtual Options GetOptions(ColumnFamilyHandle* column_family) const override;
|
||||
using DB::GetDBOptions;
|
||||
@@ -349,6 +357,8 @@ class DBImpl : public DB {
|
||||
virtual Status GetSortedWalFiles(VectorLogPtr& files) override;
|
||||
virtual Status GetCurrentWalFile(
|
||||
std::unique_ptr<LogFile>* current_log_file) override;
|
||||
virtual Status GetCreationTimeOfOldestFile(
|
||||
uint64_t* creation_time) override;
|
||||
|
||||
virtual Status GetUpdatesSince(
|
||||
SequenceNumber seq_number, std::unique_ptr<TransactionLogIterator>* iter,
|
||||
@@ -426,6 +436,7 @@ class DBImpl : public DB {
|
||||
struct GetImplOptions {
|
||||
ColumnFamilyHandle* column_family = nullptr;
|
||||
PinnableSlice* value = nullptr;
|
||||
std::string* timestamp = nullptr;
|
||||
bool* value_found = nullptr;
|
||||
ReadCallback* callback = nullptr;
|
||||
bool* is_blob_index = nullptr;
|
||||
@@ -448,7 +459,7 @@ class DBImpl : public DB {
|
||||
// If get_impl_options.get_value = false get merge operands associated with
|
||||
// get_impl_options.key via get_impl_options.merge_operands
|
||||
Status GetImpl(const ReadOptions& options, const Slice& key,
|
||||
GetImplOptions get_impl_options);
|
||||
GetImplOptions& get_impl_options);
|
||||
|
||||
ArenaWrappedDBIter* NewIteratorImpl(const ReadOptions& options,
|
||||
ColumnFamilyData* cfd,
|
||||
@@ -792,6 +803,10 @@ class DBImpl : public DB {
|
||||
logs_to_free_queue_.push_back(log_writer);
|
||||
}
|
||||
|
||||
void AddSuperVersionsToFreeQueue(SuperVersion* sv) {
|
||||
superversions_to_free_queue_.push_back(sv);
|
||||
}
|
||||
|
||||
void SetSnapshotChecker(SnapshotChecker* snapshot_checker);
|
||||
|
||||
// Fill JobContext with snapshot information needed by flush and compaction.
|
||||
@@ -815,9 +830,9 @@ class DBImpl : public DB {
|
||||
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr,
|
||||
const bool seq_per_batch, const bool batch_per_txn);
|
||||
|
||||
|
||||
static Status CreateAndNewDirectory(Env* env, const std::string& dirname,
|
||||
std::unique_ptr<Directory>* directory);
|
||||
static IOStatus CreateAndNewDirectory(
|
||||
FileSystem* fs, const std::string& dirname,
|
||||
std::unique_ptr<FSDirectory>* directory);
|
||||
|
||||
// find stats map from stats_history_ with smallest timestamp in
|
||||
// the range of [start_time, end_time)
|
||||
@@ -935,13 +950,14 @@ class DBImpl : public DB {
|
||||
#endif // NDEBUG
|
||||
|
||||
protected:
|
||||
Env* const env_;
|
||||
const std::string dbname_;
|
||||
std::string db_id_;
|
||||
std::unique_ptr<VersionSet> versions_;
|
||||
// Flag to check whether we allocated and own the info log file
|
||||
bool own_info_log_;
|
||||
const DBOptions initial_db_options_;
|
||||
Env* const env_;
|
||||
std::shared_ptr<FileSystem> fs_;
|
||||
const ImmutableDBOptions immutable_db_options_;
|
||||
MutableDBOptions mutable_db_options_;
|
||||
Statistics* stats_;
|
||||
@@ -969,10 +985,10 @@ class DBImpl : public DB {
|
||||
bool single_column_family_mode_;
|
||||
|
||||
// The options to access storage files
|
||||
const EnvOptions env_options_;
|
||||
const FileOptions file_options_;
|
||||
|
||||
// Additonal options for compaction and flush
|
||||
EnvOptions env_options_for_compaction_;
|
||||
FileOptions file_options_for_compaction_;
|
||||
|
||||
std::unique_ptr<ColumnFamilyMemTablesImpl> column_family_memtables_;
|
||||
|
||||
@@ -1005,11 +1021,11 @@ class DBImpl : public DB {
|
||||
|
||||
void NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
int job_id, TableProperties prop);
|
||||
int job_id);
|
||||
|
||||
void NotifyOnFlushCompleted(ColumnFamilyData* cfd, FileMetaData* file_meta,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
int job_id, TableProperties prop);
|
||||
void NotifyOnFlushCompleted(
|
||||
ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options,
|
||||
std::list<std::unique_ptr<FlushJobInfo>>* flush_jobs_info);
|
||||
|
||||
void NotifyOnCompactionBegin(ColumnFamilyData* cfd, Compaction* c,
|
||||
const Status& st,
|
||||
@@ -1098,10 +1114,15 @@ class DBImpl : public DB {
|
||||
// Recover the descriptor from persistent storage. May do a significant
|
||||
// amount of work to recover recently logged updates. Any changes to
|
||||
// be made to the descriptor are added to *edit.
|
||||
// recovered_seq is set to less than kMaxSequenceNumber if the log's tail is
|
||||
// skipped.
|
||||
virtual Status Recover(
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families,
|
||||
bool read_only = false, bool error_if_log_file_exist = false,
|
||||
bool error_if_data_exists_in_logs = false);
|
||||
bool error_if_data_exists_in_logs = false,
|
||||
uint64_t* recovered_seq = nullptr);
|
||||
|
||||
virtual bool OwnTablesAndLogs() const { return true; }
|
||||
|
||||
private:
|
||||
friend class DB;
|
||||
@@ -1187,7 +1208,7 @@ class DBImpl : public DB {
|
||||
};
|
||||
|
||||
// PurgeFileInfo is a structure to hold information of files to be deleted in
|
||||
// purge_queue_
|
||||
// purge_files_
|
||||
struct PurgeFileInfo {
|
||||
std::string fname;
|
||||
std::string dir_to_sync;
|
||||
@@ -1341,8 +1362,10 @@ class DBImpl : public DB {
|
||||
JobContext* job_context, LogBuffer* log_buffer, Env::Priority thread_pri);
|
||||
|
||||
// REQUIRES: log_numbers are sorted in ascending order
|
||||
// corrupted_log_found is set to true if we recover from a corrupted log file.
|
||||
Status RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
SequenceNumber* next_sequence, bool read_only);
|
||||
SequenceNumber* next_sequence, bool read_only,
|
||||
bool* corrupted_log_found);
|
||||
|
||||
// The following two methods are used to flush a memtable to
|
||||
// storage. The first one is used at database RecoveryTime (when the
|
||||
@@ -1365,6 +1388,7 @@ class DBImpl : public DB {
|
||||
Status ThrottleLowPriWritesIfNeeded(const WriteOptions& write_options,
|
||||
WriteBatch* my_batch);
|
||||
|
||||
// REQUIRES: mutex locked and in write thread.
|
||||
Status ScheduleFlushes(WriteContext* context);
|
||||
|
||||
void MaybeFlushStatsCF(autovector<ColumnFamilyData*>* cfds);
|
||||
@@ -1407,10 +1431,23 @@ class DBImpl : public DB {
|
||||
bool resuming_from_bg_err);
|
||||
|
||||
inline void WaitForPendingWrites() {
|
||||
mutex_.AssertHeld();
|
||||
TEST_SYNC_POINT("DBImpl::WaitForPendingWrites:BeforeBlock");
|
||||
// In case of pipelined write is enabled, wait for all pending memtable
|
||||
// writers.
|
||||
if (immutable_db_options_.enable_pipelined_write) {
|
||||
// Memtable writers may call DB::Get in case max_successive_merges > 0,
|
||||
// which may lock mutex. Unlocking mutex here to avoid deadlock.
|
||||
mutex_.Unlock();
|
||||
write_thread_.WaitForMemTableWriters();
|
||||
mutex_.Lock();
|
||||
}
|
||||
|
||||
if (!immutable_db_options_.unordered_write) {
|
||||
// Then the writes are finished before the next write group starts
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the ones who already wrote to the WAL to finish their
|
||||
// memtable write.
|
||||
if (pending_memtable_writes_.load() != 0) {
|
||||
@@ -1423,10 +1460,10 @@ class DBImpl : public DB {
|
||||
// REQUIRES: mutex locked and in write thread.
|
||||
void AssignAtomicFlushSeq(const autovector<ColumnFamilyData*>& cfds);
|
||||
|
||||
// REQUIRES: mutex locked
|
||||
// REQUIRES: mutex locked and in write thread.
|
||||
Status SwitchWAL(WriteContext* write_context);
|
||||
|
||||
// REQUIRES: mutex locked
|
||||
// REQUIRES: mutex locked and in write thread.
|
||||
Status HandleWriteBufferFull(WriteContext* write_context);
|
||||
|
||||
// REQUIRES: mutex locked
|
||||
@@ -1566,7 +1603,7 @@ class DBImpl : public DB {
|
||||
|
||||
uint64_t GetMaxTotalWalSize() const;
|
||||
|
||||
Directory* GetDataDir(ColumnFamilyData* cfd, size_t path_id) const;
|
||||
FSDirectory* GetDataDir(ColumnFamilyData* cfd, size_t path_id) const;
|
||||
|
||||
Status CloseHelper();
|
||||
|
||||
@@ -1626,6 +1663,81 @@ class DBImpl : public DB {
|
||||
const DBOptions& db_options,
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families);
|
||||
|
||||
// Utility function to do some debug validation and sort the given vector
|
||||
// of MultiGet keys
|
||||
void PrepareMultiGetKeys(
|
||||
const size_t num_keys, bool sorted,
|
||||
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* key_ptrs);
|
||||
|
||||
// A structure to hold the information required to process MultiGet of keys
|
||||
// belonging to one column family. For a multi column family MultiGet, there
|
||||
// will be a container of these objects.
|
||||
struct MultiGetColumnFamilyData {
|
||||
ColumnFamilyHandle* cf;
|
||||
ColumnFamilyData* cfd;
|
||||
|
||||
// For the batched MultiGet which relies on sorted keys, start specifies
|
||||
// the index of first key belonging to this column family in the sorted
|
||||
// list.
|
||||
size_t start;
|
||||
|
||||
// For the batched MultiGet case, num_keys specifies the number of keys
|
||||
// belonging to this column family in the sorted list
|
||||
size_t num_keys;
|
||||
|
||||
// SuperVersion for the column family obtained in a manner that ensures a
|
||||
// consistent view across all column families in the DB
|
||||
SuperVersion* super_version;
|
||||
MultiGetColumnFamilyData(ColumnFamilyHandle* column_family,
|
||||
SuperVersion* sv)
|
||||
: cf(column_family),
|
||||
cfd(static_cast<ColumnFamilyHandleImpl*>(cf)->cfd()),
|
||||
start(0),
|
||||
num_keys(0),
|
||||
super_version(sv) {}
|
||||
|
||||
MultiGetColumnFamilyData(ColumnFamilyHandle* column_family, size_t first,
|
||||
size_t count, SuperVersion* sv)
|
||||
: cf(column_family),
|
||||
cfd(static_cast<ColumnFamilyHandleImpl*>(cf)->cfd()),
|
||||
start(first),
|
||||
num_keys(count),
|
||||
super_version(sv) {}
|
||||
|
||||
MultiGetColumnFamilyData() = default;
|
||||
};
|
||||
|
||||
// A common function to obtain a consistent snapshot, which can be implicit
|
||||
// if the user doesn't specify a snapshot in read_options, across
|
||||
// multiple column families for MultiGet. It will attempt to get an implicit
|
||||
// snapshot without acquiring the db_mutes, but will give up after a few
|
||||
// tries and acquire the mutex if a memtable flush happens. The template
|
||||
// allows both the batched and non-batched MultiGet to call this with
|
||||
// either an std::unordered_map or autovector of column families.
|
||||
//
|
||||
// If callback is non-null, the callback is refreshed with the snapshot
|
||||
// sequence number
|
||||
//
|
||||
// A return value of true indicates that the SuperVersions were obtained
|
||||
// from the ColumnFamilyData, whereas false indicates they are thread
|
||||
// local
|
||||
template <class T>
|
||||
bool MultiCFSnapshot(
|
||||
const ReadOptions& read_options, ReadCallback* callback,
|
||||
std::function<MultiGetColumnFamilyData*(typename T::iterator&)>&
|
||||
iter_deref_func,
|
||||
T* cf_list, SequenceNumber* snapshot);
|
||||
|
||||
// The actual implementation of the batching MultiGet. The caller is expected
|
||||
// to have acquired the SuperVersion and pass in a snapshot sequence number
|
||||
// in order to construct the LookupKeys. The start_key and num_keys specify
|
||||
// the range of keys in the sorted_keys vector for a single column family.
|
||||
void MultiGetImpl(
|
||||
const ReadOptions& read_options, size_t start_key, size_t num_keys,
|
||||
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* sorted_keys,
|
||||
SuperVersion* sv, SequenceNumber snap_seqnum, ReadCallback* callback,
|
||||
bool* is_blob_index);
|
||||
|
||||
// table_cache_ provides its own synchronization
|
||||
std::shared_ptr<Cache> table_cache_;
|
||||
|
||||
@@ -1736,8 +1848,6 @@ class DBImpl : public DB {
|
||||
|
||||
WriteController write_controller_;
|
||||
|
||||
std::unique_ptr<RateLimiter> low_pri_write_rate_limiter_;
|
||||
|
||||
// Size of the last batch group. In slowdown mode, next write needs to
|
||||
// sleep if it uses up the quota.
|
||||
// Note: This is to protect memtable and compaction. If the batch only writes
|
||||
@@ -1795,6 +1905,7 @@ class DBImpl : public DB {
|
||||
|
||||
// A queue to store log writers to close
|
||||
std::deque<log::Writer*> logs_to_free_queue_;
|
||||
std::deque<SuperVersion*> superversions_to_free_queue_;
|
||||
int unscheduled_flushes_;
|
||||
int unscheduled_compactions_;
|
||||
|
||||
@@ -1909,13 +2020,13 @@ class DBImpl : public DB {
|
||||
|
||||
// handle for scheduling stats dumping at fixed intervals
|
||||
// REQUIRES: mutex locked
|
||||
std::unique_ptr<rocksdb::RepeatableThread> thread_dump_stats_;
|
||||
std::unique_ptr<ROCKSDB_NAMESPACE::RepeatableThread> thread_dump_stats_;
|
||||
|
||||
// handle for scheduling stats snapshoting at fixed intervals
|
||||
// REQUIRES: mutex locked
|
||||
std::unique_ptr<rocksdb::RepeatableThread> thread_persist_stats_;
|
||||
std::unique_ptr<ROCKSDB_NAMESPACE::RepeatableThread> thread_persist_stats_;
|
||||
|
||||
// When set, we use a separate queue for writes that dont write to memtable.
|
||||
// When set, we use a separate queue for writes that don't write to memtable.
|
||||
// In 2PC these are the writes at Prepare phase.
|
||||
const bool two_write_queues_;
|
||||
const bool manual_wal_flush_;
|
||||
@@ -1998,4 +2109,4 @@ static void ClipToRange(T* ptr, V minvalue, V maxvalue) {
|
||||
if (static_cast<V>(*ptr) < minvalue) *ptr = minvalue;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "util/cast_util.h"
|
||||
#include "util/concurrent_task_limiter_impl.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
bool DBImpl::EnoughRoomForCompaction(
|
||||
ColumnFamilyData* cfd, const std::vector<CompactionInputFiles>& inputs,
|
||||
@@ -117,7 +117,7 @@ Status DBImpl::SyncClosedLogs(JobContext* job_context) {
|
||||
}
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = directories_.GetWalDir()->Fsync();
|
||||
s = directories_.GetWalDir()->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
|
||||
mutex_.Lock();
|
||||
@@ -148,7 +148,7 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
|
||||
FlushJob flush_job(
|
||||
dbname_, cfd, immutable_db_options_, mutable_cf_options,
|
||||
nullptr /* memtable_id */, env_options_for_compaction_, versions_.get(),
|
||||
nullptr /* memtable_id */, file_options_for_compaction_, versions_.get(),
|
||||
&mutex_, &shutting_down_, snapshot_seqs, earliest_write_conflict_snapshot,
|
||||
snapshot_checker, job_context, log_buffer, directories_.GetDbDir(),
|
||||
GetDataDir(cfd, 0U),
|
||||
@@ -164,8 +164,7 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
// may temporarily unlock and lock the mutex.
|
||||
NotifyOnFlushBegin(cfd, &file_meta, mutable_cf_options, job_context->job_id,
|
||||
flush_job.GetTableProperties());
|
||||
NotifyOnFlushBegin(cfd, &file_meta, mutable_cf_options, job_context->job_id);
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
Status s;
|
||||
@@ -213,8 +212,8 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
if (s.ok()) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
// may temporarily unlock and lock the mutex.
|
||||
NotifyOnFlushCompleted(cfd, &file_meta, mutable_cf_options,
|
||||
job_context->job_id, flush_job.GetTableProperties());
|
||||
NotifyOnFlushCompleted(cfd, mutable_cf_options,
|
||||
flush_job.GetCommittedFlushJobsInfo());
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(
|
||||
immutable_db_options_.sst_file_manager.get());
|
||||
if (sfm) {
|
||||
@@ -233,6 +232,7 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::FlushMemTableToOutputFile:Finish");
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -301,15 +301,15 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
GetSnapshotContext(job_context, &snapshot_seqs,
|
||||
&earliest_write_conflict_snapshot, &snapshot_checker);
|
||||
|
||||
autovector<Directory*> distinct_output_dirs;
|
||||
autovector<FSDirectory*> distinct_output_dirs;
|
||||
autovector<std::string> distinct_output_dir_paths;
|
||||
std::vector<FlushJob> jobs;
|
||||
std::vector<std::unique_ptr<FlushJob>> jobs;
|
||||
std::vector<MutableCFOptions> all_mutable_cf_options;
|
||||
int num_cfs = static_cast<int>(cfds.size());
|
||||
all_mutable_cf_options.reserve(num_cfs);
|
||||
for (int i = 0; i < num_cfs; ++i) {
|
||||
auto cfd = cfds[i];
|
||||
Directory* data_dir = GetDataDir(cfd, 0U);
|
||||
FSDirectory* data_dir = GetDataDir(cfd, 0U);
|
||||
const std::string& curr_path = cfd->ioptions()->cf_paths[0].path;
|
||||
|
||||
// Add to distinct output directories if eligible. Use linear search. Since
|
||||
@@ -330,16 +330,16 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
all_mutable_cf_options.emplace_back(*cfd->GetLatestMutableCFOptions());
|
||||
const MutableCFOptions& mutable_cf_options = all_mutable_cf_options.back();
|
||||
const uint64_t* max_memtable_id = &(bg_flush_args[i].max_memtable_id_);
|
||||
jobs.emplace_back(
|
||||
jobs.emplace_back(new FlushJob(
|
||||
dbname_, cfd, immutable_db_options_, mutable_cf_options,
|
||||
max_memtable_id, env_options_for_compaction_, versions_.get(), &mutex_,
|
||||
max_memtable_id, file_options_for_compaction_, versions_.get(), &mutex_,
|
||||
&shutting_down_, snapshot_seqs, earliest_write_conflict_snapshot,
|
||||
snapshot_checker, job_context, log_buffer, directories_.GetDbDir(),
|
||||
data_dir, GetCompressionFlush(*cfd->ioptions(), mutable_cf_options),
|
||||
stats_, &event_logger_, mutable_cf_options.report_bg_io_stats,
|
||||
false /* sync_output_directory */, false /* write_manifest */,
|
||||
thread_pri);
|
||||
jobs.back().PickMemTable();
|
||||
thread_pri));
|
||||
jobs.back()->PickMemTable();
|
||||
}
|
||||
|
||||
std::vector<FileMetaData> file_meta(num_cfs);
|
||||
@@ -351,7 +351,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
const MutableCFOptions& mutable_cf_options = all_mutable_cf_options.at(i);
|
||||
// may temporarily unlock and lock the mutex.
|
||||
NotifyOnFlushBegin(cfds[i], &file_meta[i], mutable_cf_options,
|
||||
job_context->job_id, jobs[i].GetTableProperties());
|
||||
job_context->job_id);
|
||||
}
|
||||
#endif /* !ROCKSDB_LITE */
|
||||
|
||||
@@ -373,7 +373,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
// TODO (yanqin): parallelize jobs with threads.
|
||||
for (int i = 1; i != num_cfs; ++i) {
|
||||
exec_status[i].second =
|
||||
jobs[i].Run(&logs_with_prep_tracker_, &file_meta[i]);
|
||||
jobs[i]->Run(&logs_with_prep_tracker_, &file_meta[i]);
|
||||
exec_status[i].first = true;
|
||||
}
|
||||
if (num_cfs > 1) {
|
||||
@@ -382,8 +382,10 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
TEST_SYNC_POINT(
|
||||
"DBImpl::AtomicFlushMemTablesToOutputFiles:SomeFlushJobsComplete:2");
|
||||
}
|
||||
assert(exec_status.size() > 0);
|
||||
assert(!file_meta.empty());
|
||||
exec_status[0].second =
|
||||
jobs[0].Run(&logs_with_prep_tracker_, &file_meta[0]);
|
||||
jobs[0]->Run(&logs_with_prep_tracker_, &file_meta[0]);
|
||||
exec_status[0].first = true;
|
||||
|
||||
Status error_status;
|
||||
@@ -407,24 +409,41 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
s = Status::OK();
|
||||
}
|
||||
|
||||
if (s.ok() || s.IsShutdownInProgress() || s.IsColumnFamilyDropped()) {
|
||||
if (s.ok() || s.IsShutdownInProgress()) {
|
||||
// Sync on all distinct output directories.
|
||||
for (auto dir : distinct_output_dirs) {
|
||||
if (dir != nullptr) {
|
||||
Status error_status = dir->Fsync();
|
||||
Status error_status = dir->Fsync(IOOptions(), nullptr);
|
||||
if (!error_status.ok()) {
|
||||
s = error_status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Need to undo atomic flush if something went wrong, i.e. s is not OK and
|
||||
// it is not because of CF drop.
|
||||
// Have to cancel the flush jobs that have NOT executed because we need to
|
||||
// unref the versions.
|
||||
for (int i = 0; i != num_cfs; ++i) {
|
||||
if (!exec_status[i].first) {
|
||||
jobs[i]->Cancel();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i != num_cfs; ++i) {
|
||||
if (exec_status[i].first && exec_status[i].second.ok()) {
|
||||
auto& mems = jobs[i]->GetMemTables();
|
||||
cfds[i]->imm()->RollbackMemtableFlush(mems,
|
||||
file_meta[i].fd.GetNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
auto wait_to_install_func = [&]() {
|
||||
bool ready = true;
|
||||
for (size_t i = 0; i != cfds.size(); ++i) {
|
||||
const auto& mems = jobs[i].GetMemTables();
|
||||
const auto& mems = jobs[i]->GetMemTables();
|
||||
if (cfds[i]->IsDropped()) {
|
||||
// If the column family is dropped, then do not wait.
|
||||
continue;
|
||||
@@ -465,7 +484,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
autovector<const MutableCFOptions*> mutable_cf_options_list;
|
||||
autovector<FileMetaData*> tmp_file_meta;
|
||||
for (int i = 0; i != num_cfs; ++i) {
|
||||
const auto& mems = jobs[i].GetMemTables();
|
||||
const auto& mems = jobs[i]->GetMemTables();
|
||||
if (!cfds[i]->IsDropped() && !mems.empty()) {
|
||||
tmp_cfds.emplace_back(cfds[i]);
|
||||
mems_list.emplace_back(&mems);
|
||||
@@ -501,12 +520,13 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
#ifndef ROCKSDB_LITE
|
||||
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) {
|
||||
if (cfds[i]->IsDropped()) {
|
||||
continue;
|
||||
}
|
||||
NotifyOnFlushCompleted(cfds[i], &file_meta[i], all_mutable_cf_options[i],
|
||||
job_context->job_id, jobs[i].GetTableProperties());
|
||||
NotifyOnFlushCompleted(cfds[i], all_mutable_cf_options[i],
|
||||
jobs[i]->GetCommittedFlushJobsInfo());
|
||||
if (sfm) {
|
||||
std::string file_path = MakeTableFileName(
|
||||
cfds[i]->ioptions()->cf_paths[0].path, file_meta[i].fd.GetNumber());
|
||||
@@ -523,23 +543,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
|
||||
// Need to undo atomic flush if something went wrong, i.e. s is not OK and
|
||||
// it is not because of CF drop.
|
||||
if (!s.ok() && !s.IsColumnFamilyDropped()) {
|
||||
// Have to cancel the flush jobs that have NOT executed because we need to
|
||||
// unref the versions.
|
||||
for (int i = 0; i != num_cfs; ++i) {
|
||||
if (!exec_status[i].first) {
|
||||
jobs[i].Cancel();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i != num_cfs; ++i) {
|
||||
if (exec_status[i].first && exec_status[i].second.ok()) {
|
||||
auto& mems = jobs[i].GetMemTables();
|
||||
cfds[i]->imm()->RollbackMemtableFlush(mems,
|
||||
file_meta[i].fd.GetNumber());
|
||||
}
|
||||
}
|
||||
if (!s.ok() && !s.IsShutdownInProgress()) {
|
||||
Status new_bg_error = s;
|
||||
error_handler_.SetBGError(new_bg_error, BackgroundErrorReason::kFlush);
|
||||
}
|
||||
@@ -549,7 +553,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
|
||||
void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
int job_id, TableProperties prop) {
|
||||
int job_id) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (immutable_db_options_.listeners.size() == 0U) {
|
||||
return;
|
||||
@@ -567,20 +571,21 @@ void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
|
||||
// release lock while notifying events
|
||||
mutex_.Unlock();
|
||||
{
|
||||
FlushJobInfo info;
|
||||
FlushJobInfo info{};
|
||||
info.cf_id = cfd->GetID();
|
||||
info.cf_name = cfd->GetName();
|
||||
// TODO(yhchiang): make db_paths dynamic in case flush does not
|
||||
// go to L0 in the future.
|
||||
info.file_path = MakeTableFileName(cfd->ioptions()->cf_paths[0].path,
|
||||
file_meta->fd.GetNumber());
|
||||
const uint64_t file_number = file_meta->fd.GetNumber();
|
||||
info.file_path =
|
||||
MakeTableFileName(cfd->ioptions()->cf_paths[0].path, file_number);
|
||||
info.file_number = file_number;
|
||||
info.thread_id = env_->GetThreadID();
|
||||
info.job_id = job_id;
|
||||
info.triggered_writes_slowdown = triggered_writes_slowdown;
|
||||
info.triggered_writes_stop = triggered_writes_stop;
|
||||
info.smallest_seqno = file_meta->fd.smallest_seqno;
|
||||
info.largest_seqno = file_meta->fd.largest_seqno;
|
||||
info.table_properties = prop;
|
||||
info.flush_reason = cfd->GetFlushReason();
|
||||
for (auto listener : immutable_db_options_.listeners) {
|
||||
listener->OnFlushBegin(this, info);
|
||||
@@ -594,15 +599,14 @@ void DBImpl::NotifyOnFlushBegin(ColumnFamilyData* cfd, FileMetaData* file_meta,
|
||||
(void)file_meta;
|
||||
(void)mutable_cf_options;
|
||||
(void)job_id;
|
||||
(void)prop;
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
|
||||
void DBImpl::NotifyOnFlushCompleted(ColumnFamilyData* cfd,
|
||||
FileMetaData* file_meta,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
int job_id, TableProperties prop) {
|
||||
void DBImpl::NotifyOnFlushCompleted(
|
||||
ColumnFamilyData* cfd, const MutableCFOptions& mutable_cf_options,
|
||||
std::list<std::unique_ptr<FlushJobInfo>>* flush_jobs_info) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
assert(flush_jobs_info != nullptr);
|
||||
if (immutable_db_options_.listeners.size() == 0U) {
|
||||
return;
|
||||
}
|
||||
@@ -619,34 +623,22 @@ void DBImpl::NotifyOnFlushCompleted(ColumnFamilyData* cfd,
|
||||
// release lock while notifying events
|
||||
mutex_.Unlock();
|
||||
{
|
||||
FlushJobInfo info;
|
||||
info.cf_id = cfd->GetID();
|
||||
info.cf_name = cfd->GetName();
|
||||
// TODO(yhchiang): make db_paths dynamic in case flush does not
|
||||
// go to L0 in the future.
|
||||
info.file_path = MakeTableFileName(cfd->ioptions()->cf_paths[0].path,
|
||||
file_meta->fd.GetNumber());
|
||||
info.thread_id = env_->GetThreadID();
|
||||
info.job_id = job_id;
|
||||
info.triggered_writes_slowdown = triggered_writes_slowdown;
|
||||
info.triggered_writes_stop = triggered_writes_stop;
|
||||
info.smallest_seqno = file_meta->fd.smallest_seqno;
|
||||
info.largest_seqno = file_meta->fd.largest_seqno;
|
||||
info.table_properties = prop;
|
||||
info.flush_reason = cfd->GetFlushReason();
|
||||
for (auto listener : immutable_db_options_.listeners) {
|
||||
listener->OnFlushCompleted(this, info);
|
||||
for (auto& info : *flush_jobs_info) {
|
||||
info->triggered_writes_slowdown = triggered_writes_slowdown;
|
||||
info->triggered_writes_stop = triggered_writes_stop;
|
||||
for (auto listener : immutable_db_options_.listeners) {
|
||||
listener->OnFlushCompleted(this, *info);
|
||||
}
|
||||
}
|
||||
flush_jobs_info->clear();
|
||||
}
|
||||
mutex_.Lock();
|
||||
// no need to signal bg_cv_ as it will be signaled at the end of the
|
||||
// flush process.
|
||||
#else
|
||||
(void)cfd;
|
||||
(void)file_meta;
|
||||
(void)mutable_cf_options;
|
||||
(void)job_id;
|
||||
(void)prop;
|
||||
(void)flush_jobs_info;
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
|
||||
@@ -660,15 +652,13 @@ Status DBImpl::CompactRange(const CompactRangeOptions& options,
|
||||
return Status::InvalidArgument("Invalid target path ID");
|
||||
}
|
||||
|
||||
bool exclusive = options.exclusive_manual_compaction;
|
||||
|
||||
bool flush_needed = true;
|
||||
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(&mutex_);
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
cfd->RangesOverlapWithMemtables({range}, super_version, &flush_needed);
|
||||
CleanupSuperVersion(super_version);
|
||||
}
|
||||
@@ -694,25 +684,9 @@ Status DBImpl::CompactRange(const CompactRangeOptions& options,
|
||||
}
|
||||
}
|
||||
|
||||
int max_level_with_files = 0;
|
||||
// max_file_num_to_ignore can be used to filter out newly created SST files,
|
||||
// useful for bottom level compaction in a manual compaction
|
||||
uint64_t max_file_num_to_ignore = port::kMaxUint64;
|
||||
uint64_t next_file_number = port::kMaxUint64;
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
Version* base = cfd->current();
|
||||
for (int level = 1; level < base->storage_info()->num_non_empty_levels();
|
||||
level++) {
|
||||
if (base->storage_info()->OverlapInLevel(level, begin, end)) {
|
||||
max_level_with_files = level;
|
||||
}
|
||||
}
|
||||
next_file_number = versions_->current_next_file_number();
|
||||
}
|
||||
|
||||
int final_output_level = 0;
|
||||
|
||||
constexpr int kInvalidLevel = -1;
|
||||
int final_output_level = kInvalidLevel;
|
||||
bool exclusive = options.exclusive_manual_compaction;
|
||||
if (cfd->ioptions()->compaction_style == kCompactionStyleUniversal &&
|
||||
cfd->NumberLevels() > 1) {
|
||||
// Always compact all files together.
|
||||
@@ -723,58 +697,98 @@ Status DBImpl::CompactRange(const CompactRangeOptions& options,
|
||||
}
|
||||
s = RunManualCompaction(cfd, ColumnFamilyData::kCompactAllLevels,
|
||||
final_output_level, options, begin, end, exclusive,
|
||||
false, max_file_num_to_ignore);
|
||||
false, port::kMaxUint64);
|
||||
} else {
|
||||
for (int level = 0; level <= max_level_with_files; level++) {
|
||||
int first_overlapped_level = kInvalidLevel;
|
||||
int max_overlapped_level = kInvalidLevel;
|
||||
{
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
Version* current_version = super_version->current;
|
||||
ReadOptions ro;
|
||||
ro.total_order_seek = true;
|
||||
bool overlap;
|
||||
for (int level = 0;
|
||||
level < current_version->storage_info()->num_non_empty_levels();
|
||||
level++) {
|
||||
overlap = true;
|
||||
if (begin != nullptr && end != nullptr) {
|
||||
Status status = current_version->OverlapWithLevelIterator(
|
||||
ro, file_options_, *begin, *end, level, &overlap);
|
||||
if (!status.ok()) {
|
||||
overlap = current_version->storage_info()->OverlapInLevel(
|
||||
level, begin, end);
|
||||
}
|
||||
} else {
|
||||
overlap = current_version->storage_info()->OverlapInLevel(level,
|
||||
begin, end);
|
||||
}
|
||||
if (overlap) {
|
||||
if (first_overlapped_level == kInvalidLevel) {
|
||||
first_overlapped_level = level;
|
||||
}
|
||||
max_overlapped_level = level;
|
||||
}
|
||||
}
|
||||
CleanupSuperVersion(super_version);
|
||||
}
|
||||
if (s.ok() && first_overlapped_level != kInvalidLevel) {
|
||||
// max_file_num_to_ignore can be used to filter out newly created SST
|
||||
// files, useful for bottom level compaction in a manual compaction
|
||||
uint64_t max_file_num_to_ignore = port::kMaxUint64;
|
||||
uint64_t next_file_number = versions_->current_next_file_number();
|
||||
final_output_level = max_overlapped_level;
|
||||
int output_level;
|
||||
// in case the compaction is universal or if we're compacting the
|
||||
// bottom-most level, the output level will be the same as input one.
|
||||
// level 0 can never be the bottommost level (i.e. if all files are in
|
||||
// level 0, we will compact to level 1)
|
||||
if (cfd->ioptions()->compaction_style == kCompactionStyleUniversal ||
|
||||
cfd->ioptions()->compaction_style == kCompactionStyleFIFO) {
|
||||
output_level = level;
|
||||
} else if (level == max_level_with_files && level > 0) {
|
||||
if (options.bottommost_level_compaction ==
|
||||
BottommostLevelCompaction::kSkip) {
|
||||
// Skip bottommost level compaction
|
||||
continue;
|
||||
} else if (options.bottommost_level_compaction ==
|
||||
BottommostLevelCompaction::kIfHaveCompactionFilter &&
|
||||
cfd->ioptions()->compaction_filter == nullptr &&
|
||||
cfd->ioptions()->compaction_filter_factory == nullptr) {
|
||||
// Skip bottommost level compaction since we don't have a compaction
|
||||
// filter
|
||||
continue;
|
||||
for (int level = first_overlapped_level; level <= max_overlapped_level;
|
||||
level++) {
|
||||
// in case the compaction is universal or if we're compacting the
|
||||
// bottom-most level, the output level will be the same as input one.
|
||||
// level 0 can never be the bottommost level (i.e. if all files are in
|
||||
// level 0, we will compact to level 1)
|
||||
if (cfd->ioptions()->compaction_style == kCompactionStyleUniversal ||
|
||||
cfd->ioptions()->compaction_style == kCompactionStyleFIFO) {
|
||||
output_level = level;
|
||||
} else if (level == max_overlapped_level && level > 0) {
|
||||
if (options.bottommost_level_compaction ==
|
||||
BottommostLevelCompaction::kSkip) {
|
||||
// Skip bottommost level compaction
|
||||
continue;
|
||||
} else if (options.bottommost_level_compaction ==
|
||||
BottommostLevelCompaction::kIfHaveCompactionFilter &&
|
||||
cfd->ioptions()->compaction_filter == nullptr &&
|
||||
cfd->ioptions()->compaction_filter_factory == nullptr) {
|
||||
// Skip bottommost level compaction since we don't have a compaction
|
||||
// filter
|
||||
continue;
|
||||
}
|
||||
output_level = level;
|
||||
// update max_file_num_to_ignore only for bottom level compaction
|
||||
// because data in newly compacted files in middle levels may still
|
||||
// need to be pushed down
|
||||
max_file_num_to_ignore = next_file_number;
|
||||
} else {
|
||||
output_level = level + 1;
|
||||
if (cfd->ioptions()->compaction_style == kCompactionStyleLevel &&
|
||||
cfd->ioptions()->level_compaction_dynamic_level_bytes &&
|
||||
level == 0) {
|
||||
output_level = ColumnFamilyData::kCompactToBaseLevel;
|
||||
}
|
||||
}
|
||||
output_level = level;
|
||||
// update max_file_num_to_ignore only for bottom level compaction
|
||||
// because data in newly compacted files in middle levels may still need
|
||||
// to be pushed down
|
||||
max_file_num_to_ignore = next_file_number;
|
||||
} else {
|
||||
output_level = level + 1;
|
||||
if (cfd->ioptions()->compaction_style == kCompactionStyleLevel &&
|
||||
cfd->ioptions()->level_compaction_dynamic_level_bytes &&
|
||||
level == 0) {
|
||||
output_level = ColumnFamilyData::kCompactToBaseLevel;
|
||||
s = RunManualCompaction(cfd, level, output_level, options, begin, end,
|
||||
exclusive, false, max_file_num_to_ignore);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
if (output_level == ColumnFamilyData::kCompactToBaseLevel) {
|
||||
final_output_level = cfd->NumberLevels() - 1;
|
||||
} else if (output_level > final_output_level) {
|
||||
final_output_level = output_level;
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction()::1");
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction()::2");
|
||||
}
|
||||
s = RunManualCompaction(cfd, level, output_level, options, begin, end,
|
||||
exclusive, false, max_file_num_to_ignore);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
if (output_level == ColumnFamilyData::kCompactToBaseLevel) {
|
||||
final_output_level = cfd->NumberLevels() - 1;
|
||||
} else if (output_level > final_output_level) {
|
||||
final_output_level = output_level;
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction()::1");
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction()::2");
|
||||
}
|
||||
}
|
||||
if (!s.ok()) {
|
||||
if (!s.ok() || final_output_level == kInvalidLevel) {
|
||||
LogFlush(immutable_db_options_.info_log);
|
||||
return s;
|
||||
}
|
||||
@@ -977,7 +991,7 @@ Status DBImpl::CompactFilesImpl(
|
||||
CompactionJobStats compaction_job_stats;
|
||||
CompactionJob compaction_job(
|
||||
job_context->job_id, c.get(), immutable_db_options_,
|
||||
env_options_for_compaction_, versions_.get(), &shutting_down_,
|
||||
file_options_for_compaction_, versions_.get(), &shutting_down_,
|
||||
preserve_deletes_seqnum_.load(), log_buffer, directories_.GetDbDir(),
|
||||
GetDataDir(c->column_family_data(), c->output_path_id()), stats_, &mutex_,
|
||||
&error_handler_, snapshot_seqs, earliest_write_conflict_snapshot,
|
||||
@@ -1045,7 +1059,7 @@ Status DBImpl::CompactFilesImpl(
|
||||
}
|
||||
|
||||
if (output_file_names != nullptr) {
|
||||
for (const auto newf : c->edit()->GetNewFiles()) {
|
||||
for (const auto& newf : c->edit()->GetNewFiles()) {
|
||||
(*output_file_names)
|
||||
.push_back(TableFileName(c->immutable_cf_options()->cf_paths,
|
||||
newf.second.fd.GetNumber(),
|
||||
@@ -1116,7 +1130,7 @@ void DBImpl::NotifyOnCompactionBegin(ColumnFamilyData* cfd, Compaction* c,
|
||||
mutex_.Unlock();
|
||||
TEST_SYNC_POINT("DBImpl::NotifyOnCompactionBegin::UnlockMutex");
|
||||
{
|
||||
CompactionJobInfo info;
|
||||
CompactionJobInfo info{};
|
||||
info.cf_name = cfd->GetName();
|
||||
info.status = st;
|
||||
info.thread_id = env_->GetThreadID();
|
||||
@@ -1129,9 +1143,13 @@ void DBImpl::NotifyOnCompactionBegin(ColumnFamilyData* cfd, Compaction* c,
|
||||
info.compression = c->output_compression();
|
||||
for (size_t i = 0; i < c->num_input_levels(); ++i) {
|
||||
for (const auto fmd : *c->inputs(i)) {
|
||||
const FileDescriptor& desc = fmd->fd;
|
||||
const uint64_t file_number = desc.GetNumber();
|
||||
auto fn = TableFileName(c->immutable_cf_options()->cf_paths,
|
||||
fmd->fd.GetNumber(), fmd->fd.GetPathId());
|
||||
file_number, desc.GetPathId());
|
||||
info.input_files.push_back(fn);
|
||||
info.input_file_infos.push_back(CompactionFileInfo{
|
||||
static_cast<int>(i), file_number, fmd->oldest_blob_file_number});
|
||||
if (info.table_properties.count(fn) == 0) {
|
||||
std::shared_ptr<const TableProperties> tp;
|
||||
auto s = current->GetTableProperties(&tp, fmd, &fn);
|
||||
@@ -1141,10 +1159,14 @@ void DBImpl::NotifyOnCompactionBegin(ColumnFamilyData* cfd, Compaction* c,
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto newf : c->edit()->GetNewFiles()) {
|
||||
for (const auto& newf : c->edit()->GetNewFiles()) {
|
||||
const FileMetaData& meta = newf.second;
|
||||
const FileDescriptor& desc = meta.fd;
|
||||
const uint64_t file_number = desc.GetNumber();
|
||||
info.output_files.push_back(TableFileName(
|
||||
c->immutable_cf_options()->cf_paths, newf.second.fd.GetNumber(),
|
||||
newf.second.fd.GetPathId()));
|
||||
c->immutable_cf_options()->cf_paths, file_number, desc.GetPathId()));
|
||||
info.output_file_infos.push_back(CompactionFileInfo{
|
||||
newf.first, file_number, meta.oldest_blob_file_number});
|
||||
}
|
||||
for (auto listener : immutable_db_options_.listeners) {
|
||||
listener->OnCompactionBegin(this, info);
|
||||
@@ -1182,7 +1204,7 @@ void DBImpl::NotifyOnCompactionCompleted(
|
||||
mutex_.Unlock();
|
||||
TEST_SYNC_POINT("DBImpl::NotifyOnCompactionCompleted::UnlockMutex");
|
||||
{
|
||||
CompactionJobInfo info;
|
||||
CompactionJobInfo info{};
|
||||
BuildCompactionJobInfo(cfd, c, st, compaction_job_stats, job_id, current,
|
||||
&info);
|
||||
for (auto listener : immutable_db_options_.listeners) {
|
||||
@@ -1257,7 +1279,9 @@ Status DBImpl::ReFitLevel(ColumnFamilyData* cfd, int level, int target_level) {
|
||||
edit.AddFile(to_level, f->fd.GetNumber(), f->fd.GetPathId(),
|
||||
f->fd.GetFileSize(), f->smallest, f->largest,
|
||||
f->fd.smallest_seqno, f->fd.largest_seqno,
|
||||
f->marked_for_compaction, f->oldest_blob_file_number);
|
||||
f->marked_for_compaction, f->oldest_blob_file_number,
|
||||
f->oldest_ancester_time, f->file_creation_time,
|
||||
f->file_checksum, f->file_checksum_func_name);
|
||||
}
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log,
|
||||
"[%s] Apply version edit:\n%s", cfd->GetName().c_str(),
|
||||
@@ -1533,9 +1557,14 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
|
||||
WriteThread::Writer w;
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (!writes_stopped) {
|
||||
write_thread_.EnterUnbatched(&w, &mutex_);
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
}
|
||||
}
|
||||
WaitForPendingWrites();
|
||||
|
||||
if (!cfd->mem()->IsEmpty() || !cached_recoverable_state_empty_.load()) {
|
||||
s = SwitchMemtable(cfd, &context);
|
||||
@@ -1597,6 +1626,9 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
|
||||
|
||||
if (!writes_stopped) {
|
||||
write_thread_.ExitUnbatched(&w);
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::FlushMemTable:AfterScheduleFlush");
|
||||
@@ -1610,19 +1642,16 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
|
||||
}
|
||||
s = WaitForFlushMemTables(cfds, flush_memtable_ids,
|
||||
(flush_reason == FlushReason::kErrorRecovery));
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
for (auto* tmp_cfd : cfds) {
|
||||
if (tmp_cfd->Unref()) {
|
||||
// Only one thread can reach here.
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
delete tmp_cfd;
|
||||
}
|
||||
tmp_cfd->UnrefAndTryDelete();
|
||||
}
|
||||
}
|
||||
TEST_SYNC_POINT("FlushMemTableFinished");
|
||||
TEST_SYNC_POINT("DBImpl::FlushMemTable:FlushMemTableFinished");
|
||||
return s;
|
||||
}
|
||||
|
||||
// Flush all elments in 'column_family_datas'
|
||||
// Flush all elements in 'column_family_datas'
|
||||
// and atomically record the result to the MANIFEST.
|
||||
Status DBImpl::AtomicFlushMemTables(
|
||||
const autovector<ColumnFamilyData*>& column_family_datas,
|
||||
@@ -1651,9 +1680,14 @@ Status DBImpl::AtomicFlushMemTables(
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
|
||||
WriteThread::Writer w;
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (!writes_stopped) {
|
||||
write_thread_.EnterUnbatched(&w, &mutex_);
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
}
|
||||
}
|
||||
WaitForPendingWrites();
|
||||
|
||||
for (auto cfd : column_family_datas) {
|
||||
if (cfd->IsDropped()) {
|
||||
@@ -1670,7 +1704,7 @@ Status DBImpl::AtomicFlushMemTables(
|
||||
}
|
||||
cfd->Ref();
|
||||
s = SwitchMemtable(cfd, &context);
|
||||
cfd->Unref();
|
||||
cfd->UnrefAndTryDelete();
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
@@ -1696,6 +1730,9 @@ Status DBImpl::AtomicFlushMemTables(
|
||||
|
||||
if (!writes_stopped) {
|
||||
write_thread_.ExitUnbatched(&w);
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::AtomicFlushMemTables:AfterScheduleFlush");
|
||||
@@ -1707,12 +1744,9 @@ Status DBImpl::AtomicFlushMemTables(
|
||||
}
|
||||
s = WaitForFlushMemTables(cfds, flush_memtable_ids,
|
||||
(flush_reason == FlushReason::kErrorRecovery));
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
for (auto* cfd : cfds) {
|
||||
if (cfd->Unref()) {
|
||||
// Only one thread can reach here.
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
delete cfd;
|
||||
}
|
||||
cfd->UnrefAndTryDelete();
|
||||
}
|
||||
}
|
||||
return s;
|
||||
@@ -1904,6 +1938,10 @@ void DBImpl::MaybeScheduleFlushOrCompaction() {
|
||||
fta->thread_pri_ = Env::Priority::HIGH;
|
||||
env_->Schedule(&DBImpl::BGWorkFlush, fta, Env::Priority::HIGH, this,
|
||||
&DBImpl::UnscheduleFlushCallback);
|
||||
--unscheduled_flushes_;
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"DBImpl::MaybeScheduleFlushOrCompaction:AfterSchedule:0",
|
||||
&unscheduled_flushes_);
|
||||
}
|
||||
|
||||
// special case -- if high-pri (flush) thread pool is empty, then schedule
|
||||
@@ -1918,6 +1956,7 @@ void DBImpl::MaybeScheduleFlushOrCompaction() {
|
||||
fta->thread_pri_ = Env::Priority::LOW;
|
||||
env_->Schedule(&DBImpl::BGWorkFlush, fta, Env::Priority::LOW, this,
|
||||
&DBImpl::UnscheduleFlushCallback);
|
||||
--unscheduled_flushes_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2001,8 +2040,6 @@ ColumnFamilyData* DBImpl::PopFirstFromCompactionQueue() {
|
||||
DBImpl::FlushRequest DBImpl::PopFirstFromFlushQueue() {
|
||||
assert(!flush_queue_.empty());
|
||||
FlushRequest flush_req = flush_queue_.front();
|
||||
assert(unscheduled_flushes_ >= static_cast<int>(flush_req.size()));
|
||||
unscheduled_flushes_ -= static_cast<int>(flush_req.size());
|
||||
flush_queue_.pop_front();
|
||||
// TODO: need to unset flush reason?
|
||||
return flush_req;
|
||||
@@ -2044,7 +2081,7 @@ void DBImpl::SchedulePendingFlush(const FlushRequest& flush_req,
|
||||
cfd->Ref();
|
||||
cfd->SetFlushReason(flush_reason);
|
||||
}
|
||||
unscheduled_flushes_ += static_cast<int>(flush_req.size());
|
||||
++unscheduled_flushes_;
|
||||
flush_queue_.push_back(flush_req);
|
||||
}
|
||||
|
||||
@@ -2190,16 +2227,13 @@ Status DBImpl::BackgroundFlush(bool* made_progress, JobContext* job_context,
|
||||
*reason = bg_flush_args[0].cfd_->GetFlushReason();
|
||||
for (auto& arg : bg_flush_args) {
|
||||
ColumnFamilyData* cfd = arg.cfd_;
|
||||
if (cfd->Unref()) {
|
||||
delete cfd;
|
||||
if (cfd->UnrefAndTryDelete()) {
|
||||
arg.cfd_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto cfd : column_families_not_to_flush) {
|
||||
if (cfd->Unref()) {
|
||||
delete cfd;
|
||||
}
|
||||
cfd->UnrefAndTryDelete();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -2528,10 +2562,9 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
// reference).
|
||||
// This will all happen under a mutex so we don't have to be afraid of
|
||||
// somebody else deleting it.
|
||||
if (cfd->Unref()) {
|
||||
if (cfd->UnrefAndTryDelete()) {
|
||||
// This was the last reference of the column family, so no need to
|
||||
// compact.
|
||||
delete cfd;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -2658,7 +2691,9 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
f->fd.GetPathId(), f->fd.GetFileSize(), f->smallest,
|
||||
f->largest, f->fd.smallest_seqno,
|
||||
f->fd.largest_seqno, f->marked_for_compaction,
|
||||
f->oldest_blob_file_number);
|
||||
f->oldest_blob_file_number, f->oldest_ancester_time,
|
||||
f->file_creation_time, f->file_checksum,
|
||||
f->file_checksum_func_name);
|
||||
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer,
|
||||
@@ -2737,7 +2772,7 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
assert(is_snapshot_supported_ || snapshots_.empty());
|
||||
CompactionJob compaction_job(
|
||||
job_context->job_id, c.get(), immutable_db_options_,
|
||||
env_options_for_compaction_, versions_.get(), &shutting_down_,
|
||||
file_options_for_compaction_, versions_.get(), &shutting_down_,
|
||||
preserve_deletes_seqnum_.load(), log_buffer, directories_.GetDbDir(),
|
||||
GetDataDir(c->column_family_data(), c->output_path_id()), stats_,
|
||||
&mutex_, &error_handler_, snapshot_seqs,
|
||||
@@ -2967,9 +3002,13 @@ void DBImpl::BuildCompactionJobInfo(
|
||||
compaction_job_info->compression = c->output_compression();
|
||||
for (size_t i = 0; i < c->num_input_levels(); ++i) {
|
||||
for (const auto fmd : *c->inputs(i)) {
|
||||
auto fn = TableFileName(c->immutable_cf_options()->cf_paths,
|
||||
fmd->fd.GetNumber(), fmd->fd.GetPathId());
|
||||
const FileDescriptor& desc = fmd->fd;
|
||||
const uint64_t file_number = desc.GetNumber();
|
||||
auto fn = TableFileName(c->immutable_cf_options()->cf_paths, file_number,
|
||||
desc.GetPathId());
|
||||
compaction_job_info->input_files.push_back(fn);
|
||||
compaction_job_info->input_file_infos.push_back(CompactionFileInfo{
|
||||
static_cast<int>(i), file_number, fmd->oldest_blob_file_number});
|
||||
if (compaction_job_info->table_properties.count(fn) == 0) {
|
||||
std::shared_ptr<const TableProperties> tp;
|
||||
auto s = current->GetTableProperties(&tp, fmd, &fn);
|
||||
@@ -2980,9 +3019,13 @@ void DBImpl::BuildCompactionJobInfo(
|
||||
}
|
||||
}
|
||||
for (const auto& newf : c->edit()->GetNewFiles()) {
|
||||
compaction_job_info->output_files.push_back(
|
||||
TableFileName(c->immutable_cf_options()->cf_paths,
|
||||
newf.second.fd.GetNumber(), newf.second.fd.GetPathId()));
|
||||
const FileMetaData& meta = newf.second;
|
||||
const FileDescriptor& desc = meta.fd;
|
||||
const uint64_t file_number = desc.GetNumber();
|
||||
compaction_job_info->output_files.push_back(TableFileName(
|
||||
c->immutable_cf_options()->cf_paths, file_number, desc.GetPathId()));
|
||||
compaction_job_info->output_file_infos.push_back(CompactionFileInfo{
|
||||
newf.first, file_number, meta.oldest_blob_file_number});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -3092,4 +3135,4 @@ void DBImpl::GetSnapshotContext(
|
||||
}
|
||||
*snapshot_seqs = snapshots_.GetAll(earliest_write_conflict_snapshot);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "monitoring/thread_status_updater.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
uint64_t DBImpl::TEST_GetLevel0TotalSize() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
return default_cf_handle_->cfd()->current()->storage_info()->NumLevelBytes(0);
|
||||
@@ -24,7 +24,9 @@ uint64_t DBImpl::TEST_GetLevel0TotalSize() {
|
||||
void DBImpl::TEST_SwitchWAL() {
|
||||
WriteContext write_context;
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
void* writer = TEST_BeginWrite();
|
||||
SwitchWAL(&write_context);
|
||||
TEST_EndWrite(writer);
|
||||
}
|
||||
|
||||
bool DBImpl::TEST_WALBufferIsEmpty(bool lock) {
|
||||
@@ -105,7 +107,19 @@ Status DBImpl::TEST_SwitchMemtable(ColumnFamilyData* cfd) {
|
||||
if (cfd == nullptr) {
|
||||
cfd = default_cf_handle_->cfd();
|
||||
}
|
||||
return SwitchMemtable(cfd, &write_context);
|
||||
|
||||
Status s;
|
||||
void* writer = TEST_BeginWrite();
|
||||
if (two_write_queues_) {
|
||||
WriteThread::Writer nonmem_w;
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
s = SwitchMemtable(cfd, &write_context);
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
} else {
|
||||
s = SwitchMemtable(cfd, &write_context);
|
||||
}
|
||||
TEST_EndWrite(writer);
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::TEST_FlushMemTable(bool wait, bool allow_write_stall,
|
||||
@@ -276,5 +290,5 @@ bool DBImpl::TEST_IsPersistentStatsEnabled() const {
|
||||
size_t DBImpl::TEST_EstimateInMemoryStatsHistorySize() const {
|
||||
return EstimateInMemoryStatsHistorySize();
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // NDEBUG
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "db/version_set.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
Status DBImpl::SuggestCompactRange(ColumnFamilyHandle* column_family,
|
||||
@@ -128,7 +128,9 @@ Status DBImpl::PromoteL0(ColumnFamilyHandle* column_family, int target_level) {
|
||||
edit.AddFile(target_level, f->fd.GetNumber(), f->fd.GetPathId(),
|
||||
f->fd.GetFileSize(), f->smallest, f->largest,
|
||||
f->fd.smallest_seqno, f->fd.largest_seqno,
|
||||
f->marked_for_compaction, f->oldest_blob_file_number);
|
||||
f->marked_for_compaction, f->oldest_blob_file_number,
|
||||
f->oldest_ancester_time, f->file_creation_time,
|
||||
f->file_checksum, f->file_checksum_func_name);
|
||||
}
|
||||
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
@@ -146,4 +148,4 @@ Status DBImpl::PromoteL0(ColumnFamilyHandle* column_family, int target_level) {
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "file/sst_file_manager_impl.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
uint64_t DBImpl::MinLogNumberToKeep() {
|
||||
if (allow_2pc()) {
|
||||
@@ -385,6 +385,7 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
|
||||
w->Close();
|
||||
}
|
||||
|
||||
bool own_files = OwnTablesAndLogs();
|
||||
std::unordered_set<uint64_t> files_to_del;
|
||||
for (const auto& candidate_file : candidate_files) {
|
||||
const std::string& to_delete = candidate_file.file_name;
|
||||
@@ -484,6 +485,12 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
// If I do not own these files, e.g. secondary instance with max_open_files
|
||||
// = -1, then no need to delete or schedule delete these files since they
|
||||
// will be removed by their owner, e.g. the primary instance.
|
||||
if (!own_files) {
|
||||
continue;
|
||||
}
|
||||
Status file_deletion_status;
|
||||
if (schedule_only) {
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
@@ -495,7 +502,6 @@ void DBImpl::PurgeObsoleteFiles(JobContext& state, bool schedule_only) {
|
||||
|
||||
{
|
||||
// After purging obsolete files, remove them from files_grabbed_for_purge_.
|
||||
// Use a temporary vector to perform bulk deletion via swap.
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
autovector<uint64_t> to_be_removed;
|
||||
for (auto fn : files_grabbed_for_purge_) {
|
||||
@@ -612,9 +618,9 @@ uint64_t PrecomputeMinLogNumberToKeep(
|
||||
// family being flushed (`cfd_to_flush`).
|
||||
uint64_t cf_min_log_number_to_keep = 0;
|
||||
for (auto& e : edit_list) {
|
||||
if (e->has_log_number()) {
|
||||
if (e->HasLogNumber()) {
|
||||
cf_min_log_number_to_keep =
|
||||
std::max(cf_min_log_number_to_keep, e->log_number());
|
||||
std::max(cf_min_log_number_to_keep, e->GetLogNumber());
|
||||
}
|
||||
}
|
||||
if (cf_min_log_number_to_keep == 0) {
|
||||
@@ -658,4 +664,4 @@ uint64_t PrecomputeMinLogNumberToKeep(
|
||||
return min_log_number_to_keep;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+208
-103
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "db/builder.h"
|
||||
#include "db/error_handler.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/read_write_util.h"
|
||||
#include "file/sst_file_manager_impl.h"
|
||||
#include "file/writable_file_writer.h"
|
||||
@@ -22,7 +23,7 @@
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/rate_limiter.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
Options SanitizeOptions(const std::string& dbname, const Options& src) {
|
||||
auto db_options = SanitizeOptions(dbname, DBOptions(src));
|
||||
ImmutableDBOptions immutable_db_options(db_options);
|
||||
@@ -34,6 +35,18 @@ Options SanitizeOptions(const std::string& dbname, const Options& src) {
|
||||
DBOptions SanitizeOptions(const std::string& dbname, const DBOptions& src) {
|
||||
DBOptions result(src);
|
||||
|
||||
if (result.file_system == nullptr) {
|
||||
if (result.env == Env::Default()) {
|
||||
result.file_system = FileSystem::Default();
|
||||
} else {
|
||||
result.file_system.reset(new LegacyFileSystemWrapper(result.env));
|
||||
}
|
||||
} else {
|
||||
if (result.env == nullptr) {
|
||||
result.env = Env::Default();
|
||||
}
|
||||
}
|
||||
|
||||
// result.max_open_files means an "infinite" open files.
|
||||
if (result.max_open_files != -1) {
|
||||
int max_max_open_files = port::GetMaxOpenFiles();
|
||||
@@ -87,12 +100,11 @@ DBOptions SanitizeOptions(const std::string& dbname, const DBOptions& src) {
|
||||
if (result.recycle_log_file_num &&
|
||||
(result.wal_recovery_mode == WALRecoveryMode::kPointInTimeRecovery ||
|
||||
result.wal_recovery_mode == WALRecoveryMode::kAbsoluteConsistency)) {
|
||||
// kPointInTimeRecovery is indistinguishable from
|
||||
// kTolerateCorruptedTailRecords in recycle mode since we define
|
||||
// the "end" of the log as the first corrupt record we encounter.
|
||||
// kPointInTimeRecovery is inconsistent with recycle log file feature since
|
||||
// we define the "end" of the log as the first corrupt record we encounter.
|
||||
// kAbsoluteConsistency doesn't make sense because even a clean
|
||||
// shutdown leaves old junk at the end of the log file.
|
||||
result.wal_recovery_mode = WALRecoveryMode::kTolerateCorruptedTailRecords;
|
||||
result.recycle_log_file_num = 0;
|
||||
}
|
||||
|
||||
if (result.wal_dir.empty()) {
|
||||
@@ -160,6 +172,13 @@ DBOptions SanitizeOptions(const std::string& dbname, const DBOptions& src) {
|
||||
result.sst_file_manager = sst_file_manager;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!result.paranoid_checks) {
|
||||
result.skip_checking_sst_file_sizes_on_db_open = true;
|
||||
ROCKS_LOG_INFO(result.info_log,
|
||||
"file size check will be skipped during open.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -254,16 +273,16 @@ Status DBImpl::NewDB() {
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log, "Creating manifest 1 \n");
|
||||
const std::string manifest = DescriptorFileName(dbname_, 1);
|
||||
{
|
||||
std::unique_ptr<WritableFile> file;
|
||||
EnvOptions env_options = env_->OptimizeForManifestWrite(env_options_);
|
||||
s = NewWritableFile(env_, manifest, &file, env_options);
|
||||
std::unique_ptr<FSWritableFile> file;
|
||||
FileOptions file_options = fs_->OptimizeForManifestWrite(file_options_);
|
||||
s = NewWritableFile(fs_.get(), manifest, &file, file_options);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
file->SetPreallocationBlockSize(
|
||||
immutable_db_options_.manifest_preallocation_size);
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(file), manifest, env_options, env_, nullptr /* stats */,
|
||||
std::move(file), manifest, file_options, env_, nullptr /* stats */,
|
||||
immutable_db_options_.listeners));
|
||||
log::Writer log(std::move(file_writer), 0, false);
|
||||
std::string record;
|
||||
@@ -277,13 +296,14 @@ Status DBImpl::NewDB() {
|
||||
// Make "CURRENT" file that points to the new manifest file.
|
||||
s = SetCurrentFile(env_, dbname_, 1, directories_.GetDbDir());
|
||||
} else {
|
||||
env_->DeleteFile(manifest);
|
||||
fs_->DeleteFile(manifest, IOOptions(), nullptr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::CreateAndNewDirectory(Env* env, const std::string& dirname,
|
||||
std::unique_ptr<Directory>* directory) {
|
||||
IOStatus DBImpl::CreateAndNewDirectory(
|
||||
FileSystem* fs, const std::string& dirname,
|
||||
std::unique_ptr<FSDirectory>* directory) {
|
||||
// We call CreateDirIfMissing() as the directory may already exist (if we
|
||||
// are reopening a DB), when this happens we don't want creating the
|
||||
// directory to cause an error. However, we need to check if creating the
|
||||
@@ -291,24 +311,24 @@ Status DBImpl::CreateAndNewDirectory(Env* env, const std::string& dirname,
|
||||
// file not existing. One real-world example of this occurring is if
|
||||
// env->CreateDirIfMissing() doesn't create intermediate directories, e.g.
|
||||
// when dbname_ is "dir/db" but when "dir" doesn't exist.
|
||||
Status s = env->CreateDirIfMissing(dirname);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
IOStatus io_s = fs->CreateDirIfMissing(dirname, IOOptions(), nullptr);
|
||||
if (!io_s.ok()) {
|
||||
return io_s;
|
||||
}
|
||||
return env->NewDirectory(dirname, directory);
|
||||
return fs->NewDirectory(dirname, IOOptions(), directory, nullptr);
|
||||
}
|
||||
|
||||
Status Directories::SetDirectories(Env* env, const std::string& dbname,
|
||||
const std::string& wal_dir,
|
||||
const std::vector<DbPath>& data_paths) {
|
||||
Status s = DBImpl::CreateAndNewDirectory(env, dbname, &db_dir_);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
IOStatus Directories::SetDirectories(FileSystem* fs, const std::string& dbname,
|
||||
const std::string& wal_dir,
|
||||
const std::vector<DbPath>& data_paths) {
|
||||
IOStatus io_s = DBImpl::CreateAndNewDirectory(fs, dbname, &db_dir_);
|
||||
if (!io_s.ok()) {
|
||||
return io_s;
|
||||
}
|
||||
if (!wal_dir.empty() && dbname != wal_dir) {
|
||||
s = DBImpl::CreateAndNewDirectory(env, wal_dir, &wal_dir_);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
io_s = DBImpl::CreateAndNewDirectory(fs, wal_dir, &wal_dir_);
|
||||
if (!io_s.ok()) {
|
||||
return io_s;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,27 +338,28 @@ Status Directories::SetDirectories(Env* env, const std::string& dbname,
|
||||
if (db_path == dbname) {
|
||||
data_dirs_.emplace_back(nullptr);
|
||||
} else {
|
||||
std::unique_ptr<Directory> path_directory;
|
||||
s = DBImpl::CreateAndNewDirectory(env, db_path, &path_directory);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
std::unique_ptr<FSDirectory> path_directory;
|
||||
io_s = DBImpl::CreateAndNewDirectory(fs, db_path, &path_directory);
|
||||
if (!io_s.ok()) {
|
||||
return io_s;
|
||||
}
|
||||
data_dirs_.emplace_back(path_directory.release());
|
||||
}
|
||||
}
|
||||
assert(data_dirs_.size() == data_paths.size());
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
|
||||
Status DBImpl::Recover(
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families, bool read_only,
|
||||
bool error_if_log_file_exist, bool error_if_data_exists_in_logs) {
|
||||
bool error_if_log_file_exist, bool error_if_data_exists_in_logs,
|
||||
uint64_t* recovered_seq) {
|
||||
mutex_.AssertHeld();
|
||||
|
||||
bool is_new_db = false;
|
||||
assert(db_lock_ == nullptr);
|
||||
if (!read_only) {
|
||||
Status s = directories_.SetDirectories(env_, dbname_,
|
||||
Status s = directories_.SetDirectories(fs_.get(), dbname_,
|
||||
immutable_db_options_.wal_dir,
|
||||
immutable_db_options_.db_paths);
|
||||
if (!s.ok()) {
|
||||
@@ -350,12 +371,10 @@ Status DBImpl::Recover(
|
||||
return s;
|
||||
}
|
||||
|
||||
s = env_->FileExists(CurrentFileName(dbname_));
|
||||
std::string current_fname = CurrentFileName(dbname_);
|
||||
s = env_->FileExists(current_fname);
|
||||
if (s.IsNotFound()) {
|
||||
if (immutable_db_options_.create_if_missing) {
|
||||
// Has to be called only after Identity File creation is successful
|
||||
// because DB ID is stored in Manifest if
|
||||
// immutable_db_options_.write_dbid_to_manifest = true
|
||||
s = NewDB();
|
||||
is_new_db = true;
|
||||
if (!s.ok()) {
|
||||
@@ -363,7 +382,7 @@ Status DBImpl::Recover(
|
||||
}
|
||||
} else {
|
||||
return Status::InvalidArgument(
|
||||
dbname_, "does not exist (create_if_missing is false)");
|
||||
current_fname, "does not exist (create_if_missing is false)");
|
||||
}
|
||||
} else if (s.ok()) {
|
||||
if (immutable_db_options_.error_if_exists) {
|
||||
@@ -375,20 +394,20 @@ Status DBImpl::Recover(
|
||||
assert(s.IsIOError());
|
||||
return s;
|
||||
}
|
||||
// Verify compatibility of env_options_ and filesystem
|
||||
// Verify compatibility of file_options_ and filesystem
|
||||
{
|
||||
std::unique_ptr<RandomAccessFile> idfile;
|
||||
EnvOptions customized_env(env_options_);
|
||||
customized_env.use_direct_reads |=
|
||||
std::unique_ptr<FSRandomAccessFile> idfile;
|
||||
FileOptions customized_fs(file_options_);
|
||||
customized_fs.use_direct_reads |=
|
||||
immutable_db_options_.use_direct_io_for_flush_and_compaction;
|
||||
s = env_->NewRandomAccessFile(CurrentFileName(dbname_), &idfile,
|
||||
customized_env);
|
||||
s = fs_->NewRandomAccessFile(current_fname, customized_fs, &idfile,
|
||||
nullptr);
|
||||
if (!s.ok()) {
|
||||
std::string error_str = s.ToString();
|
||||
// Check if unsupported Direct I/O is the root cause
|
||||
customized_env.use_direct_reads = false;
|
||||
s = env_->NewRandomAccessFile(CurrentFileName(dbname_), &idfile,
|
||||
customized_env);
|
||||
customized_fs.use_direct_reads = false;
|
||||
s = fs_->NewRandomAccessFile(current_fname, customized_fs, &idfile,
|
||||
nullptr);
|
||||
if (s.ok()) {
|
||||
return Status::InvalidArgument(
|
||||
"Direct I/O is not supported by the specified DB.");
|
||||
@@ -408,7 +427,7 @@ Status DBImpl::Recover(
|
||||
// the very first time.
|
||||
if (db_id_.empty()) {
|
||||
// Check for the IDENTITY file and create it if not there.
|
||||
s = env_->FileExists(IdentityFileName(dbname_));
|
||||
s = fs_->FileExists(IdentityFileName(dbname_), IOOptions(), nullptr);
|
||||
// Typically Identity file is created in NewDB() and for some reason if
|
||||
// it is no longer available then at this point DB ID is not in Identity
|
||||
// file or Manifest.
|
||||
@@ -421,27 +440,28 @@ Status DBImpl::Recover(
|
||||
assert(s.IsIOError());
|
||||
return s;
|
||||
}
|
||||
GetDbIdentityFromIdentityFile(&db_id_);
|
||||
if (immutable_db_options_.write_dbid_to_manifest) {
|
||||
s = GetDbIdentityFromIdentityFile(&db_id_);
|
||||
if (immutable_db_options_.write_dbid_to_manifest && s.ok()) {
|
||||
VersionEdit edit;
|
||||
edit.SetDBId(db_id_);
|
||||
Options options;
|
||||
MutableCFOptions mutable_cf_options(options);
|
||||
versions_->db_id_ = db_id_;
|
||||
versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(),
|
||||
s = versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(),
|
||||
mutable_cf_options, &edit, &mutex_, nullptr,
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
SetIdentityFile(env_, dbname_, db_id_);
|
||||
s = SetIdentityFile(env_, dbname_, db_id_);
|
||||
}
|
||||
|
||||
if (immutable_db_options_.paranoid_checks && s.ok()) {
|
||||
s = CheckConsistency();
|
||||
}
|
||||
if (s.ok() && !read_only) {
|
||||
std::map<std::string, std::shared_ptr<FSDirectory>> created_dirs;
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
s = cfd->AddDirectories();
|
||||
s = cfd->AddDirectories(&created_dirs);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -452,16 +472,16 @@ Status DBImpl::Recover(
|
||||
s = InitPersistStatsColumnFamily();
|
||||
}
|
||||
|
||||
// Initial max_total_in_memory_state_ before recovery logs. Log recovery
|
||||
// may check this value to decide whether to flush.
|
||||
max_total_in_memory_state_ = 0;
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
auto* mutable_cf_options = cfd->GetLatestMutableCFOptions();
|
||||
max_total_in_memory_state_ += mutable_cf_options->write_buffer_size *
|
||||
mutable_cf_options->max_write_buffer_number;
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
// Initial max_total_in_memory_state_ before recovery logs. Log recovery
|
||||
// may check this value to decide whether to flush.
|
||||
max_total_in_memory_state_ = 0;
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
auto* mutable_cf_options = cfd->GetLatestMutableCFOptions();
|
||||
max_total_in_memory_state_ += mutable_cf_options->write_buffer_size *
|
||||
mutable_cf_options->max_write_buffer_number;
|
||||
}
|
||||
|
||||
SequenceNumber next_sequence(kMaxSequenceNumber);
|
||||
default_cf_handle_ = new ColumnFamilyHandleImpl(
|
||||
versions_->GetColumnFamilySet()->GetDefault(), this, &mutex_);
|
||||
@@ -527,7 +547,12 @@ Status DBImpl::Recover(
|
||||
if (!logs.empty()) {
|
||||
// Recover in the order in which the logs were generated
|
||||
std::sort(logs.begin(), logs.end());
|
||||
s = RecoverLogFiles(logs, &next_sequence, read_only);
|
||||
bool corrupted_log_found = false;
|
||||
s = RecoverLogFiles(logs, &next_sequence, read_only,
|
||||
&corrupted_log_found);
|
||||
if (corrupted_log_found && recovered_seq != nullptr) {
|
||||
*recovered_seq = next_sequence;
|
||||
}
|
||||
if (!s.ok()) {
|
||||
// Clear memtables if recovery failed
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
@@ -657,7 +682,8 @@ Status DBImpl::InitPersistStatsColumnFamily() {
|
||||
|
||||
// REQUIRES: log_numbers are sorted in ascending order
|
||||
Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
SequenceNumber* next_sequence, bool read_only) {
|
||||
SequenceNumber* next_sequence, bool read_only,
|
||||
bool* corrupted_log_found) {
|
||||
struct LogReporter : public log::Reader::Reporter {
|
||||
Env* env;
|
||||
Logger* info_log;
|
||||
@@ -748,9 +774,10 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
|
||||
std::unique_ptr<SequentialFileReader> file_reader;
|
||||
{
|
||||
std::unique_ptr<SequentialFile> file;
|
||||
status = env_->NewSequentialFile(fname, &file,
|
||||
env_->OptimizeForLogRead(env_options_));
|
||||
std::unique_ptr<FSSequentialFile> file;
|
||||
status = fs_->NewSequentialFile(fname,
|
||||
fs_->OptimizeForLogRead(file_options_),
|
||||
&file, nullptr);
|
||||
if (!status.ok()) {
|
||||
MaybeIgnoreError(&status);
|
||||
if (!status.ok()) {
|
||||
@@ -920,7 +947,7 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
ColumnFamilyData* cfd;
|
||||
|
||||
while ((cfd = flush_scheduler_.TakeNextColumnFamily()) != nullptr) {
|
||||
cfd->Unref();
|
||||
cfd->UnrefAndTryDelete();
|
||||
// If this asserts, it means that InsertInto failed in
|
||||
// filtering updates to already-flushed column families
|
||||
assert(cfd->GetLogNumber() <= log_number);
|
||||
@@ -958,6 +985,9 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
status = Status::OK();
|
||||
stop_replay_for_corruption = true;
|
||||
corrupted_log_number = log_number;
|
||||
if (corrupted_log_found != nullptr) {
|
||||
*corrupted_log_found = true;
|
||||
}
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log,
|
||||
"Point in time recovered to log #%" PRIu64
|
||||
" seq #%" PRIu64,
|
||||
@@ -986,6 +1016,9 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
// the corrupted log number, which means CF contains data beyond the point of
|
||||
// corruption. This could during PIT recovery when the WAL is corrupted and
|
||||
// some (but not all) CFs are flushed
|
||||
// Exclude the PIT case where no log is dropped after the corruption point.
|
||||
// This is to cover the case for empty logs after corrupted log, in which we
|
||||
// don't reset stop_replay_for_corruption.
|
||||
if (stop_replay_for_corruption == true &&
|
||||
(immutable_db_options_.wal_recovery_mode ==
|
||||
WALRecoveryMode::kPointInTimeRecovery ||
|
||||
@@ -1023,6 +1056,9 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
continue;
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"DBImpl::RecoverLogFiles:BeforeFlushFinalMemtable", /*arg=*/nullptr);
|
||||
|
||||
// flush the final memtable (if non-empty)
|
||||
if (cfd->mem()->GetFirstSequenceNumber() != 0) {
|
||||
// If flush happened in the middle of recovery (e.g. due to memtable
|
||||
@@ -1042,7 +1078,9 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
data_seen = true;
|
||||
}
|
||||
|
||||
// write MANIFEST with update
|
||||
// Update the log number info in the version edit corresponding to this
|
||||
// column family. Note that the version edits will be written to MANIFEST
|
||||
// together later.
|
||||
// writing log_number in the manifest means that any log file
|
||||
// with number strongly less than (log_number + 1) is already
|
||||
// recovered and should be ignored on next reincarnation.
|
||||
@@ -1051,19 +1089,28 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
if (flushed || cfd->mem()->GetFirstSequenceNumber() == 0) {
|
||||
edit->SetLogNumber(max_log_number + 1);
|
||||
}
|
||||
}
|
||||
if (status.ok()) {
|
||||
// we must mark the next log number as used, even though it's
|
||||
// not actually used. that is because VersionSet assumes
|
||||
// VersionSet::next_file_number_ always to be strictly greater than any
|
||||
// log number
|
||||
versions_->MarkFileNumberUsed(max_log_number + 1);
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
edit, &mutex_);
|
||||
TEST_SYNC_POINT_CALLBACK("DBImpl::RecoverLogFiles:AfterLogAndApply",
|
||||
nullptr);
|
||||
if (!status.ok()) {
|
||||
// Recovery failed
|
||||
break;
|
||||
|
||||
autovector<ColumnFamilyData*> cfds;
|
||||
autovector<const MutableCFOptions*> cf_opts;
|
||||
autovector<autovector<VersionEdit*>> edit_lists;
|
||||
for (auto* cfd : *versions_->GetColumnFamilySet()) {
|
||||
cfds.push_back(cfd);
|
||||
cf_opts.push_back(cfd->GetLatestMutableCFOptions());
|
||||
auto iter = version_edits.find(cfd->GetID());
|
||||
assert(iter != version_edits.end());
|
||||
edit_lists.push_back({&iter->second});
|
||||
}
|
||||
// write MANIFEST with update
|
||||
status = versions_->LogAndApply(cfds, cf_opts, edit_lists, &mutex_,
|
||||
directories_.GetDbDir(),
|
||||
/*new_descriptor_log=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,17 +1152,18 @@ Status DBImpl::RestoreAliveLogFiles(const std::vector<uint64_t>& log_numbers) {
|
||||
// preallocated space are not needed anymore. It is likely only the last
|
||||
// log has such preallocated space, so we only truncate for the last log.
|
||||
if (log_number == log_numbers.back()) {
|
||||
std::unique_ptr<WritableFile> last_log;
|
||||
Status truncate_status = env_->ReopenWritableFile(
|
||||
fname, &last_log,
|
||||
env_->OptimizeForLogWrite(
|
||||
env_options_,
|
||||
BuildDBOptions(immutable_db_options_, mutable_db_options_)));
|
||||
std::unique_ptr<FSWritableFile> last_log;
|
||||
Status truncate_status = fs_->ReopenWritableFile(
|
||||
fname,
|
||||
fs_->OptimizeForLogWrite(
|
||||
file_options_,
|
||||
BuildDBOptions(immutable_db_options_, mutable_db_options_)),
|
||||
&last_log, nullptr);
|
||||
if (truncate_status.ok()) {
|
||||
truncate_status = last_log->Truncate(log.size);
|
||||
truncate_status = last_log->Truncate(log.size, IOOptions(), nullptr);
|
||||
}
|
||||
if (truncate_status.ok()) {
|
||||
truncate_status = last_log->Close();
|
||||
truncate_status = last_log->Close(IOOptions(), nullptr);
|
||||
}
|
||||
// Not a critical error if fail to truncate.
|
||||
if (!truncate_status.ok()) {
|
||||
@@ -1161,6 +1209,7 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
|
||||
int64_t _current_time = 0;
|
||||
env_->GetCurrentTime(&_current_time); // ignore error
|
||||
const uint64_t current_time = static_cast<uint64_t>(_current_time);
|
||||
meta.oldest_ancester_time = current_time;
|
||||
|
||||
{
|
||||
auto write_hint = cfd->CalculateSSTWriteHint(0);
|
||||
@@ -1181,8 +1230,8 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
|
||||
range_del_iters.emplace_back(range_del_iter);
|
||||
}
|
||||
s = BuildTable(
|
||||
dbname_, env_, *cfd->ioptions(), mutable_cf_options,
|
||||
env_options_for_compaction_, cfd->table_cache(), iter.get(),
|
||||
dbname_, env_, fs_.get(), *cfd->ioptions(), mutable_cf_options,
|
||||
file_options_for_compaction_, cfd->table_cache(), iter.get(),
|
||||
std::move(range_del_iters), &meta, cfd->internal_comparator(),
|
||||
cfd->int_tbl_prop_collector_factories(), cfd->GetID(), cfd->GetName(),
|
||||
snapshot_seqs, earliest_write_conflict_snapshot, snapshot_checker,
|
||||
@@ -1210,7 +1259,9 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
|
||||
edit->AddFile(level, meta.fd.GetNumber(), meta.fd.GetPathId(),
|
||||
meta.fd.GetFileSize(), meta.smallest, meta.largest,
|
||||
meta.fd.smallest_seqno, meta.fd.largest_seqno,
|
||||
meta.marked_for_compaction, meta.oldest_blob_file_number);
|
||||
meta.marked_for_compaction, meta.oldest_blob_file_number,
|
||||
meta.oldest_ancester_time, meta.file_creation_time,
|
||||
meta.file_checksum, meta.file_checksum_func_name);
|
||||
}
|
||||
|
||||
InternalStats::CompactionStats stats(CompactionReason::kFlush, 1);
|
||||
@@ -1264,12 +1315,12 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
Status DBImpl::CreateWAL(uint64_t log_file_num, uint64_t recycle_log_number,
|
||||
size_t preallocate_block_size, log::Writer** new_log) {
|
||||
Status s;
|
||||
std::unique_ptr<WritableFile> lfile;
|
||||
std::unique_ptr<FSWritableFile> lfile;
|
||||
|
||||
DBOptions db_options =
|
||||
BuildDBOptions(immutable_db_options_, mutable_db_options_);
|
||||
EnvOptions opt_env_options =
|
||||
env_->OptimizeForLogWrite(env_options_, db_options);
|
||||
FileOptions opt_file_options =
|
||||
fs_->OptimizeForLogWrite(file_options_, db_options);
|
||||
std::string log_fname =
|
||||
LogFileName(immutable_db_options_.wal_dir, log_file_num);
|
||||
|
||||
@@ -1279,10 +1330,12 @@ Status DBImpl::CreateWAL(uint64_t log_file_num, uint64_t recycle_log_number,
|
||||
recycle_log_number);
|
||||
std::string old_log_fname =
|
||||
LogFileName(immutable_db_options_.wal_dir, recycle_log_number);
|
||||
s = env_->ReuseWritableFile(log_fname, old_log_fname, &lfile,
|
||||
opt_env_options);
|
||||
TEST_SYNC_POINT("DBImpl::CreateWAL:BeforeReuseWritableFile1");
|
||||
TEST_SYNC_POINT("DBImpl::CreateWAL:BeforeReuseWritableFile2");
|
||||
s = fs_->ReuseWritableFile(log_fname, old_log_fname, opt_file_options,
|
||||
&lfile, /*dbg=*/nullptr);
|
||||
} else {
|
||||
s = NewWritableFile(env_, log_fname, &lfile, opt_env_options);
|
||||
s = NewWritableFile(fs_.get(), log_fname, &lfile, opt_file_options);
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
@@ -1291,7 +1344,7 @@ Status DBImpl::CreateWAL(uint64_t log_file_num, uint64_t recycle_log_number,
|
||||
|
||||
const auto& listeners = immutable_db_options_.listeners;
|
||||
std::unique_ptr<WritableFileWriter> file_writer(
|
||||
new WritableFileWriter(std::move(lfile), log_fname, opt_env_options,
|
||||
new WritableFileWriter(std::move(lfile), log_fname, opt_file_options,
|
||||
env_, nullptr /* stats */, listeners));
|
||||
*new_log = new log::Writer(std::move(file_writer), log_file_num,
|
||||
immutable_db_options_.recycle_log_file_num > 0,
|
||||
@@ -1348,13 +1401,9 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
impl->error_handler_.EnableAutoRecovery();
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.ok()) {
|
||||
delete impl;
|
||||
return s;
|
||||
if (s.ok()) {
|
||||
s = impl->CreateArchivalDirectory();
|
||||
}
|
||||
|
||||
s = impl->CreateArchivalDirectory();
|
||||
if (!s.ok()) {
|
||||
delete impl;
|
||||
return s;
|
||||
@@ -1364,7 +1413,8 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
|
||||
impl->mutex_.Lock();
|
||||
// Handles create_if_missing, error_if_exists
|
||||
s = impl->Recover(column_families);
|
||||
uint64_t recovered_seq(kMaxSequenceNumber);
|
||||
s = impl->Recover(column_families, false, false, false, &recovered_seq);
|
||||
if (s.ok()) {
|
||||
uint64_t new_log_number = impl->versions_->NewFileNumber();
|
||||
log::Writer* new_log = nullptr;
|
||||
@@ -1422,8 +1472,35 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
if (impl->two_write_queues_) {
|
||||
impl->log_write_mutex_.Unlock();
|
||||
}
|
||||
|
||||
impl->DeleteObsoleteFiles();
|
||||
s = impl->directories_.GetDbDir()->Fsync();
|
||||
s = impl->directories_.GetDbDir()->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
// In WritePrepared there could be gap in sequence numbers. This breaks
|
||||
// the trick we use in kPointInTimeRecovery which assumes the first seq in
|
||||
// the log right after the corrupted log is one larger than the last seq
|
||||
// we read from the logs. To let this trick keep working, we add a dummy
|
||||
// entry with the expected sequence to the first log right after recovery.
|
||||
// In non-WritePrepared case also the new log after recovery could be
|
||||
// empty, and thus missing the consecutive seq hint to distinguish
|
||||
// middle-log corruption to corrupted-log-remained-after-recovery. This
|
||||
// case also will be addressed by a dummy write.
|
||||
if (recovered_seq != kMaxSequenceNumber) {
|
||||
WriteBatch empty_batch;
|
||||
WriteBatchInternal::SetSequence(&empty_batch, recovered_seq);
|
||||
WriteOptions write_options;
|
||||
uint64_t log_used, log_size;
|
||||
log::Writer* log_writer = impl->logs_.back().writer;
|
||||
s = impl->WriteToWAL(empty_batch, log_writer, &log_used, &log_size);
|
||||
if (s.ok()) {
|
||||
// Need to fsync, otherwise it might get lost after a power reset.
|
||||
s = impl->FlushWAL(false);
|
||||
if (s.ok()) {
|
||||
s = log_writer->file()->Sync(impl->immutable_db_options_.use_fsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.ok() && impl->immutable_db_options_.persist_stats_to_disk) {
|
||||
@@ -1480,6 +1557,27 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
if (s.ok() && sfm) {
|
||||
// Notify SstFileManager about all sst files that already exist in
|
||||
// db_paths[0] and cf_paths[0] when the DB is opened.
|
||||
|
||||
// SstFileManagerImpl needs to know sizes of the files. For files whose size
|
||||
// we already know (sst files that appear in manifest - typically that's the
|
||||
// vast majority of all files), we'll pass the size to SstFileManager.
|
||||
// For all other files SstFileManager will query the size from filesystem.
|
||||
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
|
||||
impl->mutex_.Lock();
|
||||
impl->versions_->GetLiveFilesMetaData(&metadata);
|
||||
impl->mutex_.Unlock();
|
||||
|
||||
std::unordered_map<std::string, uint64_t> known_file_sizes;
|
||||
for (const auto& md : metadata) {
|
||||
std::string name = md.name;
|
||||
if (!name.empty() && name[0] == '/') {
|
||||
name = name.substr(1);
|
||||
}
|
||||
known_file_sizes[name] = md.size;
|
||||
}
|
||||
|
||||
std::vector<std::string> paths;
|
||||
paths.emplace_back(impl->immutable_db_options_.db_paths[0].path);
|
||||
for (auto& cf : column_families) {
|
||||
@@ -1499,7 +1597,14 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
std::string file_path = path + "/" + file_name;
|
||||
if (ParseFileName(file_name, &file_number, &file_type) &&
|
||||
file_type == kTableFile) {
|
||||
sfm->OnAddFile(file_path);
|
||||
if (known_file_sizes.count(file_name)) {
|
||||
// We're assuming that each sst file name exists in at most one of
|
||||
// the paths.
|
||||
sfm->OnAddFile(file_path, known_file_sizes.at(file_name),
|
||||
/* compaction */ false);
|
||||
} else {
|
||||
sfm->OnAddFile(file_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1540,4 +1645,4 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
}
|
||||
return s;
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "db/merge_context.h"
|
||||
#include "monitoring/perf_context_imp.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
@@ -48,14 +48,16 @@ Status DBImplReadOnly::Get(const ReadOptions& read_options,
|
||||
SequenceNumber max_covering_tombstone_seq = 0;
|
||||
LookupKey lkey(key, snapshot);
|
||||
PERF_TIMER_STOP(get_snapshot_time);
|
||||
if (super_version->mem->Get(lkey, pinnable_val->GetSelf(), &s, &merge_context,
|
||||
if (super_version->mem->Get(lkey, pinnable_val->GetSelf(),
|
||||
/*timestamp=*/nullptr, &s, &merge_context,
|
||||
&max_covering_tombstone_seq, read_options)) {
|
||||
pinnable_val->PinSelf();
|
||||
RecordTick(stats_, MEMTABLE_HIT);
|
||||
} else {
|
||||
PERF_TIMER_GUARD(get_from_output_files_time);
|
||||
super_version->current->Get(read_options, lkey, pinnable_val, &s,
|
||||
&merge_context, &max_covering_tombstone_seq);
|
||||
super_version->current->Get(read_options, lkey, pinnable_val,
|
||||
/*timestamp=*/nullptr, &s, &merge_context,
|
||||
&max_covering_tombstone_seq);
|
||||
RecordTick(stats_, MEMTABLE_MISS);
|
||||
}
|
||||
RecordTick(stats_, NUMBER_KEYS_READ);
|
||||
@@ -218,4 +220,4 @@ Status DB::OpenForReadOnly(
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <vector>
|
||||
#include "db/db_impl/db_impl.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DBImplReadOnly : public DBImpl {
|
||||
public:
|
||||
@@ -132,6 +132,6 @@ class DBImplReadOnly : public DBImpl {
|
||||
private:
|
||||
friend class DB;
|
||||
};
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
@@ -11,8 +11,9 @@
|
||||
#include "db/merge_context.h"
|
||||
#include "logging/auto_roll_logger.h"
|
||||
#include "monitoring/perf_context_imp.h"
|
||||
#include "util/cast_util.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
DBImplSecondary::DBImplSecondary(const DBOptions& db_options,
|
||||
@@ -28,7 +29,7 @@ DBImplSecondary::~DBImplSecondary() {}
|
||||
Status DBImplSecondary::Recover(
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families,
|
||||
bool /*readonly*/, bool /*error_if_log_file_exist*/,
|
||||
bool /*error_if_data_exists_in_logs*/) {
|
||||
bool /*error_if_data_exists_in_logs*/, uint64_t*) {
|
||||
mutex_.AssertHeld();
|
||||
|
||||
JobContext job_context(0);
|
||||
@@ -143,9 +144,10 @@ Status DBImplSecondary::MaybeInitLogReader(
|
||||
|
||||
std::unique_ptr<SequentialFileReader> file_reader;
|
||||
{
|
||||
std::unique_ptr<SequentialFile> file;
|
||||
Status status = env_->NewSequentialFile(
|
||||
fname, &file, env_->OptimizeForLogRead(env_options_));
|
||||
std::unique_ptr<FSSequentialFile> file;
|
||||
Status status = fs_->NewSequentialFile(
|
||||
fname, fs_->OptimizeForLogRead(file_options_), &file,
|
||||
nullptr);
|
||||
if (!status.ok()) {
|
||||
*log_reader = nullptr;
|
||||
return status;
|
||||
@@ -338,15 +340,16 @@ Status DBImplSecondary::GetImpl(const ReadOptions& read_options,
|
||||
PERF_TIMER_STOP(get_snapshot_time);
|
||||
|
||||
bool done = false;
|
||||
if (super_version->mem->Get(lkey, pinnable_val->GetSelf(), &s, &merge_context,
|
||||
if (super_version->mem->Get(lkey, pinnable_val->GetSelf(),
|
||||
/*timestamp=*/nullptr, &s, &merge_context,
|
||||
&max_covering_tombstone_seq, read_options)) {
|
||||
done = true;
|
||||
pinnable_val->PinSelf();
|
||||
RecordTick(stats_, MEMTABLE_HIT);
|
||||
} else if ((s.ok() || s.IsMergeInProgress()) &&
|
||||
super_version->imm->Get(
|
||||
lkey, pinnable_val->GetSelf(), &s, &merge_context,
|
||||
&max_covering_tombstone_seq, read_options)) {
|
||||
lkey, pinnable_val->GetSelf(), /*timestamp=*/nullptr, &s,
|
||||
&merge_context, &max_covering_tombstone_seq, read_options)) {
|
||||
done = true;
|
||||
pinnable_val->PinSelf();
|
||||
RecordTick(stats_, MEMTABLE_HIT);
|
||||
@@ -357,8 +360,9 @@ Status DBImplSecondary::GetImpl(const ReadOptions& read_options,
|
||||
}
|
||||
if (!done) {
|
||||
PERF_TIMER_GUARD(get_from_output_files_time);
|
||||
super_version->current->Get(read_options, lkey, pinnable_val, &s,
|
||||
&merge_context, &max_covering_tombstone_seq);
|
||||
super_version->current->Get(read_options, lkey, pinnable_val,
|
||||
/*timestamp=*/nullptr, &s, &merge_context,
|
||||
&max_covering_tombstone_seq);
|
||||
RecordTick(stats_, MEMTABLE_MISS);
|
||||
}
|
||||
{
|
||||
@@ -405,7 +409,7 @@ ArenaWrappedDBIter* DBImplSecondary::NewIteratorImpl(
|
||||
const ReadOptions& read_options, ColumnFamilyData* cfd,
|
||||
SequenceNumber snapshot, ReadCallback* read_callback) {
|
||||
assert(nullptr != cfd);
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(&mutex_);
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
auto db_iter = NewArenaWrappedDbIterator(
|
||||
env_, read_options, *cfd->ioptions(), super_version->mutable_cf_options,
|
||||
snapshot,
|
||||
@@ -466,6 +470,11 @@ Status DBImplSecondary::CheckConsistency() {
|
||||
// approach and just proceed.
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"DBImplSecondary::CheckConsistency:AfterFirstAttempt", &s);
|
||||
|
||||
if (immutable_db_options_.skip_checking_sst_file_sizes_on_db_open) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
versions_->GetLiveFilesMetaData(&metadata);
|
||||
|
||||
@@ -497,45 +506,61 @@ Status DBImplSecondary::TryCatchUpWithPrimary() {
|
||||
// read the manifest and apply new changes to the secondary instance
|
||||
std::unordered_set<ColumnFamilyData*> cfds_changed;
|
||||
JobContext job_context(0, true /*create_superversion*/);
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
s = static_cast<ReactiveVersionSet*>(versions_.get())
|
||||
->ReadAndApply(&mutex_, &manifest_reader_, &cfds_changed);
|
||||
{
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
s = static_cast_with_check<ReactiveVersionSet>(versions_.get())
|
||||
->ReadAndApply(&mutex_, &manifest_reader_, &cfds_changed);
|
||||
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log, "Last sequence is %" PRIu64,
|
||||
static_cast<uint64_t>(versions_->LastSequence()));
|
||||
for (ColumnFamilyData* cfd : cfds_changed) {
|
||||
if (cfd->IsDropped()) {
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log, "[%s] is dropped\n",
|
||||
cfd->GetName().c_str());
|
||||
continue;
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log, "Last sequence is %" PRIu64,
|
||||
static_cast<uint64_t>(versions_->LastSequence()));
|
||||
for (ColumnFamilyData* cfd : cfds_changed) {
|
||||
if (cfd->IsDropped()) {
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log, "[%s] is dropped\n",
|
||||
cfd->GetName().c_str());
|
||||
continue;
|
||||
}
|
||||
VersionStorageInfo::LevelSummaryStorage tmp;
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log,
|
||||
"[%s] Level summary: %s\n", cfd->GetName().c_str(),
|
||||
cfd->current()->storage_info()->LevelSummary(&tmp));
|
||||
}
|
||||
VersionStorageInfo::LevelSummaryStorage tmp;
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log, "[%s] Level summary: %s\n",
|
||||
cfd->GetName().c_str(),
|
||||
cfd->current()->storage_info()->LevelSummary(&tmp));
|
||||
}
|
||||
|
||||
// list wal_dir to discover new WALs and apply new changes to the secondary
|
||||
// instance
|
||||
if (s.ok()) {
|
||||
s = FindAndRecoverLogFiles(&cfds_changed, &job_context);
|
||||
}
|
||||
if (s.IsPathNotFound()) {
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log,
|
||||
"Secondary tries to read WAL, but WAL file(s) have already "
|
||||
"been purged by primary.");
|
||||
s = Status::OK();
|
||||
}
|
||||
if (s.ok()) {
|
||||
for (auto cfd : cfds_changed) {
|
||||
cfd->imm()->RemoveOldMemTables(cfd->GetLogNumber(),
|
||||
&job_context.memtables_to_free);
|
||||
auto& sv_context = job_context.superversion_contexts.back();
|
||||
cfd->InstallSuperVersion(&sv_context, &mutex_);
|
||||
sv_context.NewSuperVersion();
|
||||
// list wal_dir to discover new WALs and apply new changes to the secondary
|
||||
// instance
|
||||
if (s.ok()) {
|
||||
s = FindAndRecoverLogFiles(&cfds_changed, &job_context);
|
||||
}
|
||||
if (s.IsPathNotFound()) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"Secondary tries to read WAL, but WAL file(s) have already "
|
||||
"been purged by primary.");
|
||||
s = Status::OK();
|
||||
}
|
||||
if (s.ok()) {
|
||||
for (auto cfd : cfds_changed) {
|
||||
cfd->imm()->RemoveOldMemTables(cfd->GetLogNumber(),
|
||||
&job_context.memtables_to_free);
|
||||
auto& sv_context = job_context.superversion_contexts.back();
|
||||
cfd->InstallSuperVersion(&sv_context, &mutex_);
|
||||
sv_context.NewSuperVersion();
|
||||
}
|
||||
}
|
||||
job_context.Clean();
|
||||
}
|
||||
job_context.Clean();
|
||||
|
||||
// Cleanup unused, obsolete files.
|
||||
JobContext purge_files_job_context(0);
|
||||
{
|
||||
InstrumentedMutexLock lock_guard(&mutex_);
|
||||
// Currently, secondary instance does not own the database files, thus it
|
||||
// is unnecessary for the secondary to force full scan.
|
||||
FindObsoleteFiles(&purge_files_job_context, /*force=*/false);
|
||||
}
|
||||
if (purge_files_job_context.HaveSomethingToDelete()) {
|
||||
PurgeObsoleteFiles(purge_files_job_context);
|
||||
}
|
||||
purge_files_job_context.Clean();
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -583,7 +608,7 @@ Status DB::OpenAsSecondary(
|
||||
handles->clear();
|
||||
DBImplSecondary* impl = new DBImplSecondary(tmp_opts, dbname);
|
||||
impl->versions_.reset(new ReactiveVersionSet(
|
||||
dbname, &impl->immutable_db_options_, impl->env_options_,
|
||||
dbname, &impl->immutable_db_options_, impl->file_options_,
|
||||
impl->table_cache_.get(), impl->write_buffer_manager_,
|
||||
&impl->write_controller_));
|
||||
impl->column_family_memtables_.reset(
|
||||
@@ -645,4 +670,4 @@ Status DB::OpenAsSecondary(
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <vector>
|
||||
#include "db/db_impl/db_impl.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// A wrapper class to hold log reader, log reporter, log status.
|
||||
class LogReaderContainer {
|
||||
@@ -78,7 +78,8 @@ class DBImplSecondary : public DBImpl {
|
||||
// and log_readers_ to facilitate future operations.
|
||||
Status Recover(const std::vector<ColumnFamilyDescriptor>& column_families,
|
||||
bool read_only, bool error_if_log_file_exist,
|
||||
bool error_if_data_exists_in_logs) override;
|
||||
bool error_if_data_exists_in_logs,
|
||||
uint64_t* = nullptr) override;
|
||||
|
||||
// Implementations of the DB interface
|
||||
using DB::Get;
|
||||
@@ -172,6 +173,24 @@ class DBImplSecondary : public DBImpl {
|
||||
return Status::NotSupported("Not supported operation in secondary mode.");
|
||||
}
|
||||
|
||||
using DBImpl::SetDBOptions;
|
||||
Status SetDBOptions(const std::unordered_map<std::string, std::string>&
|
||||
/*options_map*/) override {
|
||||
// Currently not supported because changing certain options may cause
|
||||
// flush/compaction.
|
||||
return Status::NotSupported("Not supported operation in secondary mode.");
|
||||
}
|
||||
|
||||
using DBImpl::SetOptions;
|
||||
Status SetOptions(
|
||||
ColumnFamilyHandle* /*cfd*/,
|
||||
const std::unordered_map<std::string, std::string>& /*options_map*/)
|
||||
override {
|
||||
// Currently not supported because changing certain options may cause
|
||||
// flush/compaction and/or write to MANIFEST.
|
||||
return Status::NotSupported("Not supported operation in secondary mode.");
|
||||
}
|
||||
|
||||
using DBImpl::SyncWAL;
|
||||
Status SyncWAL() override {
|
||||
return Status::NotSupported("Not supported operation in secondary mode.");
|
||||
@@ -269,6 +288,14 @@ class DBImplSecondary : public DBImpl {
|
||||
return s;
|
||||
}
|
||||
|
||||
bool OwnTablesAndLogs() const override {
|
||||
// Currently, the secondary instance does not own the database files. It
|
||||
// simply opens the files of the primary instance and tracks their file
|
||||
// descriptors until they become obsolete. In the future, the secondary may
|
||||
// create links to database files. OwnTablesAndLogs will return true then.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class DB;
|
||||
|
||||
@@ -301,6 +328,6 @@ class DBImplSecondary : public DBImpl {
|
||||
std::unordered_map<ColumnFamilyData*, uint64_t> cfd_to_current_log_;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
+55
-40
@@ -15,7 +15,7 @@
|
||||
#include "options/options_helper.h"
|
||||
#include "test_util/sync_point.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
// Convenience methods
|
||||
Status DBImpl::Put(const WriteOptions& o, ColumnFamilyHandle* column_family,
|
||||
const Slice& key, const Slice& val) {
|
||||
@@ -131,6 +131,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
log_used, log_ref, &seq, sub_batch_cnt,
|
||||
pre_release_callback, kDoAssignOrder,
|
||||
kDoPublishLastSeq, disable_memtable);
|
||||
TEST_SYNC_POINT("DBImpl::WriteImpl:UnorderedWriteAfterWriteWAL");
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
@@ -138,6 +139,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
*seq_used = seq;
|
||||
}
|
||||
if (!disable_memtable) {
|
||||
TEST_SYNC_POINT("DBImpl::WriteImpl:BeforeUnorderedWriteMemtable");
|
||||
status = UnorderedWriteMemtable(write_options, my_batch, callback,
|
||||
log_ref, seq, sub_batch_cnt);
|
||||
}
|
||||
@@ -1039,7 +1041,7 @@ Status DBImpl::WriteToWAL(const WriteThread::WriteGroup& write_group,
|
||||
// We only sync WAL directory the first time WAL syncing is
|
||||
// requested, so that in case users never turn on WAL sync,
|
||||
// we can avoid the disk I/O in the write code path.
|
||||
status = directories_.GetWalDir()->Fsync();
|
||||
status = directories_.GetWalDir()->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1246,14 +1248,23 @@ Status DBImpl::SwitchWAL(WriteContext* write_context) {
|
||||
}
|
||||
MaybeFlushStatsCF(&cfds);
|
||||
}
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
}
|
||||
|
||||
for (const auto cfd : cfds) {
|
||||
cfd->Ref();
|
||||
status = SwitchMemtable(cfd, write_context);
|
||||
cfd->Unref();
|
||||
cfd->UnrefAndTryDelete();
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
|
||||
if (status.ok()) {
|
||||
if (immutable_db_options_.atomic_flush) {
|
||||
AssignAtomicFlushSeq(cfds);
|
||||
@@ -1281,7 +1292,7 @@ Status DBImpl::HandleWriteBufferFull(WriteContext* write_context) {
|
||||
// suboptimal but still correct.
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"Flushing column family with largest mem table size. Write buffer is "
|
||||
"Flushing column family with oldest memtable entry. Write buffer is "
|
||||
"using %" ROCKSDB_PRIszt " bytes out of a total of %" ROCKSDB_PRIszt ".",
|
||||
write_buffer_manager_->memory_usage(),
|
||||
write_buffer_manager_->buffer_size());
|
||||
@@ -1314,17 +1325,25 @@ Status DBImpl::HandleWriteBufferFull(WriteContext* write_context) {
|
||||
MaybeFlushStatsCF(&cfds);
|
||||
}
|
||||
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
}
|
||||
for (const auto cfd : cfds) {
|
||||
if (cfd->mem()->IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
cfd->Ref();
|
||||
status = SwitchMemtable(cfd, write_context);
|
||||
cfd->Unref();
|
||||
cfd->UnrefAndTryDelete();
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
|
||||
if (status.ok()) {
|
||||
if (immutable_db_options_.atomic_flush) {
|
||||
AssignAtomicFlushSeq(cfds);
|
||||
@@ -1439,7 +1458,7 @@ Status DBImpl::ThrottleLowPriWritesIfNeeded(const WriteOptions& write_options,
|
||||
return Status::OK();
|
||||
}
|
||||
if (write_options.no_slowdown) {
|
||||
return Status::Incomplete();
|
||||
return Status::Incomplete("Low priority write stall");
|
||||
} else {
|
||||
assert(my_batch != nullptr);
|
||||
// Rate limit those writes. The reason that we don't completely wait
|
||||
@@ -1499,15 +1518,16 @@ Status DBImpl::TrimMemtableHistory(WriteContext* context) {
|
||||
for (auto& cfd : cfds) {
|
||||
autovector<MemTable*> to_delete;
|
||||
cfd->imm()->TrimHistory(&to_delete, cfd->mem()->ApproximateMemoryUsage());
|
||||
for (auto m : to_delete) {
|
||||
delete m;
|
||||
if (!to_delete.empty()) {
|
||||
for (auto m : to_delete) {
|
||||
delete m;
|
||||
}
|
||||
context->superversion_context.NewSuperVersion();
|
||||
assert(context->superversion_context.new_superversion.get() != nullptr);
|
||||
cfd->InstallSuperVersion(&context->superversion_context, &mutex_);
|
||||
}
|
||||
context->superversion_context.NewSuperVersion();
|
||||
assert(context->superversion_context.new_superversion.get() != nullptr);
|
||||
cfd->InstallSuperVersion(&context->superversion_context, &mutex_);
|
||||
|
||||
if (cfd->Unref()) {
|
||||
delete cfd;
|
||||
if (cfd->UnrefAndTryDelete()) {
|
||||
cfd = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1530,18 +1550,27 @@ Status DBImpl::ScheduleFlushes(WriteContext* context) {
|
||||
MaybeFlushStatsCF(&cfds);
|
||||
}
|
||||
Status status;
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
}
|
||||
|
||||
for (auto& cfd : cfds) {
|
||||
if (!cfd->mem()->IsEmpty()) {
|
||||
status = SwitchMemtable(cfd, context);
|
||||
}
|
||||
if (cfd->Unref()) {
|
||||
delete cfd;
|
||||
if (cfd->UnrefAndTryDelete()) {
|
||||
cfd = nullptr;
|
||||
}
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
|
||||
if (status.ok()) {
|
||||
if (immutable_db_options_.atomic_flush) {
|
||||
AssignAtomicFlushSeq(cfds);
|
||||
@@ -1572,15 +1601,11 @@ void DBImpl::NotifyOnMemTableSealed(ColumnFamilyData* /*cfd*/,
|
||||
|
||||
// REQUIRES: mutex_ is held
|
||||
// REQUIRES: this thread is currently at the front of the writer queue
|
||||
// REQUIRES: this thread is currently at the front of the 2nd writer queue if
|
||||
// two_write_queues_ is true (This is to simplify the reasoning.)
|
||||
Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
mutex_.AssertHeld();
|
||||
WriteThread::Writer nonmem_w;
|
||||
if (two_write_queues_) {
|
||||
// SwitchMemtable is a rare event. To simply the reasoning, we make sure
|
||||
// that there is no concurrent thread writing to WAL.
|
||||
nonmem_write_thread_.EnterUnbatched(&nonmem_w, &mutex_);
|
||||
}
|
||||
|
||||
std::unique_ptr<WritableFile> lfile;
|
||||
log::Writer* new_log = nullptr;
|
||||
MemTable* new_mem = nullptr;
|
||||
@@ -1592,16 +1617,6 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// In case of pipelined write is enabled, wait for all pending memtable
|
||||
// writers.
|
||||
if (immutable_db_options_.enable_pipelined_write) {
|
||||
// Memtable writers may call DB::Get in case max_successive_merges > 0,
|
||||
// which may lock mutex. Unlocking mutex here to avoid deadlock.
|
||||
mutex_.Unlock();
|
||||
write_thread_.WaitForMemTableWriters();
|
||||
mutex_.Lock();
|
||||
}
|
||||
|
||||
// Attempt to switch to a new memtable and trigger flush of old.
|
||||
// Do this without holding the dbmutex lock.
|
||||
assert(versions_->prev_log_number() == 0);
|
||||
@@ -1616,7 +1631,6 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
if (creating_new_log && immutable_db_options_.recycle_log_file_num &&
|
||||
!log_recycle_files_.empty()) {
|
||||
recycle_log_number = log_recycle_files_.front();
|
||||
log_recycle_files_.pop_front();
|
||||
}
|
||||
uint64_t new_log_number =
|
||||
creating_new_log ? versions_->NewFileNumber() : logfile_number_;
|
||||
@@ -1653,6 +1667,14 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
". Immutable memtables: %d.\n",
|
||||
cfd->GetName().c_str(), new_log_number, num_imm_unflushed);
|
||||
mutex_.Lock();
|
||||
if (recycle_log_number != 0) {
|
||||
// Since renaming the file is done outside DB mutex, we need to ensure
|
||||
// concurrent full purges don't delete the file while we're recycling it.
|
||||
// To achieve that we hold the old log number in the recyclable list until
|
||||
// after it has been renamed.
|
||||
assert(log_recycle_files_.front() == recycle_log_number);
|
||||
log_recycle_files_.pop_front();
|
||||
}
|
||||
if (s.ok() && creating_new_log) {
|
||||
log_write_mutex_.Lock();
|
||||
assert(new_log != nullptr);
|
||||
@@ -1697,10 +1719,6 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
error_handler_.SetBGError(s, BackgroundErrorReason::kMemTable);
|
||||
// Read back bg_error in order to get the right severity
|
||||
s = error_handler_.GetBGError();
|
||||
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1731,9 +1749,6 @@ Status DBImpl::SwitchMemtable(ColumnFamilyData* cfd, WriteContext* context) {
|
||||
NotifyOnMemTableSealed(cfd, memtable_info);
|
||||
mutex_.Lock();
|
||||
#endif // ROCKSDB_LITE
|
||||
if (two_write_queues_) {
|
||||
nonmem_write_thread_.ExitUnbatched(&nonmem_w);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -1821,4 +1836,4 @@ Status DB::Merge(const WriteOptions& opt, ColumnFamilyHandle* column_family,
|
||||
}
|
||||
return Write(opt, &batch);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "test_util/fault_injection_test_env.h"
|
||||
#include "test_util/sync_point.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
class DBSecondaryTest : public DBTestBase {
|
||||
@@ -195,6 +195,90 @@ TEST_F(DBSecondaryTest, OpenAsSecondary) {
|
||||
verify_db_func("new_foo_value", "new_bar_value");
|
||||
}
|
||||
|
||||
namespace {
|
||||
class TraceFileEnv : public EnvWrapper {
|
||||
public:
|
||||
explicit TraceFileEnv(Env* _target) : EnvWrapper(_target) {}
|
||||
Status NewRandomAccessFile(const std::string& f,
|
||||
std::unique_ptr<RandomAccessFile>* r,
|
||||
const EnvOptions& env_options) override {
|
||||
class TracedRandomAccessFile : public RandomAccessFile {
|
||||
public:
|
||||
TracedRandomAccessFile(std::unique_ptr<RandomAccessFile>&& target,
|
||||
std::atomic<int>& counter)
|
||||
: target_(std::move(target)), files_closed_(counter) {}
|
||||
~TracedRandomAccessFile() override {
|
||||
files_closed_.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const override {
|
||||
return target_->Read(offset, n, result, scratch);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<RandomAccessFile> target_;
|
||||
std::atomic<int>& files_closed_;
|
||||
};
|
||||
Status s = target()->NewRandomAccessFile(f, r, env_options);
|
||||
if (s.ok()) {
|
||||
r->reset(new TracedRandomAccessFile(std::move(*r), files_closed_));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int files_closed() const {
|
||||
return files_closed_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int> files_closed_{0};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_F(DBSecondaryTest, SecondaryCloseFiles) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
options.max_open_files = 1;
|
||||
options.disable_auto_compactions = true;
|
||||
Reopen(options);
|
||||
Options options1;
|
||||
std::unique_ptr<Env> traced_env(new TraceFileEnv(env_));
|
||||
options1.env = traced_env.get();
|
||||
OpenSecondary(options1);
|
||||
|
||||
static const auto verify_db = [&]() {
|
||||
std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions()));
|
||||
std::unique_ptr<Iterator> iter2(db_secondary_->NewIterator(ReadOptions()));
|
||||
for (iter1->SeekToFirst(), iter2->SeekToFirst();
|
||||
iter1->Valid() && iter2->Valid(); iter1->Next(), iter2->Next()) {
|
||||
ASSERT_EQ(iter1->key(), iter2->key());
|
||||
ASSERT_EQ(iter1->value(), iter2->value());
|
||||
}
|
||||
ASSERT_FALSE(iter1->Valid());
|
||||
ASSERT_FALSE(iter2->Valid());
|
||||
};
|
||||
|
||||
ASSERT_OK(Put("a", "value"));
|
||||
ASSERT_OK(Put("c", "value"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(db_secondary_->TryCatchUpWithPrimary());
|
||||
verify_db();
|
||||
|
||||
ASSERT_OK(Put("b", "value"));
|
||||
ASSERT_OK(Put("d", "value"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(db_secondary_->TryCatchUpWithPrimary());
|
||||
verify_db();
|
||||
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_OK(db_secondary_->TryCatchUpWithPrimary());
|
||||
ASSERT_EQ(2, static_cast<TraceFileEnv*>(traced_env.get())->files_closed());
|
||||
|
||||
Status s = db_secondary_->SetDBOptions({{"max_open_files", "-1"}});
|
||||
ASSERT_TRUE(s.IsNotSupported());
|
||||
CloseSecondary();
|
||||
}
|
||||
|
||||
TEST_F(DBSecondaryTest, OpenAsSecondaryWALTailing) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
@@ -776,10 +860,10 @@ TEST_F(DBSecondaryTest, CheckConsistencyWhenOpen) {
|
||||
}
|
||||
#endif //! ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
rocksdb::port::InstallStackTraceHandler();
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "file/filename.h"
|
||||
#include "rocksdb/env.h"
|
||||
|
||||
namespace rocksdb {
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
const std::string& dbname) {
|
||||
@@ -120,4 +120,4 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
Header(options.info_log, "Write Ahead Log file in %s: %s\n",
|
||||
options.wal_dir.c_str(), wal_info.c_str());
|
||||
}
|
||||
} // namespace rocksdb
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Loaded 100 of 1102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user