mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-06 11:02:36 -05:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d57a393a8 | ||
|
|
224da7f494 | ||
|
|
9674b843c2 | ||
|
|
7448618ac8 | ||
|
|
52626f10b1 | ||
|
|
7c25388623 |
No files matched your search
-51
@@ -5,7 +5,6 @@ os:
|
||||
arch:
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
@@ -60,12 +59,6 @@ matrix:
|
||||
- os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=make-gcc4.8
|
||||
- os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=make-gcc4.8
|
||||
- os: linux
|
||||
compiler: clang
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
@@ -80,10 +73,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=1
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: TEST_GROUP=1
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -92,10 +81,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=2
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: TEST_GROUP=2
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -104,10 +89,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=3
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: TEST_GROUP=3
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -116,10 +97,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=4
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: TEST_GROUP=4
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -132,10 +109,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=java_test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/ AND commit_message !~ /java/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=java_test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -144,10 +117,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=lite_build
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=lite_build
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -156,10 +125,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=examples
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=examples
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -168,10 +133,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -180,10 +141,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-gcc9
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=cmake-gcc9
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -192,10 +149,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-gcc9-c++20
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=cmake-gcc9-c++20
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -204,10 +157,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=status_checked
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: s390x
|
||||
env: JOB_NAME=status_checked
|
||||
|
||||
install:
|
||||
- if [ "${JOB_NAME}" == cmake-gcc8 ]; then
|
||||
|
||||
+1
-13
@@ -267,13 +267,6 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64|AARCH64")
|
||||
endif(HAS_ARMV8_CRC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64|AARCH64")
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "s390x")
|
||||
CHECK_C_COMPILER_FLAG("-march=native" HAS_S390X_MARCH_NATIVE)
|
||||
if(HAS_S390X_MARCH_NATIVE)
|
||||
message(STATUS " HAS_S390X_MARCH_NATIVE yes")
|
||||
endif(HAS_S390X_MARCH_NATIVE)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "s390x")
|
||||
|
||||
option(PORTABLE "build a portable binary" OFF)
|
||||
option(FORCE_SSE42 "force building with SSE4.2, even when PORTABLE=ON" OFF)
|
||||
option(FORCE_AVX "force building with AVX, even when PORTABLE=ON" OFF)
|
||||
@@ -299,17 +292,12 @@ if(PORTABLE)
|
||||
if(FORCE_AVX2)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx2 -mbmi -mlzcnt")
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^s390x")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=z196")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2")
|
||||
else()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^s390x" AND NOT HAS_S390X_MARCH_NATIVE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=z196")
|
||||
elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)64" 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()
|
||||
|
||||
+3
-28
@@ -1,32 +1,7 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
### New Features
|
||||
* Added new ChecksumType kXXH3 which is faster than kCRC32c on almost all x86\_64 hardware.
|
||||
* Added a new online consistency check for BlobDB which validates that the number/total size of garbage blobs does not exceed the number/total size of all blobs in any given blob file.
|
||||
|
||||
# Rocksdb Change Lo
|
||||
## 6.26.1 (2021-11-18)
|
||||
### Bug Fixes
|
||||
* Prevent a `CompactRange()` with `CompactRangeOptions::change_level == true` from possibly causing corruption to the LSM state (overlapping files within a level) when run in parallel with another manual compaction. Note that setting `force_consistency_checks == true` (the default) would cause the DB to enter read-only mode in this scenario and return `Status::Corruption`, rather than committing any corruption.
|
||||
* Fixed a bug in CompactionIterator when write-prepared transaction is used. A released earliest write conflict snapshot may cause assertion failure in dbg mode and unexpected key in opt mode.
|
||||
* Fix ticker WRITE_WITH_WAL("rocksdb.write.wal"), this bug is caused by a bad extra `RecordTick(stats_, WRITE_WITH_WAL)` (at 2 place), this fix remove the extra `RecordTick`s and fix the corresponding test case.
|
||||
* EventListener::OnTableFileCreated was previously called with OK status and file_size==0 in cases of no SST file contents written (because there was no content to add) and the empty file deleted before calling the listener. Now the status is Aborted.
|
||||
* Fixed a bug in CompactionIterator when write-preared transaction is used. Releasing earliest_snapshot during compaction may cause a SingleDelete to be output after a PUT of the same user key whose seq has been zeroed.
|
||||
* Added input sanitization on negative bytes passed into `GenericRateLimiter::Request`.
|
||||
|
||||
### Behavior Changes
|
||||
* `NUM_FILES_IN_SINGLE_COMPACTION` was only counting the first input level files, now it's including all input files.
|
||||
|
||||
### Public Interface Change
|
||||
* When options.ttl is used with leveled compaction with compactinon priority kMinOverlappingRatio, files exceeding half of TTL value will be prioritized more, so that by the time TTL is reached, fewer extra compactions will be scheduled to clear them up. At the same time, when compacting files with data older than half of TTL, output files may be cut off based on those files' boundaries, in order for the early TTL compaction to work properly.
|
||||
|
||||
### Public API change
|
||||
* Made FileSystem extend the Customizable class and added a CreateFromString method. Implementations need to be registered with the ObjectRegistry and to implement a Name() method in order to be created via this method.
|
||||
* Clarified in API comments that RocksDB is not exception safe for callbacks and custom extensions. An exception propagating into RocksDB can lead to undefined behavior, including data loss, unreported corruption, deadlocks, and more.
|
||||
* Marked `WriteBufferManager` as `final` because it is not intended for extension.
|
||||
* Add API `FSDirectory::FsyncWithDirOptions()`, which provides extra information like directory fsync reason in `DirFsyncOptions`. File system like btrfs is using that to skip directory fsync for creating a new file, or when renaming a file, fsync the target file instead of the directory, which improves the `DB::Open()` speed by ~20%.
|
||||
* `DB::Open()` is not going be blocked by obsolete file purge if `DBOptions::avoid_unnecessary_blocking_io` is set to true.
|
||||
|
||||
### Performance Improvements
|
||||
* Released some memory related to filter construction earlier in `BlockBasedTableBuilder` for `FullFilter` and `PartitionedFilter` case (#9070)
|
||||
* Fix builds for some platforms.
|
||||
|
||||
## 6.26.0 (2021-10-20)
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1926,9 +1926,6 @@ clipping_iterator_test: $(OBJ_DIR)/db/compaction/clipping_iterator_test.o $(TEST
|
||||
ribbon_bench: $(OBJ_DIR)/microbench/ribbon_bench.o $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_basic_bench: $(OBJ_DIR)/microbench/db_basic_bench.o $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
cache_reservation_manager_test: $(OBJ_DIR)/cache/cache_reservation_manager_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
#-------------------------------------------------
|
||||
@@ -2001,7 +1998,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 amd64 ppc64 ppc64le s390x arm64 aarch64 sparc64, $(MACHINE)))
|
||||
ifneq (,$(filter amd64 ppc64 ppc64le arm64 aarch64 sparc64, $(MACHINE)))
|
||||
ARCH := 64
|
||||
else
|
||||
ARCH := 32
|
||||
@@ -2021,7 +2018,7 @@ ifneq ($(origin JNI_LIBC), undefined)
|
||||
JNI_LIBC_POSTFIX = -$(JNI_LIBC)
|
||||
endif
|
||||
|
||||
ifneq (,$(filter ppc% s390x arm64 aarch64 sparc64, $(MACHINE)))
|
||||
ifneq (,$(filter ppc% arm64 aarch64 sparc64, $(MACHINE)))
|
||||
ROCKSDBJNILIB = librocksdbjni-linux-$(MACHINE)$(JNI_LIBC_POSTFIX).so
|
||||
else
|
||||
ROCKSDBJNILIB = librocksdbjni-linux$(ARCH)$(JNI_LIBC_POSTFIX).so
|
||||
|
||||
@@ -31,11 +31,7 @@ ROCKSDB_EXTERNAL_DEPS = [
|
||||
ROCKSDB_OS_DEPS_0 = [
|
||||
(
|
||||
"linux",
|
||||
[
|
||||
"third-party//numa:numa",
|
||||
"third-party//liburing:uring",
|
||||
"third-party//tbb:tbb",
|
||||
],
|
||||
["third-party//numa:numa", "third-party//liburing:uring", "third-party//tbb:tbb"],
|
||||
),
|
||||
(
|
||||
"macos",
|
||||
@@ -73,13 +69,7 @@ ROCKSDB_OS_PREPROCESSOR_FLAGS_0 = [
|
||||
),
|
||||
(
|
||||
"windows",
|
||||
[
|
||||
"-DOS_WIN",
|
||||
"-DWIN32",
|
||||
"-D_MBCS",
|
||||
"-DWIN64",
|
||||
"-DNOMINMAX",
|
||||
],
|
||||
[ "-DOS_WIN", "-DWIN32", "-D_MBCS", "-DWIN64", "-DNOMINMAX" ]
|
||||
),
|
||||
]
|
||||
|
||||
@@ -455,14 +445,13 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = False,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
link_whole = False,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
@@ -782,14 +771,13 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = True,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
link_whole = True,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
@@ -807,16 +795,15 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = False,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_lib"],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS + [
|
||||
("googletest", None, "gtest"),
|
||||
],
|
||||
link_whole = False,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
@@ -831,14 +818,13 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = False,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_lib"],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
link_whole = False,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
@@ -847,14 +833,13 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = False,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_lib"],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
link_whole = False,
|
||||
)
|
||||
|
||||
cpp_library(
|
||||
@@ -878,11 +863,10 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = ROCKSDB_LIB_DEPS,
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
)
|
||||
@@ -891,10 +875,10 @@ cpp_binary(
|
||||
name = "c_test_bin",
|
||||
srcs = ["db/c_test.c"],
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_test_lib"],
|
||||
) if not is_opt_mode else None
|
||||
|
||||
@@ -913,14 +897,13 @@ cpp_library(
|
||||
auto_headers = AutoHeaders.RECURSIVE_GLOB,
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = False,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_test_lib"],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
link_whole = False,
|
||||
)
|
||||
|
||||
# [test_name, test_src, test_type, extra_deps, extra_compiler_flags]
|
||||
@@ -2237,10 +2220,10 @@ ROCKS_TESTS = [
|
||||
name = test_name,
|
||||
srcs = [test_cc],
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS + extra_compiler_flags,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS + extra_compiler_flags,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_test_lib"] + extra_deps,
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS + [
|
||||
("googletest", None, "gtest"),
|
||||
|
||||
@@ -84,10 +84,10 @@ cpp_binary(
|
||||
name = "c_test_bin",
|
||||
srcs = ["db/c_test.c"],
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_test_lib"],
|
||||
) if not is_opt_mode else None
|
||||
|
||||
|
||||
@@ -38,11 +38,7 @@ ROCKSDB_EXTERNAL_DEPS = [
|
||||
ROCKSDB_OS_DEPS_0 = [
|
||||
(
|
||||
"linux",
|
||||
[
|
||||
"third-party//numa:numa",
|
||||
"third-party//liburing:uring",
|
||||
"third-party//tbb:tbb",
|
||||
],
|
||||
["third-party//numa:numa", "third-party//liburing:uring", "third-party//tbb:tbb"],
|
||||
),
|
||||
(
|
||||
"macos",
|
||||
@@ -80,13 +76,7 @@ ROCKSDB_OS_PREPROCESSOR_FLAGS_0 = [
|
||||
),
|
||||
(
|
||||
"windows",
|
||||
[
|
||||
"-DOS_WIN",
|
||||
"-DWIN32",
|
||||
"-D_MBCS",
|
||||
"-DWIN64",
|
||||
"-DNOMINMAX",
|
||||
],
|
||||
[ "-DOS_WIN", "-DWIN32", "-D_MBCS", "-DWIN64", "-DNOMINMAX" ]
|
||||
),
|
||||
]
|
||||
|
||||
@@ -154,14 +144,13 @@ cpp_library(
|
||||
{headers_attr_prefix}headers = {headers},
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
link_whole = {link_whole},
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [{deps}],
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS{extra_external_deps},
|
||||
link_whole = {link_whole},
|
||||
)
|
||||
"""
|
||||
|
||||
@@ -172,11 +161,10 @@ cpp_library(
|
||||
{headers_attr_prefix}headers = {headers},
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
os_deps = ROCKSDB_OS_DEPS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
unexported_deps_by_default = False,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = ROCKSDB_LIB_DEPS,
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS,
|
||||
)
|
||||
@@ -217,10 +205,10 @@ ROCKS_TESTS = [
|
||||
name = test_name,
|
||||
srcs = [test_cc],
|
||||
arch_preprocessor_flags = ROCKSDB_ARCH_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS + extra_compiler_flags,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
os_preprocessor_flags = ROCKSDB_OS_PREPROCESSOR_FLAGS,
|
||||
compiler_flags = ROCKSDB_COMPILER_FLAGS + extra_compiler_flags,
|
||||
preprocessor_flags = ROCKSDB_PREPROCESSOR_FLAGS,
|
||||
include_paths = ROCKSDB_INCLUDE_PATHS,
|
||||
deps = [":rocksdb_test_lib"] + extra_deps,
|
||||
external_deps = ROCKSDB_EXTERNAL_DEPS + [
|
||||
("googletest", None, "gtest"),
|
||||
|
||||
@@ -638,19 +638,13 @@ if test "0$PORTABLE" -eq 0; then
|
||||
# Tune for this POWER processor, treating '+' models as base models
|
||||
POWER=`LD_SHOW_AUXV=1 /bin/true | grep AT_PLATFORM | grep -E -o power[0-9]+`
|
||||
COMMON_FLAGS="$COMMON_FLAGS -mcpu=$POWER -mtune=$POWER "
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep ^s390x`"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=z10 "
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep -e^arm -e^aarch64`"; then
|
||||
# TODO: Handle this with approprite options.
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep ^aarch64`"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif test -n "`echo $TARGET_ARCHITECTURE | grep ^s390x`"; then
|
||||
if echo 'int main() {}' | $CXX $PLATFORM_CXXFLAGS -x c++ \
|
||||
-fsyntax-only -march=native - -o /dev/null 2>/dev/null; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=native "
|
||||
else
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=z196 "
|
||||
fi
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif [ "$TARGET_OS" == "IOS" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS"
|
||||
elif [ "$TARGET_OS" == "AIX" ] || [ "$TARGET_OS" == "SunOS" ]; then
|
||||
@@ -667,10 +661,6 @@ else
|
||||
TRY_SSE_ETC="1"
|
||||
fi
|
||||
|
||||
if test -n "`echo $TARGET_ARCHITECTURE | grep ^s390x`"; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -march=z196 "
|
||||
fi
|
||||
|
||||
if [[ "${PLATFORM}" == "OS_MACOSX" ]]; then
|
||||
# For portability compile for macOS 10.12 (2016) or newer
|
||||
COMMON_FLAGS="$COMMON_FLAGS -mmacosx-version-min=10.12"
|
||||
|
||||
@@ -127,11 +127,11 @@ uncommitted_code=`git diff HEAD`
|
||||
if [ -z "$uncommitted_code" ]
|
||||
then
|
||||
# Attempt to get name of facebook/rocksdb.git remote.
|
||||
[ "$FORMAT_REMOTE" ] || FORMAT_REMOTE="$(LC_ALL=POSIX LANG=POSIX git remote -v | grep 'facebook/rocksdb.git' | head -n 1 | cut -f 1)"
|
||||
[ "$FORMAT_REMOTE" ] || FORMAT_REMOTE="$(git remote -v | grep 'facebook/rocksdb.git' | head -n 1 | cut -f 1)"
|
||||
# Fall back on 'origin' if that fails
|
||||
[ "$FORMAT_REMOTE" ] || FORMAT_REMOTE=origin
|
||||
# Use main branch from that remote
|
||||
[ "$FORMAT_UPSTREAM" ] || FORMAT_UPSTREAM="$FORMAT_REMOTE/$(LC_ALL=POSIX LANG=POSIX git remote show $FORMAT_REMOTE | sed -n '/HEAD branch/s/.*: //p')"
|
||||
[ "$FORMAT_UPSTREAM" ] || FORMAT_UPSTREAM="$FORMAT_REMOTE/$(git remote show $FORMAT_REMOTE | sed -n '/HEAD branch/s/.*: //p')"
|
||||
# Get the common ancestor with that remote branch. Everything after that
|
||||
# common ancestor would be considered the contents of a pull request, so
|
||||
# should be relevant for formatting fixes.
|
||||
|
||||
@@ -27,7 +27,7 @@ if [ ! -z $EMAIL ]; then
|
||||
'type':'email',
|
||||
'triggers': [ '$TRIGGER' ],
|
||||
'emails':['$EMAIL']
|
||||
}"
|
||||
},"
|
||||
fi
|
||||
|
||||
CREATE_TASK=
|
||||
@@ -38,8 +38,8 @@ if [ ! -z $ONCALL ]; then
|
||||
'triggers':[ 'fail' ],
|
||||
'priority':0,
|
||||
'subscribers':[ '$SUBSCRIBER' ],
|
||||
'tags':[ 'rocksdb', 'ci' ]
|
||||
}"
|
||||
'tags':[ 'rocksdb', 'ci' ],
|
||||
},"
|
||||
fi
|
||||
|
||||
# For now, create the tasks using only the dedicated task creation tool.
|
||||
@@ -48,7 +48,7 @@ CREATE_TASK=
|
||||
REPORT=
|
||||
if [[ ! -z $REPORT_EMAIL || ! -z $CREATE_TASK ]]; then
|
||||
REPORT="'report': [
|
||||
$REPORT_EMAIL,
|
||||
$REPORT_EMAIL
|
||||
$CREATE_TASK
|
||||
]"
|
||||
fi
|
||||
@@ -79,9 +79,9 @@ UPLOAD_DB_DIR="
|
||||
{
|
||||
'name':'rocksdb_db_dir',
|
||||
'paths': ['rocksdb_db.tar.gz'],
|
||||
'bundle': false
|
||||
}
|
||||
]
|
||||
'bundle': false,
|
||||
},
|
||||
],
|
||||
}"
|
||||
|
||||
# We will eventually set the RATIO to 1, but we want do this
|
||||
@@ -141,8 +141,8 @@ DISABLE_COMMANDS="[
|
||||
'name':'Job disabled. Please contact test owner',
|
||||
'shell':'exit 1',
|
||||
'user':'root'
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
||||
]"
|
||||
|
||||
@@ -161,7 +161,7 @@ UNIT_TEST_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -184,7 +184,7 @@ UNIT_TEST_NON_SHM_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $NON_SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=non_shm_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -205,7 +205,7 @@ RELEASE_BUILD_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; make $PARALLEL_j release || $CONTRUN_NAME=release $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -226,7 +226,7 @@ UNIT_TEST_COMMANDS_481="[
|
||||
'shell':'cd $WORKING_DIR; $SHM $GCC_481 $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=unit_gcc_481_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -247,7 +247,7 @@ RELEASE_BUILD_COMMANDS_481="[
|
||||
'shell':'cd $WORKING_DIR; $GCC_481 make $PARALLEL_j release || $CONTRUN_NAME=release_gcc481 $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -268,7 +268,7 @@ CLANG_UNIT_TEST_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $CLANG $SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=clang_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -289,7 +289,7 @@ CLANG_RELEASE_BUILD_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $CLANG make $PARALLEL_j release|| $CONTRUN_NAME=clang_release $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -310,7 +310,7 @@ CLANG_ANALYZE_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $CLANG $SHM $DEBUG make $PARALLEL_j analyze || $CONTRUN_NAME=clang_analyze $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -331,7 +331,7 @@ CODE_COV_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM coverage || $CONTRUN_NAME=coverage $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -352,7 +352,7 @@ UNITY_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG V=1 make J=1 unity_test || $CONTRUN_NAME=unity_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -373,7 +373,7 @@ LITE_BUILD_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $SKIP_FORMAT_CHECKS make J=1 LITE=1 all check || $CONTRUN_NAME=lite $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -403,7 +403,7 @@ STRESS_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -433,7 +433,7 @@ BLACKBOX_STRESS_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -463,7 +463,7 @@ WHITEBOX_STRESS_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -493,7 +493,7 @@ STRESS_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -523,7 +523,7 @@ STRESS_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -553,7 +553,7 @@ STRESS_CRASH_TEST_WITH_TS_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -621,7 +621,7 @@ ASAN_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -645,7 +645,7 @@ ASAN_BLACKBOX_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -669,7 +669,7 @@ ASAN_WHITEBOX_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -693,7 +693,7 @@ ASAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -717,7 +717,7 @@ ASAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -762,7 +762,7 @@ UBSAN_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -786,7 +786,7 @@ UBSAN_BLACKBOX_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -810,7 +810,7 @@ UBSAN_WHITEBOX_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -834,7 +834,7 @@ UBSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -858,7 +858,7 @@ UBSAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -881,7 +881,7 @@ VALGRIND_TEST_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $SHM $DEBUG make $PARALLELISM valgrind_test || $CONTRUN_NAME=valgrind_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -904,7 +904,7 @@ TSAN_UNIT_TEST_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $DEBUG $TSAN $SKIP_FORMAT_CHECKS make $PARALLELISM check || $CONTRUN_NAME=tsan_check $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -928,7 +928,7 @@ TSAN_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -952,7 +952,7 @@ TSAN_BLACKBOX_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -976,7 +976,7 @@ TSAN_WHITEBOX_CRASH_TEST_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1000,7 +1000,7 @@ TSAN_CRASH_TEST_WITH_ATOMIC_FLUSH_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1024,7 +1024,7 @@ TSAN_CRASH_TEST_WITH_TXN_COMMANDS="[
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
$UPLOAD_DB_DIR
|
||||
$UPLOAD_DB_DIR,
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1041,7 +1041,7 @@ run_format_compatible()
|
||||
mkdir /dev/shm/rocksdb
|
||||
|
||||
export https_proxy="fwdproxy:8080"
|
||||
|
||||
|
||||
tools/check_format_compatible.sh
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@ FORMAT_COMPATIBLE_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; build_tools/rocksdb-lego-determinator run_format_compatible || $CONTRUN_NAME=run_format_compatible $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1092,7 +1092,7 @@ NO_COMPRESSION_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; build_tools/rocksdb-lego-determinator run_no_compression || $CONTRUN_NAME=run_no_compression $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1152,7 +1152,7 @@ REGRESSION_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; build_tools/rocksdb-lego-determinator run_regression || $CONTRUN_NAME=run_regression $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1173,7 +1173,7 @@ JAVA_BUILD_TEST_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; $SETUP_JAVA_ENV; $SHM make rocksdbjava || $CONTRUN_NAME=rocksdbjava $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
@@ -1207,7 +1207,7 @@ FBCODE_STRESS_CRASH_TEST_COMMANDS="[
|
||||
'shell':'cd $WORKING_DIR; mkdir /dev/shm/rocksdb_fbcode_crash_test && TEST_TMPDIR=\$(mktemp -d --tmpdir=/dev/shm/rocksdb_fbcode_crash_test) python3 rocksdb/src/tools/db_crashtest.py --stress_cmd=buck-out/dbg/gen/rocks/tools/rocks_db_stress -secondary_cache_uri=\"$SECONDARY_CACHE_URI\" --env_uri=$ENV_URI $EXTRA_DB_STRESS_ARGS -logtostderr=false $TEST_TYPE || $CONTRUN_NAME=db_stress_fbcode $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
},
|
||||
],
|
||||
$REPORT
|
||||
}
|
||||
|
||||
Vendored
+1
-3
@@ -75,8 +75,6 @@ class CacheReservationManager {
|
||||
Status UpdateCacheReservation(std::size_t new_memory_used);
|
||||
std::size_t GetTotalReservedCacheSize();
|
||||
|
||||
static constexpr std::size_t GetDummyEntrySize() { return kSizeDummyEntry; }
|
||||
|
||||
private:
|
||||
static constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
// The key will be longer than keys for blocks in SST files so they won't
|
||||
@@ -97,4 +95,4 @@ class CacheReservationManager {
|
||||
// The non-prefix part will be updated according to the ID to use.
|
||||
char cache_key_[kCacheKeyPrefixSize + kMaxVarint64Length];
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+5
-9
@@ -25,8 +25,7 @@ class CacheReservationManagerTest : public ::testing::Test {
|
||||
static constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
static constexpr int kNumShardBits = 0; // 2^0 shard
|
||||
|
||||
static constexpr std::size_t kSizeDummyEntry =
|
||||
CacheReservationManager::GetDummyEntrySize();
|
||||
static constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
static const std::size_t kCacheKeyPrefixSize =
|
||||
BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length;
|
||||
static constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
@@ -144,8 +143,7 @@ TEST(CacheReservationManagerIncreaseReservcationOnFullCacheTest,
|
||||
IncreaseCacheReservationOnFullCache) {
|
||||
constexpr std::size_t kOneMegabyte = 1024 * 1024;
|
||||
constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
constexpr std::size_t kSizeDummyEntry =
|
||||
CacheReservationManager::GetDummyEntrySize();
|
||||
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
LRUCacheOptions lo;
|
||||
@@ -309,8 +307,7 @@ TEST_F(CacheReservationManagerTest,
|
||||
TEST(CacheReservationManagerWithDelayedDecreaseTest,
|
||||
DecreaseCacheReservationWithDelayedDecrease) {
|
||||
constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
constexpr std::size_t kSizeDummyEntry =
|
||||
CacheReservationManager::GetDummyEntrySize();
|
||||
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
LRUCacheOptions lo;
|
||||
@@ -382,8 +379,7 @@ TEST(CacheReservationManagerWithDelayedDecreaseTest,
|
||||
TEST(CacheReservationManagerDestructorTest,
|
||||
ReleaseRemainingDummyEntriesOnDestruction) {
|
||||
constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
constexpr std::size_t kSizeDummyEntry =
|
||||
CacheReservationManager::GetDummyEntrySize();
|
||||
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
LRUCacheOptions lo;
|
||||
@@ -412,4 +408,4 @@ TEST(CacheReservationManagerDestructorTest,
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
}
|
||||
+1
-6
@@ -380,19 +380,14 @@ Status BuildTable(
|
||||
}
|
||||
}
|
||||
|
||||
Status status_for_listener = s;
|
||||
if (meta->fd.GetFileSize() == 0) {
|
||||
fname = "(nil)";
|
||||
if (s.ok()) {
|
||||
status_for_listener = Status::Aborted("Empty SST file not kept");
|
||||
}
|
||||
}
|
||||
// Output to event logger and fire events.
|
||||
EventHelpers::LogAndNotifyTableFileCreationFinished(
|
||||
event_logger, ioptions.listeners, dbname, tboptions.column_family_name,
|
||||
fname, job_id, meta->fd, meta->oldest_blob_file_number, tp,
|
||||
tboptions.reason, status_for_listener, file_checksum,
|
||||
file_checksum_func_name);
|
||||
tboptions.reason, s, file_checksum, file_checksum_func_name);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -612,19 +612,10 @@ bool Compaction::DoesInputReferenceBlobFiles() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t Compaction::MinInputFileOldestAncesterTime(
|
||||
const InternalKey* start, const InternalKey* end) const {
|
||||
uint64_t Compaction::MinInputFileOldestAncesterTime() const {
|
||||
uint64_t min_oldest_ancester_time = port::kMaxUint64;
|
||||
const InternalKeyComparator& icmp =
|
||||
column_family_data()->internal_comparator();
|
||||
for (const auto& level_files : inputs_) {
|
||||
for (const auto& file : level_files.files) {
|
||||
if (start != nullptr && icmp.Compare(file->largest, *start) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (end != nullptr && icmp.Compare(file->smallest, *end) > 0) {
|
||||
continue;
|
||||
}
|
||||
uint64_t oldest_ancester_time = file->TryGetOldestAncesterTime();
|
||||
if (oldest_ancester_time != 0) {
|
||||
min_oldest_ancester_time =
|
||||
|
||||
@@ -304,10 +304,7 @@ class Compaction {
|
||||
|
||||
uint32_t max_subcompactions() const { return max_subcompactions_; }
|
||||
|
||||
// start and end are sub compact range. Null if no boundary.
|
||||
// This is used to filter out some input files' ancester's time range.
|
||||
uint64_t MinInputFileOldestAncesterTime(const InternalKey* start,
|
||||
const InternalKey* end) const;
|
||||
uint64_t MinInputFileOldestAncesterTime() const;
|
||||
|
||||
// Called by DBImpl::NotifyOnCompactionCompleted to make sure number of
|
||||
// compaction begin and compaction completion callbacks match.
|
||||
|
||||
@@ -433,8 +433,6 @@ void CompactionIterator::NextFromInput() {
|
||||
|
||||
has_outputted_key_ = false;
|
||||
|
||||
last_key_seq_zeroed_ = false;
|
||||
|
||||
current_key_committed_ = KeyCommitted(ikey_.sequence);
|
||||
|
||||
// Apply the compaction filter to the first committed version of the user
|
||||
@@ -522,25 +520,6 @@ void CompactionIterator::NextFromInput() {
|
||||
// 2) We've already returned a record in this snapshot -OR-
|
||||
// there are no earlier earliest_write_conflict_snapshot.
|
||||
//
|
||||
// A note about 2) above:
|
||||
// we try to determine whether there is any earlier write conflict
|
||||
// checking snapshot by calling DefinitelyInSnapshot() with seq and
|
||||
// earliest_write_conflict_snapshot as arguments. For write-prepared
|
||||
// and write-unprepared transactions, if earliest_write_conflict_snapshot
|
||||
// is evicted from WritePreparedTxnDB::commit_cache, then
|
||||
// DefinitelyInSnapshot(seq, earliest_write_conflict_snapshot) returns
|
||||
// false, even if the seq is actually visible within
|
||||
// earliest_write_conflict_snapshot. Consequently, CompactionIterator
|
||||
// may try to zero out its sequence number, thus hitting assertion error
|
||||
// in debug mode or cause incorrect DBIter return result.
|
||||
// We observe that earliest_write_conflict_snapshot >= earliest_snapshot,
|
||||
// and the seq zeroing logic depends on
|
||||
// DefinitelyInSnapshot(seq, earliest_snapshot). Therefore, if we cannot
|
||||
// determine whether seq is **definitely** in
|
||||
// earliest_write_conflict_snapshot, then we can additionally check if
|
||||
// seq is definitely in earliest_snapshot. If the latter holds, then the
|
||||
// former holds too.
|
||||
//
|
||||
// Rule 1 is needed for SingleDelete correctness. Rule 2 is needed to
|
||||
// allow Transactions to do write-conflict checking (if we compacted away
|
||||
// all keys, then we wouldn't know that a write happened in this
|
||||
@@ -596,16 +575,10 @@ void CompactionIterator::NextFromInput() {
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionIterator::NextFromInput:SingleDelete:1",
|
||||
const_cast<Compaction*>(c));
|
||||
if (last_key_seq_zeroed_) {
|
||||
++iter_stats_.num_record_drop_hidden;
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
assert(bottommost_level_);
|
||||
AdvanceInputIter();
|
||||
} else if (prev_snapshot == 0 ||
|
||||
DefinitelyNotInSnapshot(next_ikey.sequence, prev_snapshot)) {
|
||||
// Check whether the next key belongs to the same snapshot as the
|
||||
// SingleDelete.
|
||||
|
||||
// Check whether the next key belongs to the same snapshot as the
|
||||
// SingleDelete.
|
||||
if (prev_snapshot == 0 ||
|
||||
DefinitelyNotInSnapshot(next_ikey.sequence, prev_snapshot)) {
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionIterator::NextFromInput:SingleDelete:2", nullptr);
|
||||
if (next_ikey.type == kTypeSingleDeletion) {
|
||||
@@ -625,10 +598,7 @@ void CompactionIterator::NextFromInput() {
|
||||
valid_ = true;
|
||||
} else if (has_outputted_key_ ||
|
||||
DefinitelyInSnapshot(ikey_.sequence,
|
||||
earliest_write_conflict_snapshot_) ||
|
||||
(earliest_snapshot_ < earliest_write_conflict_snapshot_ &&
|
||||
DefinitelyInSnapshot(ikey_.sequence,
|
||||
earliest_snapshot_))) {
|
||||
earliest_write_conflict_snapshot_)) {
|
||||
// Found a matching value, we can drop the single delete and the
|
||||
// value. It is safe to drop both records since we've already
|
||||
// outputted a key in this snapshot, or there is no earlier
|
||||
@@ -669,9 +639,6 @@ void CompactionIterator::NextFromInput() {
|
||||
// We hit the next snapshot without hitting a put, so the iterator
|
||||
// returns the single delete.
|
||||
valid_ = true;
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionIterator::NextFromInput:SingleDelete:3",
|
||||
const_cast<Compaction*>(c));
|
||||
}
|
||||
} else {
|
||||
// We are at the end of the input, could not parse the next key, or hit
|
||||
@@ -694,11 +661,6 @@ void CompactionIterator::NextFromInput() {
|
||||
if (!bottommost_level_) {
|
||||
++iter_stats_.num_optimized_del_drop_obsolete;
|
||||
}
|
||||
} else if (last_key_seq_zeroed_) {
|
||||
// Skip.
|
||||
++iter_stats_.num_record_drop_hidden;
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
assert(bottommost_level_);
|
||||
} else {
|
||||
// Output SingleDelete
|
||||
valid_ = true;
|
||||
@@ -1054,9 +1016,6 @@ void CompactionIterator::PrepareOutput() {
|
||||
ikey_.type);
|
||||
}
|
||||
ikey_.sequence = 0;
|
||||
last_key_seq_zeroed_ = true;
|
||||
TEST_SYNC_POINT_CALLBACK("CompactionIterator::PrepareOutput:ZeroingSeq",
|
||||
&ikey_);
|
||||
if (!timestamp_size_) {
|
||||
current_key_.UpdateInternalKey(0, ikey_.type);
|
||||
} else if (full_history_ts_low_ && cmp_with_history_ts_low_ < 0) {
|
||||
@@ -1125,6 +1084,41 @@ inline bool CompactionIterator::ikeyNotNeededForIncrementalSnapshot() {
|
||||
(ikey_.sequence < preserve_deletes_seqnum_);
|
||||
}
|
||||
|
||||
bool CompactionIterator::IsInCurrentEarliestSnapshot(SequenceNumber sequence) {
|
||||
assert(snapshot_checker_ != nullptr);
|
||||
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)) {
|
||||
// Avoid the the current earliest_snapshot_ being return as
|
||||
// earliest visible snapshot for the next value. So if a value's sequence
|
||||
// is zero-ed out by PrepareOutput(), the next value will be compact out.
|
||||
released_snapshots_.insert(earliest_snapshot_);
|
||||
earliest_snapshot_iter_++;
|
||||
|
||||
if (earliest_snapshot_iter_ == snapshots_->end()) {
|
||||
earliest_snapshot_ = kMaxSequenceNumber;
|
||||
} else {
|
||||
earliest_snapshot_ = *earliest_snapshot_iter_;
|
||||
}
|
||||
in_snapshot =
|
||||
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;
|
||||
}
|
||||
|
||||
uint64_t CompactionIterator::ComputeBlobGarbageCollectionCutoffFileNumber(
|
||||
const CompactionProxy* compaction) {
|
||||
if (!compaction) {
|
||||
|
||||
@@ -271,10 +271,14 @@ class CompactionIterator {
|
||||
SnapshotCheckerResult::kInSnapshot;
|
||||
}
|
||||
|
||||
bool IsInCurrentEarliestSnapshot(SequenceNumber sequence);
|
||||
|
||||
bool DefinitelyInSnapshot(SequenceNumber seq, SequenceNumber snapshot);
|
||||
|
||||
bool DefinitelyNotInSnapshot(SequenceNumber seq, SequenceNumber snapshot);
|
||||
|
||||
bool InCurrentEarliestSnapshot(SequenceNumber seq);
|
||||
|
||||
// Extract user-defined timestamp from user key if possible and compare it
|
||||
// with *full_history_ts_low_ if applicable.
|
||||
inline void UpdateTimestampAndCompareWithFullHistoryLow() {
|
||||
@@ -401,10 +405,6 @@ class CompactionIterator {
|
||||
|
||||
const int level_;
|
||||
|
||||
// True if the previous internal key (same user key)'s sequence number has
|
||||
// just been zeroed out during bottommost compaction.
|
||||
bool last_key_seq_zeroed_{false};
|
||||
|
||||
void AdvanceInputIter() { input_.Next(); }
|
||||
|
||||
void SkipUntil(const Slice& skip_until) { input_.Seek(skip_until); }
|
||||
@@ -439,4 +439,10 @@ inline bool CompactionIterator::DefinitelyNotInSnapshot(
|
||||
SnapshotCheckerResult::kNotInSnapshot)));
|
||||
}
|
||||
|
||||
inline bool CompactionIterator::InCurrentEarliestSnapshot(SequenceNumber seq) {
|
||||
return ((seq) <= earliest_snapshot_ &&
|
||||
(snapshot_checker_ == nullptr ||
|
||||
LIKELY(IsInCurrentEarliestSnapshot(seq))));
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -170,13 +170,6 @@ struct CompactionJob::SubcompactionState {
|
||||
}
|
||||
}
|
||||
|
||||
// Some identified files with old oldest ancester time and the range should be
|
||||
// isolated out so that the output file(s) in that range can be merged down
|
||||
// for TTL and clear the timestamps for the range.
|
||||
std::vector<FileMetaData*> files_to_cut_for_ttl;
|
||||
int cur_files_to_cut_for_ttl = -1;
|
||||
int next_files_to_cut_for_ttl = 0;
|
||||
|
||||
uint64_t current_output_file_size = 0;
|
||||
|
||||
// State during the subcompaction
|
||||
@@ -219,8 +212,6 @@ struct CompactionJob::SubcompactionState {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void FillFilesToCutForTtl();
|
||||
|
||||
// Returns true iff we should stop building the current output
|
||||
// before processing "internal_key".
|
||||
bool ShouldStopBefore(const Slice& internal_key, uint64_t curr_file_size) {
|
||||
@@ -253,40 +244,6 @@ struct CompactionJob::SubcompactionState {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!files_to_cut_for_ttl.empty()) {
|
||||
if (cur_files_to_cut_for_ttl != -1) {
|
||||
// Previous key is inside the range of a file
|
||||
if (icmp->Compare(internal_key,
|
||||
files_to_cut_for_ttl[cur_files_to_cut_for_ttl]
|
||||
->largest.Encode()) > 0) {
|
||||
next_files_to_cut_for_ttl = cur_files_to_cut_for_ttl + 1;
|
||||
cur_files_to_cut_for_ttl = -1;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Look for the key position
|
||||
while (next_files_to_cut_for_ttl <
|
||||
static_cast<int>(files_to_cut_for_ttl.size())) {
|
||||
if (icmp->Compare(internal_key,
|
||||
files_to_cut_for_ttl[next_files_to_cut_for_ttl]
|
||||
->smallest.Encode()) >= 0) {
|
||||
if (icmp->Compare(internal_key,
|
||||
files_to_cut_for_ttl[next_files_to_cut_for_ttl]
|
||||
->largest.Encode()) <= 0) {
|
||||
// With in the current file
|
||||
cur_files_to_cut_for_ttl = next_files_to_cut_for_ttl;
|
||||
return true;
|
||||
}
|
||||
// Beyond the current file
|
||||
next_files_to_cut_for_ttl++;
|
||||
} else {
|
||||
// Still fall into the gap
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -299,46 +256,6 @@ struct CompactionJob::SubcompactionState {
|
||||
}
|
||||
};
|
||||
|
||||
void CompactionJob::SubcompactionState::FillFilesToCutForTtl() {
|
||||
if (compaction->immutable_options()->compaction_style !=
|
||||
CompactionStyle::kCompactionStyleLevel ||
|
||||
compaction->immutable_options()->compaction_pri !=
|
||||
CompactionPri::kMinOverlappingRatio ||
|
||||
compaction->mutable_cf_options()->ttl == 0 ||
|
||||
compaction->num_input_levels() < 2 || compaction->bottommost_level()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We define new file with oldest ancestor time to be younger than 1/4 TTL,
|
||||
// and an old one to be older than 1/2 TTL time.
|
||||
int64_t temp_current_time;
|
||||
auto get_time_status = compaction->immutable_options()->clock->GetCurrentTime(
|
||||
&temp_current_time);
|
||||
if (!get_time_status.ok()) {
|
||||
return;
|
||||
}
|
||||
uint64_t current_time = static_cast<uint64_t>(temp_current_time);
|
||||
if (current_time < compaction->mutable_cf_options()->ttl) {
|
||||
return;
|
||||
}
|
||||
uint64_t old_age_thres =
|
||||
current_time - compaction->mutable_cf_options()->ttl / 2;
|
||||
|
||||
const std::vector<FileMetaData*>& olevel =
|
||||
*(compaction->inputs(compaction->num_input_levels() - 1));
|
||||
for (FileMetaData* file : olevel) {
|
||||
// Worth filtering out by start and end?
|
||||
uint64_t oldest_ancester_time = file->TryGetOldestAncesterTime();
|
||||
// We put old files if they are not too small to prevent a flood
|
||||
// of small files.
|
||||
if (oldest_ancester_time < old_age_thres &&
|
||||
file->fd.GetFileSize() >
|
||||
compaction->mutable_cf_options()->target_file_size_base / 2) {
|
||||
files_to_cut_for_ttl.push_back(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maintains state for the entire compaction
|
||||
struct CompactionJob::CompactionState {
|
||||
Compaction* const compaction;
|
||||
@@ -763,16 +680,12 @@ Status CompactionJob::Run() {
|
||||
constexpr IODebugContext* dbg = nullptr;
|
||||
|
||||
if (output_directory_) {
|
||||
io_s = output_directory_->FsyncWithDirOptions(
|
||||
IOOptions(), dbg,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
io_s = output_directory_->Fsync(IOOptions(), dbg);
|
||||
}
|
||||
|
||||
if (io_s.ok() && wrote_new_blob_files && blob_output_directory_ &&
|
||||
blob_output_directory_ != output_directory_) {
|
||||
io_s = blob_output_directory_->FsyncWithDirOptions(
|
||||
IOOptions(), dbg,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
io_s = blob_output_directory_->Fsync(IOOptions(), dbg);
|
||||
}
|
||||
}
|
||||
if (io_status_.ok()) {
|
||||
@@ -1378,7 +1291,6 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
auto c_iter = sub_compact->c_iter.get();
|
||||
c_iter->SeekToFirst();
|
||||
if (c_iter->Valid() && sub_compact->compaction->output_level() != 0) {
|
||||
sub_compact->FillFilesToCutForTtl();
|
||||
// ShouldStopBefore() maintains state based on keys processed so far. The
|
||||
// compaction loop always calls it on the "next" key, thus won't tell it the
|
||||
// first key. So we do that here.
|
||||
@@ -1827,6 +1739,7 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
meta->UpdateBoundariesForRange(smallest_candidate, largest_candidate,
|
||||
tombstone.seq_,
|
||||
cfd->internal_comparator());
|
||||
|
||||
// The smallest key in a file is used for range tombstone truncation, so
|
||||
// it cannot have a seqnum of 0 (unless the smallest data key in a file
|
||||
// has a seqnum of 0). Otherwise, the truncated tombstone may expose
|
||||
@@ -1850,23 +1763,6 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
if (s.ok()) {
|
||||
meta->fd.file_size = current_bytes;
|
||||
meta->marked_for_compaction = sub_compact->builder->NeedCompact();
|
||||
// With accurate smallest and largest key, we can get a slightly more
|
||||
// accurate oldest ancester time.
|
||||
// This makes oldest ancester time in manifest more accurate than in
|
||||
// table properties. Not sure how to resolve it.
|
||||
if (meta->smallest.size() > 0 && meta->largest.size() > 0) {
|
||||
uint64_t refined_oldest_ancester_time;
|
||||
Slice new_smallest = meta->smallest.user_key();
|
||||
Slice new_largest = meta->largest.user_key();
|
||||
if (!new_largest.empty() && !new_smallest.empty()) {
|
||||
refined_oldest_ancester_time =
|
||||
sub_compact->compaction->MinInputFileOldestAncesterTime(
|
||||
&(meta->smallest), &(meta->largest));
|
||||
if (refined_oldest_ancester_time != port::kMaxUint64) {
|
||||
meta->oldest_ancester_time = refined_oldest_ancester_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sub_compact->current_output()->finished = true;
|
||||
sub_compact->total_bytes += current_bytes;
|
||||
@@ -2137,17 +2033,8 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
get_time_status.ToString().c_str());
|
||||
}
|
||||
uint64_t current_time = static_cast<uint64_t>(temp_current_time);
|
||||
InternalKey tmp_start, tmp_end;
|
||||
if (sub_compact->start != nullptr) {
|
||||
tmp_start.SetMinPossibleForUserKey(*(sub_compact->start));
|
||||
}
|
||||
if (sub_compact->end != nullptr) {
|
||||
tmp_end.SetMinPossibleForUserKey(*(sub_compact->end));
|
||||
}
|
||||
uint64_t oldest_ancester_time =
|
||||
sub_compact->compaction->MinInputFileOldestAncesterTime(
|
||||
(sub_compact->start != nullptr) ? &tmp_start : nullptr,
|
||||
(sub_compact->end != nullptr) ? &tmp_end : nullptr);
|
||||
sub_compact->compaction->MinInputFileOldestAncesterTime();
|
||||
if (oldest_ancester_time == port::kMaxUint64) {
|
||||
oldest_ancester_time = current_time;
|
||||
}
|
||||
@@ -2446,8 +2333,7 @@ Status CompactionServiceCompactionJob::Run() {
|
||||
constexpr IODebugContext* dbg = nullptr;
|
||||
|
||||
if (output_directory_) {
|
||||
io_s = output_directory_->FsyncWithDirOptions(IOOptions(), dbg,
|
||||
DirFsyncOptions());
|
||||
io_s = output_directory_->Fsync(IOOptions(), dbg);
|
||||
}
|
||||
}
|
||||
if (io_status_.ok()) {
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "db/compaction/compaction.h"
|
||||
#include "db/compaction/compaction_picker_fifo.h"
|
||||
#include "db/compaction/compaction_picker_level.h"
|
||||
#include "db/compaction/compaction_picker_universal.h"
|
||||
#include "db/compaction/file_pri.h"
|
||||
|
||||
#include "test_util/testharness.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
@@ -149,7 +149,7 @@ class CompactionPickerTest : public testing::Test {
|
||||
vstorage_ = std::move(temp_vstorage_);
|
||||
}
|
||||
vstorage_->CalculateBaseBytes(ioptions_, mutable_cf_options_);
|
||||
vstorage_->UpdateFilesByCompactionPri(ioptions_, mutable_cf_options_);
|
||||
vstorage_->UpdateFilesByCompactionPri(ioptions_.compaction_pri);
|
||||
vstorage_->UpdateNumNonEmptyLevels();
|
||||
vstorage_->GenerateFileIndexer();
|
||||
vstorage_->GenerateLevelFilesBrief();
|
||||
@@ -1673,66 +1673,6 @@ TEST_F(CompactionPickerTest, OverlappingUserKeys11) {
|
||||
ASSERT_EQ(7U, compaction->input(1, 0)->fd.GetNumber());
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, FileTtlBooster) {
|
||||
// Set TTL to 2048
|
||||
// TTL boosting for all levels starts at 1024,
|
||||
// Whole TTL range is 2048 * 31 / 32 - 1024 = 1984 - 1024 = 960.
|
||||
// From second last level (L5), range starts at
|
||||
// 1024 + 480, 1024 + 240, 1024 + 120 (which is L3).
|
||||
// Boosting step 124 / 16 = 7.75 -> 7
|
||||
//
|
||||
const uint64_t kCurrentTime = 1000000;
|
||||
FileMetaData meta;
|
||||
|
||||
{
|
||||
FileTtlBooster booster(kCurrentTime, 2048, 7, 3);
|
||||
|
||||
// Not triggering if the file is younger than ttl/2
|
||||
meta.oldest_ancester_time = kCurrentTime - 1023;
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
meta.oldest_ancester_time = kCurrentTime - 1024;
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
meta.oldest_ancester_time = kCurrentTime + 10;
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
|
||||
// Within one boosting step
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 120 + 6);
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
|
||||
// One boosting step
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 120 + 7);
|
||||
ASSERT_EQ(2, booster.GetBoostScore(&meta));
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 120 + 8);
|
||||
ASSERT_EQ(2, booster.GetBoostScore(&meta));
|
||||
|
||||
// Multiple boosting steps
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 120 + 30);
|
||||
ASSERT_EQ(5, booster.GetBoostScore(&meta));
|
||||
|
||||
// Very high boosting steps
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 120 + 700);
|
||||
ASSERT_EQ(101, booster.GetBoostScore(&meta));
|
||||
}
|
||||
{
|
||||
// Test second last level
|
||||
FileTtlBooster booster(kCurrentTime, 2048, 7, 5);
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 480);
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 480 + 60);
|
||||
ASSERT_EQ(3, booster.GetBoostScore(&meta));
|
||||
}
|
||||
{
|
||||
// Test last level
|
||||
FileTtlBooster booster(kCurrentTime, 2048, 7, 6);
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 480);
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
meta.oldest_ancester_time = kCurrentTime - (1024 + 480 + 60);
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
meta.oldest_ancester_time = kCurrentTime - 3000;
|
||||
ASSERT_EQ(1, booster.GetBoostScore(&meta));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri1) {
|
||||
NewVersionStorage(6, kCompactionStyleLevel);
|
||||
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
// 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 <algorithm>
|
||||
|
||||
#include "db/version_edit.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
// We boost files that are closer to TTL limit. This boosting could be
|
||||
// through FileMetaData.compensated_file_size but this compensated size
|
||||
// is widely used as something similar to file size so dramatically boost
|
||||
// the value might cause unintended consequences.
|
||||
//
|
||||
// This boosting algorithm can go very fancy, but here we use a simple
|
||||
// formula which can satisify:
|
||||
// (1) Different levels are triggered slightly differently to avoid
|
||||
// too many cascading cases
|
||||
// (2) Files in the same level get boosting more when TTL gets closer.
|
||||
//
|
||||
// Don't do any boosting before TTL has past by half. This is to make
|
||||
// sure lower write amp for most of the case. And all levels should be
|
||||
// fully boosted when total TTL compaction threshold triggers.
|
||||
// Differientiate boosting ranges of each level by 1/2. This will make
|
||||
// range for each level exponentially increasing. We could do it by
|
||||
// having them to be equal, or go even fancier. We can adjust it after
|
||||
// we observe the behavior in production.
|
||||
// The threshold starting boosting:
|
||||
// +------------------------------------------------------------------ +
|
||||
// ^ ^ ^ ^ ^ ^
|
||||
// Age 0 ... | | second last level thresold
|
||||
// | |
|
||||
// | third last level
|
||||
// |
|
||||
// forth last level
|
||||
//
|
||||
// We arbitrarily set with 0 when a file is aged boost_age_start and
|
||||
// grow linearly. The ratio is arbitrarily set so that when the next level
|
||||
// starts to boost, the previous level's boosting amount is 16.
|
||||
class FileTtlBooster {
|
||||
public:
|
||||
FileTtlBooster(uint64_t current_time, uint64_t ttl, int num_non_empty_levels,
|
||||
int level)
|
||||
: current_time_(current_time) {
|
||||
if (ttl == 0 || level == 0 || level >= num_non_empty_levels - 1) {
|
||||
enabled_ = false;
|
||||
boost_age_start_ = 0;
|
||||
boost_step_ = 1;
|
||||
} else {
|
||||
enabled_ = true;
|
||||
uint64_t all_boost_start_age = ttl / 2;
|
||||
uint64_t all_boost_age_range = (ttl / 32) * 31 - all_boost_start_age;
|
||||
uint64_t boost_age_range =
|
||||
all_boost_age_range >> (num_non_empty_levels - level - 1);
|
||||
boost_age_start_ = all_boost_start_age + boost_age_range;
|
||||
const uint64_t kBoostRatio = 16;
|
||||
// prevent 0 value to avoid divide 0 error.
|
||||
boost_step_ = std::max(boost_age_range / kBoostRatio, uint64_t{1});
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t GetBoostScore(FileMetaData* f) {
|
||||
if (!enabled_) {
|
||||
return 1;
|
||||
}
|
||||
uint64_t oldest_ancester_time = f->TryGetOldestAncesterTime();
|
||||
if (oldest_ancester_time >= current_time_) {
|
||||
return 1;
|
||||
}
|
||||
uint64_t age = current_time_ - oldest_ancester_time;
|
||||
if (age > boost_age_start_) {
|
||||
// Use integer just for convenience.
|
||||
// We could make all file_to_order double if we want.
|
||||
// Technically this can overflow if users override timing and
|
||||
// give a very high current time. Ignore the case for simplicity.
|
||||
// Boosting is addition to current value, so +1. This will effectively
|
||||
// make boosting to kick in after the first boost_step_ is reached.
|
||||
return (age - boost_age_start_) / boost_step_ + 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
bool enabled_;
|
||||
uint64_t current_time_;
|
||||
uint64_t boost_age_start_;
|
||||
uint64_t boost_step_;
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+7
-17
@@ -10,7 +10,6 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/flush_block_policy.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
@@ -975,14 +974,13 @@ TEST_F(DBBasicTest, MultiGetEmpty) {
|
||||
TEST_F(DBBasicTest, ChecksumTest) {
|
||||
BlockBasedTableOptions table_options;
|
||||
Options options = CurrentOptions();
|
||||
// change when new checksum type added
|
||||
int max_checksum = static_cast<int>(kxxHash64);
|
||||
const int kNumPerFile = 2;
|
||||
|
||||
const auto algs = GetSupportedChecksums();
|
||||
const int algs_size = static_cast<int>(algs.size());
|
||||
|
||||
// generate one table with each type of checksum
|
||||
for (int i = 0; i < algs_size; ++i) {
|
||||
table_options.checksum = algs[i];
|
||||
for (int i = 0; i <= max_checksum; ++i) {
|
||||
table_options.checksum = static_cast<ChecksumType>(i);
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
for (int j = 0; j < kNumPerFile; ++j) {
|
||||
@@ -992,20 +990,15 @@ TEST_F(DBBasicTest, ChecksumTest) {
|
||||
}
|
||||
|
||||
// with each valid checksum type setting...
|
||||
for (int i = 0; i < algs_size; ++i) {
|
||||
table_options.checksum = algs[i];
|
||||
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 < algs_size * kNumPerFile; ++j) {
|
||||
for (int j = 0; j < (max_checksum + 1) * kNumPerFile; ++j) {
|
||||
ASSERT_EQ(Key(j), Get(Key(j)));
|
||||
}
|
||||
}
|
||||
|
||||
// Now test invalid checksum type
|
||||
table_options.checksum = static_cast<ChecksumType>(123);
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
ASSERT_TRUE(TryReopen(options).IsInvalidArgument());
|
||||
}
|
||||
|
||||
// On Windows you can have either memory mapped file or a file
|
||||
@@ -3296,9 +3289,6 @@ class DeadlineFS : public FileSystemWrapper {
|
||||
ignore_deadline_(false),
|
||||
error_on_delay_(error_on_delay) {}
|
||||
|
||||
static const char* kClassName() { return "DeadlineFileSystem"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
IOStatus NewRandomAccessFile(const std::string& fname,
|
||||
const FileOptions& opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* result,
|
||||
|
||||
@@ -4302,67 +4302,6 @@ TEST_F(DBCompactionTest, LevelPeriodicAndTtlCompaction) {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, LevelTtlBooster) {
|
||||
const int kNumKeysPerFile = 32;
|
||||
const int kNumLevelFiles = 3;
|
||||
const int kValueSize = 1000;
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.ttl = 10 * 60 * 60; // 10 hours
|
||||
options.periodic_compaction_seconds = 480 * 60 * 60; // very long
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.max_bytes_for_level_base = 5 * uint64_t{kNumKeysPerFile * kValueSize};
|
||||
options.max_open_files = -1; // needed for both periodic and ttl compactions
|
||||
options.compaction_pri = CompactionPri::kMinOverlappingRatio;
|
||||
env_->SetMockSleep();
|
||||
options.env = env_;
|
||||
|
||||
// NOTE: Presumed unnecessary and removed: resetting mock time in env
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < kNumLevelFiles; ++i) {
|
||||
for (int j = 0; j < kNumKeysPerFile; ++j) {
|
||||
ASSERT_OK(
|
||||
Put(Key(i * kNumKeysPerFile + j), rnd.RandomString(kValueSize)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
MoveFilesToLevel(2);
|
||||
|
||||
ASSERT_EQ("0,0,3", FilesPerLevel());
|
||||
|
||||
// Create some files for L1
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < kNumKeysPerFile; ++j) {
|
||||
ASSERT_OK(Put(Key(2 * j + i), rnd.RandomString(kValueSize)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
|
||||
ASSERT_EQ("0,1,3", FilesPerLevel());
|
||||
|
||||
// Make the new L0 files qualify TTL boosting and generate one more to trigger
|
||||
// L1 -> L2 compaction. Old files will be picked even if their priority is
|
||||
// lower without boosting.
|
||||
env_->MockSleepForSeconds(8 * 60 * 60);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < kNumKeysPerFile; ++j) {
|
||||
ASSERT_OK(Put(Key(kNumKeysPerFile * 2 + 2 * j + i),
|
||||
rnd.RandomString(kValueSize * 2)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
ASSERT_EQ("0,1,2", FilesPerLevel());
|
||||
|
||||
ASSERT_GT(SizeAtLevel(1), kNumKeysPerFile * 4 * kValueSize);
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, LevelPeriodicCompactionWithCompactionFilters) {
|
||||
class TestCompactionFilter : public CompactionFilter {
|
||||
const char* Name() const override { return "TestCompactionFilter"; }
|
||||
@@ -6924,82 +6863,6 @@ TEST_F(DBCompactionTest,
|
||||
ASSERT_TRUE(callback_completed);
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, ChangeLevelConflictsWithManual) {
|
||||
Options options = CurrentOptions();
|
||||
options.num_levels = 3;
|
||||
Reopen(options);
|
||||
|
||||
// Setup an LSM with L2 populated.
|
||||
Random rnd(301);
|
||||
ASSERT_OK(Put(Key(0), rnd.RandomString(990)));
|
||||
ASSERT_OK(Put(Key(1), rnd.RandomString(990)));
|
||||
{
|
||||
CompactRangeOptions cro;
|
||||
cro.change_level = true;
|
||||
cro.target_level = 2;
|
||||
ASSERT_OK(dbfull()->CompactRange(cro, nullptr, nullptr));
|
||||
}
|
||||
ASSERT_EQ("0,0,1", FilesPerLevel(0));
|
||||
|
||||
// The background thread will refit L2->L1 while the foreground thread will
|
||||
// attempt to run a compaction on new data. The following dependencies
|
||||
// ensure the background manual compaction's refitting phase disables manual
|
||||
// compaction immediately before the foreground manual compaction can register
|
||||
// itself. Manual compaction is kept disabled until the foreground manual
|
||||
// checks for the failure once.
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
|
||||
// Only do Put()s for foreground CompactRange() once the background
|
||||
// CompactRange() has reached the refitting phase.
|
||||
{
|
||||
"DBImpl::CompactRange:BeforeRefit:1",
|
||||
"DBCompactionTest::ChangeLevelConflictsWithManual:"
|
||||
"PreForegroundCompactRange",
|
||||
},
|
||||
// Right before we register the manual compaction, proceed with
|
||||
// the refitting phase so manual compactions are disabled. Stay in
|
||||
// the refitting phase with manual compactions disabled until it is
|
||||
// noticed.
|
||||
{
|
||||
"DBImpl::RunManualCompaction:0",
|
||||
"DBImpl::CompactRange:BeforeRefit:2",
|
||||
},
|
||||
{
|
||||
"DBImpl::CompactRange:PreRefitLevel",
|
||||
"DBImpl::RunManualCompaction:1",
|
||||
},
|
||||
{
|
||||
"DBImpl::RunManualCompaction:PausedAtStart",
|
||||
"DBImpl::CompactRange:PostRefitLevel",
|
||||
},
|
||||
// If compaction somehow were scheduled, let's let it run after reenabling
|
||||
// manual compactions. This dependency is not expected to be hit but is
|
||||
// here for speculatively coercing future bugs.
|
||||
{
|
||||
"DBImpl::CompactRange:PostRefitLevel:ManualCompactionEnabled",
|
||||
"BackgroundCallCompaction:0",
|
||||
},
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ROCKSDB_NAMESPACE::port::Thread refit_level_thread([&] {
|
||||
CompactRangeOptions cro;
|
||||
cro.change_level = true;
|
||||
cro.target_level = 1;
|
||||
ASSERT_OK(dbfull()->CompactRange(cro, nullptr, nullptr));
|
||||
});
|
||||
|
||||
TEST_SYNC_POINT(
|
||||
"DBCompactionTest::ChangeLevelConflictsWithManual:"
|
||||
"PreForegroundCompactRange");
|
||||
ASSERT_OK(Put(Key(0), rnd.RandomString(990)));
|
||||
ASSERT_OK(Put(Key(1), rnd.RandomString(990)));
|
||||
ASSERT_TRUE(dbfull()
|
||||
->CompactRange(CompactRangeOptions(), nullptr, nullptr)
|
||||
.IsIncomplete());
|
||||
|
||||
refit_level_thread.join();
|
||||
}
|
||||
|
||||
#endif // !defined(ROCKSDB_LITE)
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
+22
-20
@@ -783,8 +783,8 @@ TEST_F(DBFlushTest, MemPurgeBasic) {
|
||||
options.listeners.emplace_back(listener);
|
||||
#endif // !ROCKSDB_LITE
|
||||
ASSERT_OK(TryReopen(options));
|
||||
std::atomic<uint32_t> mempurge_count{0};
|
||||
std::atomic<uint32_t> sst_count{0};
|
||||
uint32_t mempurge_count = 0;
|
||||
uint32_t sst_count = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::FlushJob:MemPurgeSuccessful",
|
||||
[&](void* /*arg*/) { mempurge_count++; });
|
||||
@@ -859,8 +859,10 @@ TEST_F(DBFlushTest, MemPurgeBasic) {
|
||||
// Check that there was no SST files created during flush.
|
||||
const uint32_t EXPECTED_SST_COUNT = 0;
|
||||
|
||||
EXPECT_GE(mempurge_count.exchange(0), EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_EQ(sst_count.exchange(0), EXPECTED_SST_COUNT);
|
||||
EXPECT_GE(mempurge_count, EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_EQ(sst_count, EXPECTED_SST_COUNT);
|
||||
|
||||
const uint32_t mempurge_count_record = mempurge_count;
|
||||
|
||||
// Insertion of of K-V pairs, no overwrites.
|
||||
for (size_t i = 0; i < NUM_REPEAT; i++) {
|
||||
@@ -891,9 +893,9 @@ TEST_F(DBFlushTest, MemPurgeBasic) {
|
||||
}
|
||||
|
||||
// Assert that at least one flush to storage has been performed
|
||||
EXPECT_GT(sst_count.exchange(0), EXPECTED_SST_COUNT);
|
||||
ASSERT_GT(sst_count, EXPECTED_SST_COUNT);
|
||||
// (which will consequently increase the number of mempurges recorded too).
|
||||
EXPECT_GE(mempurge_count.exchange(0), EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
ASSERT_GE(mempurge_count, mempurge_count_record);
|
||||
|
||||
// Assert that there is no data corruption, even with
|
||||
// a flush to storage.
|
||||
@@ -933,8 +935,8 @@ TEST_F(DBFlushTest, MemPurgeDeleteAndDeleteRange) {
|
||||
|
||||
ASSERT_OK(TryReopen(options));
|
||||
|
||||
std::atomic<uint32_t> mempurge_count{0};
|
||||
std::atomic<uint32_t> sst_count{0};
|
||||
uint32_t mempurge_count = 0;
|
||||
uint32_t sst_count = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::FlushJob:MemPurgeSuccessful",
|
||||
[&](void* /*arg*/) { mempurge_count++; });
|
||||
@@ -1022,8 +1024,8 @@ TEST_F(DBFlushTest, MemPurgeDeleteAndDeleteRange) {
|
||||
// Check that there was no SST files created during flush.
|
||||
const uint32_t EXPECTED_SST_COUNT = 0;
|
||||
|
||||
EXPECT_GE(mempurge_count.exchange(0), EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_EQ(sst_count.exchange(0), EXPECTED_SST_COUNT);
|
||||
EXPECT_GE(mempurge_count, EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_EQ(sst_count, EXPECTED_SST_COUNT);
|
||||
|
||||
// Additional test for the iterator+memPurge.
|
||||
ASSERT_OK(Put(KEY2, p_v2));
|
||||
@@ -1140,8 +1142,8 @@ TEST_F(DBFlushTest, MemPurgeAndCompactionFilter) {
|
||||
|
||||
ASSERT_OK(TryReopen(options));
|
||||
|
||||
std::atomic<uint32_t> mempurge_count{0};
|
||||
std::atomic<uint32_t> sst_count{0};
|
||||
uint32_t mempurge_count = 0;
|
||||
uint32_t sst_count = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::FlushJob:MemPurgeSuccessful",
|
||||
[&](void* /*arg*/) { mempurge_count++; });
|
||||
@@ -1187,8 +1189,8 @@ TEST_F(DBFlushTest, MemPurgeAndCompactionFilter) {
|
||||
// Check that there was no SST files created during flush.
|
||||
const uint32_t EXPECTED_SST_COUNT = 0;
|
||||
|
||||
EXPECT_GE(mempurge_count.exchange(0), EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_EQ(sst_count.exchange(0), EXPECTED_SST_COUNT);
|
||||
EXPECT_GE(mempurge_count, EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_EQ(sst_count, EXPECTED_SST_COUNT);
|
||||
|
||||
// Verify that the ConditionalUpdateCompactionFilter
|
||||
// updated the values of KEY2 and KEY3, and not KEY4 and KEY5.
|
||||
@@ -1231,8 +1233,8 @@ TEST_F(DBFlushTest, MemPurgeWALSupport) {
|
||||
ASSERT_OK(Put(0, "bar", "v2"));
|
||||
ASSERT_OK(Put(1, "bar", "v2"));
|
||||
ASSERT_OK(Put(1, "foo", "v3"));
|
||||
std::atomic<uint32_t> mempurge_count{0};
|
||||
std::atomic<uint32_t> sst_count{0};
|
||||
uint32_t mempurge_count = 0;
|
||||
uint32_t sst_count = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::FlushJob:MemPurgeSuccessful",
|
||||
[&](void* /*arg*/) { mempurge_count++; });
|
||||
@@ -1328,10 +1330,10 @@ TEST_F(DBFlushTest, MemPurgeWALSupport) {
|
||||
// Check that there was no SST files created during flush.
|
||||
const uint32_t EXPECTED_SST_COUNT = 0;
|
||||
|
||||
EXPECT_GE(mempurge_count.exchange(0), EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
EXPECT_GE(mempurge_count, EXPECTED_MIN_MEMPURGE_COUNT);
|
||||
if (options.experimental_mempurge_threshold ==
|
||||
std::numeric_limits<double>::max()) {
|
||||
EXPECT_EQ(sst_count.exchange(0), EXPECTED_SST_COUNT);
|
||||
EXPECT_EQ(sst_count, EXPECTED_SST_COUNT);
|
||||
}
|
||||
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
@@ -1357,7 +1359,7 @@ TEST_F(DBFlushTest, MemPurgeWALSupport) {
|
||||
ASSERT_OK(Put(1, RNDKEY, RNDVALUE));
|
||||
}
|
||||
// ASsert than there was at least one flush to storage.
|
||||
EXPECT_GT(sst_count.exchange(0), EXPECTED_SST_COUNT);
|
||||
EXPECT_GT(sst_count, EXPECTED_SST_COUNT);
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_EQ("v4", Get(1, "foo"));
|
||||
ASSERT_EQ("v2", Get(1, "bar"));
|
||||
@@ -1532,7 +1534,7 @@ TEST_F(DBFlushTest, FireOnFlushCompletedAfterCommittedResult) {
|
||||
std::shared_ptr<TestListener> listener = std::make_shared<TestListener>();
|
||||
|
||||
SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::FlushMemTableToOutputFile:AfterPickMemtables",
|
||||
{{"DBImpl::BackgroundCallFlush:start",
|
||||
"DBFlushTest::FireOnFlushCompletedAfterCommittedResult:WaitFirst"},
|
||||
{"DBImpl::FlushMemTableToOutputFile:Finish",
|
||||
"DBFlushTest::FireOnFlushCompletedAfterCommittedResult:WaitSecond"}});
|
||||
|
||||
+1
-11
@@ -1389,9 +1389,7 @@ Status DBImpl::SyncWAL() {
|
||||
IOStatusCheck(io_s);
|
||||
}
|
||||
if (status.ok() && need_log_dir_sync) {
|
||||
status = directories_.GetWalDir()->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
status = directories_.GetWalDir()->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
TEST_SYNC_POINT("DBWALTest::SyncWALNotWaitWrite:2");
|
||||
|
||||
@@ -4290,14 +4288,6 @@ Status DBImpl::RenameTempFileToOptionsFile(const std::string& file_name) {
|
||||
if (s.ok()) {
|
||||
// Retry if the file name happen to conflict with an existing one.
|
||||
s = GetEnv()->RenameFile(file_name, options_file_name);
|
||||
std::unique_ptr<FSDirectory> dir_obj;
|
||||
if (s.ok()) {
|
||||
s = fs_->NewDirectory(GetName(), IOOptions(), &dir_obj, nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = dir_obj->FsyncWithDirOptions(IOOptions(), nullptr,
|
||||
DirFsyncOptions(options_file_name));
|
||||
}
|
||||
}
|
||||
if (s.ok()) {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
|
||||
@@ -974,9 +974,6 @@ class DBImpl : public DB {
|
||||
// is only for the special test of CancelledCompactions
|
||||
Status TEST_WaitForCompact(bool waitUnscheduled = false);
|
||||
|
||||
// Wait for any background purge
|
||||
Status TEST_WaitForPurge();
|
||||
|
||||
// Get the background error status
|
||||
Status TEST_GetBGError();
|
||||
|
||||
|
||||
@@ -120,9 +120,7 @@ IOStatus DBImpl::SyncClosedLogs(JobContext* job_context) {
|
||||
}
|
||||
}
|
||||
if (io_s.ok()) {
|
||||
io_s = directories_.GetWalDir()->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
io_s = directories_.GetWalDir()->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
|
||||
mutex_.Lock();
|
||||
@@ -534,9 +532,7 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
// Sync on all distinct output directories.
|
||||
for (auto dir : distinct_output_dirs) {
|
||||
if (dir != nullptr) {
|
||||
Status error_status = dir->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
Status error_status = dir->Fsync(IOOptions(), nullptr);
|
||||
if (!error_status.ok()) {
|
||||
s = error_status;
|
||||
break;
|
||||
@@ -1114,8 +1110,6 @@ Status DBImpl::CompactRangeInternal(const CompactRangeOptions& options,
|
||||
assert(temp_s.ok());
|
||||
}
|
||||
EnableManualCompaction();
|
||||
TEST_SYNC_POINT(
|
||||
"DBImpl::CompactRange:PostRefitLevel:ManualCompactionEnabled");
|
||||
}
|
||||
LogFlush(immutable_db_options_.info_log);
|
||||
|
||||
@@ -1749,17 +1743,6 @@ Status DBImpl::RunManualCompaction(
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction:1");
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
|
||||
if (manual_compaction_paused_ > 0) {
|
||||
// Does not make sense to `AddManualCompaction()` in this scenario since
|
||||
// `DisableManualCompaction()` just waited for the manual compaction queue
|
||||
// to drain. So return immediately.
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction:PausedAtStart");
|
||||
manual.status =
|
||||
Status::Incomplete(Status::SubCode::kManualCompactionPaused);
|
||||
manual.done = true;
|
||||
return manual.status;
|
||||
}
|
||||
|
||||
// When a manual compaction arrives, temporarily disable scheduling of
|
||||
// non-manual compactions and wait until the number of scheduled compaction
|
||||
// jobs drops to zero. This used to be needed to ensure that this manual
|
||||
@@ -3080,12 +3063,8 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
status = Status::CompactionTooLarge();
|
||||
} else {
|
||||
// update statistics
|
||||
size_t num_files = 0;
|
||||
for (auto& each_level : *c->inputs()) {
|
||||
num_files += each_level.files.size();
|
||||
}
|
||||
RecordInHistogram(stats_, NUM_FILES_IN_SINGLE_COMPACTION, num_files);
|
||||
|
||||
RecordInHistogram(stats_, NUM_FILES_IN_SINGLE_COMPACTION,
|
||||
c->inputs(0)->size());
|
||||
// There are three things that can change compaction score:
|
||||
// 1) When flush or compaction finish. This case is covered by
|
||||
// InstallSuperVersionAndScheduleWork
|
||||
@@ -3405,7 +3384,6 @@ bool DBImpl::HasPendingManualCompaction() {
|
||||
}
|
||||
|
||||
void DBImpl::AddManualCompaction(DBImpl::ManualCompactionState* m) {
|
||||
assert(manual_compaction_paused_ == 0);
|
||||
manual_compaction_dequeue_.push_back(m);
|
||||
}
|
||||
|
||||
|
||||
@@ -184,14 +184,6 @@ Status DBImpl::TEST_WaitForCompact(bool wait_unscheduled) {
|
||||
return error_handler_.GetBGError();
|
||||
}
|
||||
|
||||
Status DBImpl::TEST_WaitForPurge() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
while (bg_purge_scheduled_ && error_handler_.GetBGError().ok()) {
|
||||
bg_cv_.Wait();
|
||||
}
|
||||
return error_handler_.GetBGError();
|
||||
}
|
||||
|
||||
Status DBImpl::TEST_GetBGError() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
return error_handler_.GetBGError();
|
||||
|
||||
@@ -655,13 +655,7 @@ void DBImpl::DeleteObsoleteFiles() {
|
||||
|
||||
mutex_.Unlock();
|
||||
if (job_context.HaveSomethingToDelete()) {
|
||||
bool defer_purge = immutable_db_options_.avoid_unnecessary_blocking_io;
|
||||
PurgeObsoleteFiles(job_context, defer_purge);
|
||||
if (defer_purge) {
|
||||
mutex_.Lock();
|
||||
SchedulePurge();
|
||||
mutex_.Unlock();
|
||||
}
|
||||
PurgeObsoleteFiles(job_context);
|
||||
}
|
||||
job_context.Clean();
|
||||
mutex_.Lock();
|
||||
|
||||
@@ -1694,6 +1694,10 @@ 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(IOOptions(), nullptr);
|
||||
TEST_SYNC_POINT("DBImpl::Open:AfterDeleteFilesAndSyncDir");
|
||||
}
|
||||
if (s.ok()) {
|
||||
// In WritePrepared there could be gap in sequence numbers. This breaks
|
||||
@@ -1766,8 +1770,6 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
|
||||
*dbptr = impl;
|
||||
impl->opened_successfully_ = true;
|
||||
impl->DeleteObsoleteFiles();
|
||||
TEST_SYNC_POINT("DBImpl::Open:AfterDeleteFiles");
|
||||
impl->MaybeScheduleFlushOrCompaction();
|
||||
} else {
|
||||
persist_options_status.PermitUncheckedError();
|
||||
|
||||
@@ -156,6 +156,11 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
PERF_TIMER_GUARD(write_pre_and_post_process_time);
|
||||
WriteThread::Writer w(write_options, my_batch, callback, log_ref,
|
||||
disable_memtable, batch_cnt, pre_release_callback);
|
||||
|
||||
if (!write_options.disableWAL) {
|
||||
RecordTick(stats_, WRITE_WITH_WAL);
|
||||
}
|
||||
|
||||
StopWatch write_sw(immutable_db_options_.clock, stats_, DB_WRITE);
|
||||
|
||||
write_thread_.JoinBatchGroup(&w);
|
||||
@@ -676,6 +681,7 @@ Status DBImpl::WriteImplWALOnly(
|
||||
PERF_TIMER_GUARD(write_pre_and_post_process_time);
|
||||
WriteThread::Writer w(write_options, my_batch, callback, log_ref,
|
||||
disable_memtable, sub_batch_cnt, pre_release_callback);
|
||||
RecordTick(stats_, WRITE_WITH_WAL);
|
||||
StopWatch write_sw(immutable_db_options_.clock, stats_, DB_WRITE);
|
||||
|
||||
write_thread->JoinBatchGroup(&w);
|
||||
@@ -1142,9 +1148,7 @@ IOStatus 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.
|
||||
io_s = directories_.GetWalDir()->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
io_s = directories_.GetWalDir()->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ void VerifySimilar(uint64_t a, uint64_t b, double bias) {
|
||||
|
||||
void VerifyTableProperties(
|
||||
const TableProperties& base_tp, const TableProperties& new_tp,
|
||||
double filter_size_bias = CACHE_LINE_SIZE >= 256 ? 0.18 : 0.1,
|
||||
double filter_size_bias = CACHE_LINE_SIZE >= 256 ? 0.15 : 0.1,
|
||||
double index_size_bias = 0.1, double data_size_bias = 0.1,
|
||||
double num_data_blocks_bias = 0.05) {
|
||||
VerifySimilar(base_tp.data_size, new_tp.data_size, data_size_bias);
|
||||
@@ -627,8 +627,7 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
|
||||
value_is_delta_encoded);
|
||||
// Gives larger bias here as index block size, filter block size,
|
||||
// and data block size become much harder to estimate in this test.
|
||||
VerifyTableProperties(expected_tp, tp, CACHE_LINE_SIZE >= 256 ? 0.6 : 0.5,
|
||||
0.4, 0.4, 0.25);
|
||||
VerifyTableProperties(expected_tp, tp, 0.5, 0.4, 0.4, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -690,7 +690,7 @@ TEST_F(DBSecondaryTest, SwitchToNewManifestDuringOpen) {
|
||||
SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"ReactiveVersionSet::MaybeSwitchManifest:AfterGetCurrentManifestPath:0",
|
||||
"VersionSet::ProcessManifestWrites:BeforeNewManifest"},
|
||||
{"DBImpl::Open:AfterDeleteFiles",
|
||||
{"DBImpl::Open:AfterDeleteFilesAndSyncDir",
|
||||
"ReactiveVersionSet::MaybeSwitchManifest:AfterGetCurrentManifestPath:"
|
||||
"1"}});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
+6
-2
@@ -475,8 +475,12 @@ Options DBTestBase::GetOptions(
|
||||
case kInfiniteMaxOpenFiles:
|
||||
options.max_open_files = -1;
|
||||
break;
|
||||
case kXXH3Checksum: {
|
||||
table_options.checksum = kXXH3;
|
||||
case kxxHashChecksum: {
|
||||
table_options.checksum = kxxHash;
|
||||
break;
|
||||
}
|
||||
case kxxHash64Checksum: {
|
||||
table_options.checksum = kxxHash64;
|
||||
break;
|
||||
}
|
||||
case kFIFOCompaction: {
|
||||
|
||||
+2
-1
@@ -854,7 +854,7 @@ class DBTestBase : public testing::Test {
|
||||
kUniversalCompactionMultiLevel = 20,
|
||||
kCompressedBlockCache = 21,
|
||||
kInfiniteMaxOpenFiles = 22,
|
||||
kXXH3Checksum = 23,
|
||||
kxxHashChecksum = 23,
|
||||
kFIFOCompaction = 24,
|
||||
kOptimizeFiltersForHits = 25,
|
||||
kRowCache = 26,
|
||||
@@ -869,6 +869,7 @@ class DBTestBase : public testing::Test {
|
||||
kBlockBasedTableWithPartitionedIndexFormat4,
|
||||
kPartitionedFilterWithNewTableReaderForCompactions,
|
||||
kUniversalSubcompactions,
|
||||
kxxHash64Checksum,
|
||||
kUnorderedWrite,
|
||||
// This must be the last line
|
||||
kEnd,
|
||||
|
||||
+6
-49
@@ -117,15 +117,9 @@ class DeleteFileTest : public DBTestBase {
|
||||
manifest_cnt += (type == kDescriptorFile);
|
||||
}
|
||||
}
|
||||
if (required_log >= 0) {
|
||||
ASSERT_EQ(required_log, log_cnt);
|
||||
}
|
||||
if (required_sst >= 0) {
|
||||
ASSERT_EQ(required_sst, sst_cnt);
|
||||
}
|
||||
if (required_manifest >= 0) {
|
||||
ASSERT_EQ(required_manifest, manifest_cnt);
|
||||
}
|
||||
ASSERT_EQ(required_log, log_cnt);
|
||||
ASSERT_EQ(required_sst, sst_cnt);
|
||||
ASSERT_EQ(required_manifest, manifest_cnt);
|
||||
}
|
||||
|
||||
static void DoSleep(void* arg) {
|
||||
@@ -270,41 +264,6 @@ TEST_F(DeleteFileTest, BackgroundPurgeIteratorTest) {
|
||||
CheckFileTypeCounts(dbname_, 0, 1, 1);
|
||||
}
|
||||
|
||||
TEST_F(DeleteFileTest, PurgeDuringOpen) {
|
||||
Options options = CurrentOptions();
|
||||
CheckFileTypeCounts(dbname_, -1, 0, -1);
|
||||
Close();
|
||||
std::unique_ptr<WritableFile> file;
|
||||
ASSERT_OK(options.env->NewWritableFile(dbname_ + "/000002.sst", &file,
|
||||
EnvOptions()));
|
||||
ASSERT_OK(file->Close());
|
||||
CheckFileTypeCounts(dbname_, -1, 1, -1);
|
||||
options.avoid_unnecessary_blocking_io = false;
|
||||
options.create_if_missing = false;
|
||||
Reopen(options);
|
||||
CheckFileTypeCounts(dbname_, -1, 0, -1);
|
||||
Close();
|
||||
|
||||
// test background purge
|
||||
options.avoid_unnecessary_blocking_io = true;
|
||||
options.create_if_missing = false;
|
||||
ASSERT_OK(options.env->NewWritableFile(dbname_ + "/000002.sst", &file,
|
||||
EnvOptions()));
|
||||
ASSERT_OK(file->Close());
|
||||
CheckFileTypeCounts(dbname_, -1, 1, -1);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DeleteFileTest::PurgeDuringOpen:1", "DBImpl::BGWorkPurge:start"}});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
Reopen(options);
|
||||
// the obsolete file is not deleted until the background purge job is ran
|
||||
CheckFileTypeCounts(dbname_, -1, 1, -1);
|
||||
TEST_SYNC_POINT("DeleteFileTest::PurgeDuringOpen:1");
|
||||
ASSERT_OK(dbfull()->TEST_WaitForPurge());
|
||||
CheckFileTypeCounts(dbname_, -1, 0, -1);
|
||||
}
|
||||
|
||||
TEST_F(DeleteFileTest, BackgroundPurgeCFDropTest) {
|
||||
Options options = CurrentOptions();
|
||||
SetOptions(&options);
|
||||
@@ -351,11 +310,6 @@ TEST_F(DeleteFileTest, BackgroundPurgeCFDropTest) {
|
||||
do_test(false);
|
||||
}
|
||||
|
||||
options.avoid_unnecessary_blocking_io = true;
|
||||
options.create_if_missing = false;
|
||||
Reopen(options);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForPurge());
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->LoadDependency(
|
||||
@@ -363,6 +317,9 @@ TEST_F(DeleteFileTest, BackgroundPurgeCFDropTest) {
|
||||
"DBImpl::BGWorkPurge:start"}});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
options.avoid_unnecessary_blocking_io = true;
|
||||
options.create_if_missing = false;
|
||||
Reopen(options);
|
||||
{
|
||||
SCOPED_TRACE("avoid_unnecessary_blocking_io = true");
|
||||
do_test(true);
|
||||
|
||||
@@ -168,9 +168,7 @@ Status ExternalSstFileIngestionJob::Prepare(
|
||||
TEST_SYNC_POINT("ExternalSstFileIngestionJob::BeforeSyncDir");
|
||||
if (status.ok()) {
|
||||
for (auto path_id : ingestion_path_ids) {
|
||||
status = directories_->GetDataDir(path_id)->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
status = directories_->GetDataDir(path_id)->Fsync(IOOptions(), nullptr);
|
||||
if (!status.ok()) {
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
"Failed to sync directory %" ROCKSDB_PRIszt
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "file/filename.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/sst_file_reader.h"
|
||||
@@ -2384,9 +2383,10 @@ TEST_F(ExternalSSTFileTest, IngestFileWrittenWithCompressionDictionary) {
|
||||
|
||||
// Very slow, not worth the cost to run regularly
|
||||
TEST_F(ExternalSSTFileTest, DISABLED_HugeBlockChecksum) {
|
||||
for (auto t : GetSupportedChecksums()) {
|
||||
int max_checksum = static_cast<int>(kxxHash64);
|
||||
for (int i = 0; i <= max_checksum; ++i) {
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.checksum = t;
|
||||
table_options.checksum = static_cast<ChecksumType>(i);
|
||||
Options options = CurrentOptions();
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
|
||||
|
||||
+1
-3
@@ -937,9 +937,7 @@ Status FlushJob::WriteLevel0Table() {
|
||||
meta_.marked_for_compaction ? " (needs compaction)" : "");
|
||||
|
||||
if (s.ok() && output_file_directory_ != nullptr && sync_output_directory_) {
|
||||
s = output_file_directory_->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kNewFileSynced));
|
||||
s = output_file_directory_->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
TEST_SYNC_POINT_CALLBACK("FlushJob::WriteLevel0Table", &mems_);
|
||||
db_mutex_->Lock();
|
||||
|
||||
@@ -1519,11 +1519,9 @@ void InternalStats::DumpCFMapStats(
|
||||
}
|
||||
}
|
||||
// Cumulative summary
|
||||
double w_amp = (0 == curr_ingest)
|
||||
? 0.0
|
||||
: (compaction_stats_sum->bytes_written +
|
||||
compaction_stats_sum->bytes_written_blob) /
|
||||
static_cast<double>(curr_ingest);
|
||||
double w_amp = (compaction_stats_sum->bytes_written +
|
||||
compaction_stats_sum->bytes_written_blob) /
|
||||
static_cast<double>(curr_ingest + 1);
|
||||
// Stats summary across levels
|
||||
std::map<LevelStatType, double> sum_stats;
|
||||
PrepareLevelStats(&sum_stats, total_files, total_files_being_compacted,
|
||||
|
||||
@@ -377,7 +377,6 @@ TEST_F(EventListenerTest, MultiCF) {
|
||||
ASSERT_OK(Put(7, "popovich", std::string(90000, 'p')));
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
ASSERT_OK(Flush(i));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
ASSERT_EQ(listener->flushed_dbs_.size(), i);
|
||||
ASSERT_EQ(listener->flushed_column_family_names_.size(), i);
|
||||
}
|
||||
@@ -772,7 +771,6 @@ class TableFileCreationListener : public EventListener {
|
||||
} else {
|
||||
if (idx >= 0) {
|
||||
failure_[idx]++;
|
||||
last_failure_ = info.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -780,7 +778,6 @@ class TableFileCreationListener : public EventListener {
|
||||
int started_[2];
|
||||
int finished_[2];
|
||||
int failure_[2];
|
||||
Status last_failure_;
|
||||
};
|
||||
|
||||
TEST_F(EventListenerTest, TableFileCreationListenersTest) {
|
||||
@@ -803,7 +800,6 @@ TEST_F(EventListenerTest, TableFileCreationListenersTest) {
|
||||
test_env->SetStatus(Status::NotSupported("not supported"));
|
||||
ASSERT_NOK(Flush());
|
||||
listener->CheckAndResetCounters(1, 1, 1, 0, 0, 0);
|
||||
ASSERT_TRUE(listener->last_failure_.IsNotSupported());
|
||||
test_env->SetStatus(Status::OK());
|
||||
|
||||
Reopen(options);
|
||||
@@ -820,14 +816,6 @@ TEST_F(EventListenerTest, TableFileCreationListenersTest) {
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
listener->CheckAndResetCounters(0, 0, 0, 1, 1, 0);
|
||||
|
||||
// Verify that an empty table file that is immediately deleted gives Aborted
|
||||
// status to listener.
|
||||
ASSERT_OK(Put("baz", "z"));
|
||||
ASSERT_OK(SingleDelete("baz"));
|
||||
ASSERT_OK(Flush());
|
||||
listener->CheckAndResetCounters(1, 1, 1, 0, 0, 0);
|
||||
ASSERT_TRUE(listener->last_failure_.IsAborted());
|
||||
|
||||
ASSERT_OK(Put("foo", "aaa3"));
|
||||
ASSERT_OK(Put("bar", "bbb3"));
|
||||
ASSERT_OK(Flush());
|
||||
@@ -836,7 +824,6 @@ TEST_F(EventListenerTest, TableFileCreationListenersTest) {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), &kRangeStart, &kRangeEnd));
|
||||
ASSERT_NOK(dbfull()->TEST_WaitForCompact());
|
||||
listener->CheckAndResetCounters(1, 1, 0, 1, 1, 1);
|
||||
ASSERT_TRUE(listener->last_failure_.IsNotSupported());
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
+291
-413
@@ -34,62 +34,68 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
bool NewestFirstBySeqNo(FileMetaData* a, FileMetaData* b) {
|
||||
if (a->fd.largest_seqno != b->fd.largest_seqno) {
|
||||
return a->fd.largest_seqno > b->fd.largest_seqno;
|
||||
}
|
||||
if (a->fd.smallest_seqno != b->fd.smallest_seqno) {
|
||||
return a->fd.smallest_seqno > b->fd.smallest_seqno;
|
||||
}
|
||||
// Break ties by file number
|
||||
return a->fd.GetNumber() > b->fd.GetNumber();
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool BySmallestKey(FileMetaData* a, FileMetaData* b,
|
||||
const InternalKeyComparator* cmp) {
|
||||
int r = cmp->Compare(a->smallest, b->smallest);
|
||||
if (r != 0) {
|
||||
return (r < 0);
|
||||
}
|
||||
// Break ties by file number
|
||||
return (a->fd.GetNumber() < b->fd.GetNumber());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class VersionBuilder::Rep {
|
||||
class NewestFirstBySeqNo {
|
||||
public:
|
||||
bool operator()(const FileMetaData* lhs, const FileMetaData* rhs) const {
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
private:
|
||||
// Helper to sort files_ in v
|
||||
// kLevel0 -- NewestFirstBySeqNo
|
||||
// kLevelNon0 -- BySmallestKey
|
||||
struct FileComparator {
|
||||
enum SortMethod { kLevel0 = 0, kLevelNon0 = 1, } sort_method;
|
||||
const InternalKeyComparator* internal_comparator;
|
||||
|
||||
if (lhs->fd.largest_seqno != rhs->fd.largest_seqno) {
|
||||
return lhs->fd.largest_seqno > rhs->fd.largest_seqno;
|
||||
FileComparator() : internal_comparator(nullptr) {}
|
||||
|
||||
bool operator()(FileMetaData* f1, FileMetaData* f2) const {
|
||||
switch (sort_method) {
|
||||
case kLevel0:
|
||||
return NewestFirstBySeqNo(f1, f2);
|
||||
case kLevelNon0:
|
||||
return BySmallestKey(f1, f2, internal_comparator);
|
||||
}
|
||||
|
||||
if (lhs->fd.smallest_seqno != rhs->fd.smallest_seqno) {
|
||||
return lhs->fd.smallest_seqno > rhs->fd.smallest_seqno;
|
||||
}
|
||||
|
||||
// Break ties by file number
|
||||
return lhs->fd.GetNumber() > rhs->fd.GetNumber();
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class BySmallestKey {
|
||||
public:
|
||||
explicit BySmallestKey(const InternalKeyComparator* cmp) : cmp_(cmp) {}
|
||||
|
||||
bool operator()(const FileMetaData* lhs, const FileMetaData* rhs) const {
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
assert(cmp_);
|
||||
|
||||
const int r = cmp_->Compare(lhs->smallest, rhs->smallest);
|
||||
if (r != 0) {
|
||||
return (r < 0);
|
||||
}
|
||||
|
||||
// Break ties by file number
|
||||
return (lhs->fd.GetNumber() < rhs->fd.GetNumber());
|
||||
}
|
||||
|
||||
private:
|
||||
const InternalKeyComparator* cmp_;
|
||||
};
|
||||
|
||||
struct LevelState {
|
||||
std::unordered_set<uint64_t> deleted_files;
|
||||
// Map from file number to file meta data.
|
||||
std::unordered_map<uint64_t, FileMetaData*> added_files;
|
||||
};
|
||||
|
||||
// A class that represents the accumulated changes (like additional garbage or
|
||||
// newly linked/unlinked SST files) for a given blob file after applying a
|
||||
// series of VersionEdits.
|
||||
class BlobFileMetaDataDelta {
|
||||
public:
|
||||
bool IsEmpty() const {
|
||||
return !additional_garbage_count_ && !additional_garbage_bytes_ &&
|
||||
newly_linked_ssts_.empty() && newly_unlinked_ssts_.empty();
|
||||
return !shared_meta_ && !additional_garbage_count_ &&
|
||||
!additional_garbage_bytes_ && newly_linked_ssts_.empty() &&
|
||||
newly_unlinked_ssts_.empty();
|
||||
}
|
||||
|
||||
std::shared_ptr<SharedBlobFileMetaData> GetSharedMeta() const {
|
||||
return shared_meta_;
|
||||
}
|
||||
|
||||
uint64_t GetAdditionalGarbageCount() const {
|
||||
@@ -108,6 +114,13 @@ class VersionBuilder::Rep {
|
||||
return newly_unlinked_ssts_;
|
||||
}
|
||||
|
||||
void SetSharedMeta(std::shared_ptr<SharedBlobFileMetaData> shared_meta) {
|
||||
assert(!shared_meta_);
|
||||
assert(shared_meta);
|
||||
|
||||
shared_meta_ = std::move(shared_meta);
|
||||
}
|
||||
|
||||
void AddGarbage(uint64_t count, uint64_t bytes) {
|
||||
additional_garbage_count_ += count;
|
||||
additional_garbage_bytes_ += bytes;
|
||||
@@ -146,86 +159,13 @@ class VersionBuilder::Rep {
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SharedBlobFileMetaData> shared_meta_;
|
||||
uint64_t additional_garbage_count_ = 0;
|
||||
uint64_t additional_garbage_bytes_ = 0;
|
||||
std::unordered_set<uint64_t> newly_linked_ssts_;
|
||||
std::unordered_set<uint64_t> newly_unlinked_ssts_;
|
||||
};
|
||||
|
||||
// A class that represents the state of a blob file after applying a series of
|
||||
// VersionEdits. In addition to the resulting state, it also contains the
|
||||
// delta (see BlobFileMetaDataDelta above). The resulting state can be used to
|
||||
// identify obsolete blob files, while the delta makes it possible to
|
||||
// efficiently detect trivial moves.
|
||||
class MutableBlobFileMetaData {
|
||||
public:
|
||||
// To be used for brand new blob files
|
||||
explicit MutableBlobFileMetaData(
|
||||
std::shared_ptr<SharedBlobFileMetaData>&& shared_meta)
|
||||
: shared_meta_(std::move(shared_meta)) {}
|
||||
|
||||
// To be used for pre-existing blob files
|
||||
explicit MutableBlobFileMetaData(
|
||||
const std::shared_ptr<BlobFileMetaData>& meta)
|
||||
: shared_meta_(meta->GetSharedMeta()),
|
||||
linked_ssts_(meta->GetLinkedSsts()),
|
||||
garbage_blob_count_(meta->GetGarbageBlobCount()),
|
||||
garbage_blob_bytes_(meta->GetGarbageBlobBytes()) {}
|
||||
|
||||
const std::shared_ptr<SharedBlobFileMetaData>& GetSharedMeta() const {
|
||||
return shared_meta_;
|
||||
}
|
||||
|
||||
bool HasDelta() const { return !delta_.IsEmpty(); }
|
||||
|
||||
const std::unordered_set<uint64_t>& GetLinkedSsts() const {
|
||||
return linked_ssts_;
|
||||
}
|
||||
|
||||
uint64_t GetGarbageBlobCount() const { return garbage_blob_count_; }
|
||||
|
||||
uint64_t GetGarbageBlobBytes() const { return garbage_blob_bytes_; }
|
||||
|
||||
bool AddGarbage(uint64_t count, uint64_t bytes) {
|
||||
assert(shared_meta_);
|
||||
|
||||
if (garbage_blob_count_ + count > shared_meta_->GetTotalBlobCount() ||
|
||||
garbage_blob_bytes_ + bytes > shared_meta_->GetTotalBlobBytes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delta_.AddGarbage(count, bytes);
|
||||
|
||||
garbage_blob_count_ += count;
|
||||
garbage_blob_bytes_ += bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LinkSst(uint64_t sst_file_number) {
|
||||
delta_.LinkSst(sst_file_number);
|
||||
|
||||
assert(linked_ssts_.find(sst_file_number) == linked_ssts_.end());
|
||||
linked_ssts_.emplace(sst_file_number);
|
||||
}
|
||||
|
||||
void UnlinkSst(uint64_t sst_file_number) {
|
||||
delta_.UnlinkSst(sst_file_number);
|
||||
|
||||
assert(linked_ssts_.find(sst_file_number) != linked_ssts_.end());
|
||||
linked_ssts_.erase(sst_file_number);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SharedBlobFileMetaData> shared_meta_;
|
||||
// Accumulated changes
|
||||
BlobFileMetaDataDelta delta_;
|
||||
// Resulting state after applying the changes
|
||||
BlobFileMetaData::LinkedSsts linked_ssts_;
|
||||
uint64_t garbage_blob_count_ = 0;
|
||||
uint64_t garbage_blob_bytes_ = 0;
|
||||
};
|
||||
|
||||
const FileOptions& file_options_;
|
||||
const ImmutableCFOptions* const ioptions_;
|
||||
TableCache* table_cache_;
|
||||
@@ -243,12 +183,11 @@ class VersionBuilder::Rep {
|
||||
bool has_invalid_levels_;
|
||||
// Current levels of table files affected by additions/deletions.
|
||||
std::unordered_map<uint64_t, int> table_file_levels_;
|
||||
NewestFirstBySeqNo level_zero_cmp_;
|
||||
BySmallestKey level_nonzero_cmp_;
|
||||
FileComparator level_zero_cmp_;
|
||||
FileComparator level_nonzero_cmp_;
|
||||
|
||||
// Mutable metadata objects for all blob files affected by the series of
|
||||
// version edits.
|
||||
std::map<uint64_t, MutableBlobFileMetaData> mutable_blob_file_metas_;
|
||||
// Metadata delta for all blob files affected by the series of version edits.
|
||||
std::map<uint64_t, BlobFileMetaDataDelta> blob_file_meta_deltas_;
|
||||
|
||||
public:
|
||||
Rep(const FileOptions& file_options, const ImmutableCFOptions* ioptions,
|
||||
@@ -260,11 +199,14 @@ class VersionBuilder::Rep {
|
||||
base_vstorage_(base_vstorage),
|
||||
version_set_(version_set),
|
||||
num_levels_(base_vstorage->num_levels()),
|
||||
has_invalid_levels_(false),
|
||||
level_nonzero_cmp_(base_vstorage_->InternalComparator()) {
|
||||
has_invalid_levels_(false) {
|
||||
assert(ioptions_);
|
||||
|
||||
levels_ = new LevelState[num_levels_];
|
||||
level_zero_cmp_.sort_method = FileComparator::kLevel0;
|
||||
level_nonzero_cmp_.sort_method = FileComparator::kLevelNon0;
|
||||
level_nonzero_cmp_.internal_comparator =
|
||||
base_vstorage_->InternalComparator();
|
||||
}
|
||||
|
||||
~Rep() {
|
||||
@@ -290,10 +232,29 @@ class VersionBuilder::Rep {
|
||||
}
|
||||
}
|
||||
|
||||
// Mapping used for checking the consistency of links between SST files and
|
||||
// blob files. It is built using the forward links (table file -> blob file),
|
||||
// and is subsequently compared with the inverse mapping stored in the
|
||||
// BlobFileMetaData objects.
|
||||
bool IsBlobFileInVersion(uint64_t blob_file_number) const {
|
||||
auto delta_it = blob_file_meta_deltas_.find(blob_file_number);
|
||||
if (delta_it != blob_file_meta_deltas_.end()) {
|
||||
if (delta_it->second.GetSharedMeta()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
assert(base_vstorage_);
|
||||
|
||||
const auto& base_blob_files = base_vstorage_->GetBlobFiles();
|
||||
|
||||
auto base_it = base_blob_files.find(blob_file_number);
|
||||
if (base_it != base_blob_files.end()) {
|
||||
assert(base_it->second);
|
||||
assert(base_it->second->GetSharedMeta());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
using ExpectedLinkedSsts =
|
||||
std::unordered_map<uint64_t, BlobFileMetaData::LinkedSsts>;
|
||||
|
||||
@@ -309,155 +270,91 @@ class VersionBuilder::Rep {
|
||||
(*expected_linked_ssts)[blob_file_number].emplace(table_file_number);
|
||||
}
|
||||
|
||||
template <class Checker>
|
||||
Status CheckConsistencyDetailsForLevel(
|
||||
const VersionStorageInfo* vstorage, int level, Checker checker,
|
||||
const std::string& sync_point,
|
||||
ExpectedLinkedSsts* expected_linked_ssts) const {
|
||||
#ifdef NDEBUG
|
||||
(void)sync_point;
|
||||
#endif
|
||||
|
||||
assert(vstorage);
|
||||
assert(level >= 0 && level < num_levels_);
|
||||
assert(expected_linked_ssts);
|
||||
|
||||
const auto& level_files = vstorage->LevelFiles(level);
|
||||
|
||||
if (level_files.empty()) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
assert(level_files[0]);
|
||||
UpdateExpectedLinkedSsts(level_files[0]->fd.GetNumber(),
|
||||
level_files[0]->oldest_blob_file_number,
|
||||
expected_linked_ssts);
|
||||
|
||||
for (size_t i = 1; i < level_files.size(); ++i) {
|
||||
assert(level_files[i]);
|
||||
UpdateExpectedLinkedSsts(level_files[i]->fd.GetNumber(),
|
||||
level_files[i]->oldest_blob_file_number,
|
||||
expected_linked_ssts);
|
||||
|
||||
auto lhs = level_files[i - 1];
|
||||
auto rhs = level_files[i];
|
||||
|
||||
#ifndef NDEBUG
|
||||
auto pair = std::make_pair(&lhs, &rhs);
|
||||
TEST_SYNC_POINT_CALLBACK(sync_point, &pair);
|
||||
#endif
|
||||
|
||||
const Status s = checker(lhs, rhs);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
// Make sure table files are sorted correctly and that the links between
|
||||
// table files and blob files are consistent.
|
||||
Status CheckConsistencyDetails(const VersionStorageInfo* vstorage) const {
|
||||
assert(vstorage);
|
||||
|
||||
Status CheckConsistencyDetails(VersionStorageInfo* vstorage) {
|
||||
// Make sure the files are sorted correctly and that the links between
|
||||
// table files and blob files are consistent. The latter is checked using
|
||||
// the following mapping, which is built using the forward links
|
||||
// (table file -> blob file), and is subsequently compared with the inverse
|
||||
// mapping stored in the BlobFileMetaData objects.
|
||||
ExpectedLinkedSsts expected_linked_ssts;
|
||||
|
||||
if (num_levels_ > 0) {
|
||||
// Check L0
|
||||
{
|
||||
auto l0_checker = [this](const FileMetaData* lhs,
|
||||
const FileMetaData* rhs) {
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
for (int level = 0; level < num_levels_; level++) {
|
||||
auto& level_files = vstorage->LevelFiles(level);
|
||||
|
||||
if (!level_zero_cmp_(lhs, rhs)) {
|
||||
std::ostringstream oss;
|
||||
oss << "L0 files are not sorted properly: files #"
|
||||
<< lhs->fd.GetNumber() << ", #" << rhs->fd.GetNumber();
|
||||
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
}
|
||||
|
||||
if (rhs->fd.smallest_seqno == rhs->fd.largest_seqno) {
|
||||
// This is an external file that we ingested
|
||||
const SequenceNumber external_file_seqno = rhs->fd.smallest_seqno;
|
||||
|
||||
if (!(external_file_seqno < lhs->fd.largest_seqno ||
|
||||
external_file_seqno == 0)) {
|
||||
std::ostringstream oss;
|
||||
oss << "L0 file #" << lhs->fd.GetNumber() << " with seqno "
|
||||
<< lhs->fd.smallest_seqno << ' ' << lhs->fd.largest_seqno
|
||||
<< " vs. file #" << rhs->fd.GetNumber()
|
||||
<< " with global_seqno " << external_file_seqno;
|
||||
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
}
|
||||
} else if (lhs->fd.smallest_seqno <= rhs->fd.smallest_seqno) {
|
||||
std::ostringstream oss;
|
||||
oss << "L0 file #" << lhs->fd.GetNumber() << " with seqno "
|
||||
<< lhs->fd.smallest_seqno << ' ' << lhs->fd.largest_seqno
|
||||
<< " vs. file #" << rhs->fd.GetNumber() << " with seqno "
|
||||
<< rhs->fd.smallest_seqno << ' ' << rhs->fd.largest_seqno;
|
||||
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
};
|
||||
|
||||
const Status s = CheckConsistencyDetailsForLevel(
|
||||
vstorage, /* level */ 0, l0_checker,
|
||||
"VersionBuilder::CheckConsistency0", &expected_linked_ssts);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
if (level_files.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check L1 and up
|
||||
const InternalKeyComparator* const icmp = vstorage->InternalComparator();
|
||||
assert(icmp);
|
||||
assert(level_files[0]);
|
||||
UpdateExpectedLinkedSsts(level_files[0]->fd.GetNumber(),
|
||||
level_files[0]->oldest_blob_file_number,
|
||||
&expected_linked_ssts);
|
||||
for (size_t i = 1; i < level_files.size(); i++) {
|
||||
assert(level_files[i]);
|
||||
UpdateExpectedLinkedSsts(level_files[i]->fd.GetNumber(),
|
||||
level_files[i]->oldest_blob_file_number,
|
||||
&expected_linked_ssts);
|
||||
|
||||
for (int level = 1; level < num_levels_; ++level) {
|
||||
auto checker = [this, level, icmp](const FileMetaData* lhs,
|
||||
const FileMetaData* rhs) {
|
||||
assert(lhs);
|
||||
assert(rhs);
|
||||
|
||||
if (!level_nonzero_cmp_(lhs, rhs)) {
|
||||
std::ostringstream oss;
|
||||
oss << 'L' << level << " files are not sorted properly: files #"
|
||||
<< lhs->fd.GetNumber() << ", #" << rhs->fd.GetNumber();
|
||||
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
auto f1 = level_files[i - 1];
|
||||
auto f2 = level_files[i];
|
||||
if (level == 0) {
|
||||
#ifndef NDEBUG
|
||||
auto pair = std::make_pair(&f1, &f2);
|
||||
TEST_SYNC_POINT_CALLBACK("VersionBuilder::CheckConsistency0", &pair);
|
||||
#endif
|
||||
if (!level_zero_cmp_(f1, f2)) {
|
||||
return Status::Corruption("L0 files are not sorted properly");
|
||||
}
|
||||
|
||||
// Make sure there is no overlap in level
|
||||
if (icmp->Compare(lhs->largest, rhs->smallest) >= 0) {
|
||||
std::ostringstream oss;
|
||||
oss << 'L' << level << " has overlapping ranges: file #"
|
||||
<< lhs->fd.GetNumber()
|
||||
<< " largest key: " << lhs->largest.DebugString(true)
|
||||
<< " vs. file #" << rhs->fd.GetNumber()
|
||||
<< " smallest key: " << rhs->smallest.DebugString(true);
|
||||
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
if (f2->fd.smallest_seqno == f2->fd.largest_seqno) {
|
||||
// This is an external file that we ingested
|
||||
SequenceNumber external_file_seqno = f2->fd.smallest_seqno;
|
||||
if (!(external_file_seqno < f1->fd.largest_seqno ||
|
||||
external_file_seqno == 0)) {
|
||||
return Status::Corruption(
|
||||
"L0 file with seqno " + ToString(f1->fd.smallest_seqno) +
|
||||
" " + ToString(f1->fd.largest_seqno) +
|
||||
" vs. file with global_seqno" +
|
||||
ToString(external_file_seqno) + " with fileNumber " +
|
||||
ToString(f1->fd.GetNumber()));
|
||||
}
|
||||
} else if (f1->fd.smallest_seqno <= f2->fd.smallest_seqno) {
|
||||
return Status::Corruption("L0 files seqno " +
|
||||
ToString(f1->fd.smallest_seqno) + " " +
|
||||
ToString(f1->fd.largest_seqno) + " " +
|
||||
ToString(f1->fd.GetNumber()) + " vs. " +
|
||||
ToString(f2->fd.smallest_seqno) + " " +
|
||||
ToString(f2->fd.largest_seqno) + " " +
|
||||
ToString(f2->fd.GetNumber()));
|
||||
}
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
auto pair = std::make_pair(&f1, &f2);
|
||||
TEST_SYNC_POINT_CALLBACK("VersionBuilder::CheckConsistency1", &pair);
|
||||
#endif
|
||||
if (!level_nonzero_cmp_(f1, f2)) {
|
||||
return Status::Corruption(
|
||||
"L" + ToString(level) +
|
||||
" files are not sorted properly: files #" +
|
||||
ToString(f1->fd.GetNumber()) + ", #" +
|
||||
ToString(f2->fd.GetNumber()));
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
};
|
||||
|
||||
const Status s = CheckConsistencyDetailsForLevel(
|
||||
vstorage, level, checker, "VersionBuilder::CheckConsistency1",
|
||||
&expected_linked_ssts);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
// Make sure there is no overlap in levels > 0
|
||||
if (vstorage->InternalComparator()->Compare(f1->largest,
|
||||
f2->smallest) >= 0) {
|
||||
return Status::Corruption(
|
||||
"L" + ToString(level) + " have overlapping ranges: file #" +
|
||||
ToString(f1->fd.GetNumber()) +
|
||||
" largest key: " + (f1->largest).DebugString(true) +
|
||||
" vs. file #" + ToString(f2->fd.GetNumber()) +
|
||||
" smallest key: " + (f2->smallest).DebugString(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that all blob files in the version have non-garbage data and
|
||||
// the links between them and the table files are consistent.
|
||||
// Make sure that all blob files in the version have non-garbage data.
|
||||
const auto& blob_files = vstorage->GetBlobFiles();
|
||||
for (const auto& pair : blob_files) {
|
||||
const uint64_t blob_file_number = pair.first;
|
||||
@@ -489,9 +386,7 @@ class VersionBuilder::Rep {
|
||||
return ret_s;
|
||||
}
|
||||
|
||||
Status CheckConsistency(const VersionStorageInfo* vstorage) const {
|
||||
assert(vstorage);
|
||||
|
||||
Status CheckConsistency(VersionStorageInfo* vstorage) {
|
||||
// Always run consistency checks in debug build
|
||||
#ifdef NDEBUG
|
||||
if (!vstorage->force_consistency_checks()) {
|
||||
@@ -531,49 +426,6 @@ class VersionBuilder::Rep {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsBlobFileInVersion(uint64_t blob_file_number) const {
|
||||
auto mutable_it = mutable_blob_file_metas_.find(blob_file_number);
|
||||
if (mutable_it != mutable_blob_file_metas_.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(base_vstorage_);
|
||||
|
||||
const auto& base_blob_files = base_vstorage_->GetBlobFiles();
|
||||
|
||||
auto base_it = base_blob_files.find(blob_file_number);
|
||||
if (base_it != base_blob_files.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
MutableBlobFileMetaData* GetOrCreateMutableBlobFileMetaData(
|
||||
uint64_t blob_file_number) {
|
||||
auto mutable_it = mutable_blob_file_metas_.find(blob_file_number);
|
||||
if (mutable_it != mutable_blob_file_metas_.end()) {
|
||||
return &mutable_it->second;
|
||||
}
|
||||
|
||||
assert(base_vstorage_);
|
||||
|
||||
const auto& base_blob_files = base_vstorage_->GetBlobFiles();
|
||||
|
||||
auto base_it = base_blob_files.find(blob_file_number);
|
||||
if (base_it != base_blob_files.end()) {
|
||||
assert(base_it->second);
|
||||
|
||||
mutable_it = mutable_blob_file_metas_
|
||||
.emplace(blob_file_number,
|
||||
MutableBlobFileMetaData(base_it->second))
|
||||
.first;
|
||||
return &mutable_it->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Status ApplyBlobFileAddition(const BlobFileAddition& blob_file_addition) {
|
||||
const uint64_t blob_file_number = blob_file_addition.GetBlobFileNumber();
|
||||
|
||||
@@ -608,8 +460,8 @@ class VersionBuilder::Rep {
|
||||
blob_file_addition.GetChecksumMethod(),
|
||||
blob_file_addition.GetChecksumValue(), deleter);
|
||||
|
||||
mutable_blob_file_metas_.emplace(
|
||||
blob_file_number, MutableBlobFileMetaData(std::move(shared_meta)));
|
||||
blob_file_meta_deltas_[blob_file_number].SetSharedMeta(
|
||||
std::move(shared_meta));
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
@@ -617,22 +469,16 @@ class VersionBuilder::Rep {
|
||||
Status ApplyBlobFileGarbage(const BlobFileGarbage& blob_file_garbage) {
|
||||
const uint64_t blob_file_number = blob_file_garbage.GetBlobFileNumber();
|
||||
|
||||
MutableBlobFileMetaData* const mutable_meta =
|
||||
GetOrCreateMutableBlobFileMetaData(blob_file_number);
|
||||
|
||||
if (!mutable_meta) {
|
||||
if (!IsBlobFileInVersion(blob_file_number)) {
|
||||
std::ostringstream oss;
|
||||
oss << "Blob file #" << blob_file_number << " not found";
|
||||
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
}
|
||||
|
||||
if (!mutable_meta->AddGarbage(blob_file_garbage.GetGarbageBlobCount(),
|
||||
blob_file_garbage.GetGarbageBlobBytes())) {
|
||||
std::ostringstream oss;
|
||||
oss << "Garbage overflow for blob file #" << blob_file_number;
|
||||
return Status::Corruption("VersionBuilder", oss.str());
|
||||
}
|
||||
blob_file_meta_deltas_[blob_file_number].AddGarbage(
|
||||
blob_file_garbage.GetGarbageBlobCount(),
|
||||
blob_file_garbage.GetGarbageBlobBytes());
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
@@ -727,12 +573,9 @@ class VersionBuilder::Rep {
|
||||
const uint64_t blob_file_number =
|
||||
GetOldestBlobFileNumberForTableFile(level, file_number);
|
||||
|
||||
if (blob_file_number != kInvalidBlobFileNumber) {
|
||||
MutableBlobFileMetaData* const mutable_meta =
|
||||
GetOrCreateMutableBlobFileMetaData(blob_file_number);
|
||||
if (mutable_meta) {
|
||||
mutable_meta->UnlinkSst(file_number);
|
||||
}
|
||||
if (blob_file_number != kInvalidBlobFileNumber &&
|
||||
IsBlobFileInVersion(blob_file_number)) {
|
||||
blob_file_meta_deltas_[blob_file_number].UnlinkSst(file_number);
|
||||
}
|
||||
|
||||
auto& level_state = levels_[level];
|
||||
@@ -797,12 +640,9 @@ class VersionBuilder::Rep {
|
||||
|
||||
const uint64_t blob_file_number = f->oldest_blob_file_number;
|
||||
|
||||
if (blob_file_number != kInvalidBlobFileNumber) {
|
||||
MutableBlobFileMetaData* const mutable_meta =
|
||||
GetOrCreateMutableBlobFileMetaData(blob_file_number);
|
||||
if (mutable_meta) {
|
||||
mutable_meta->LinkSst(file_number);
|
||||
}
|
||||
if (blob_file_number != kInvalidBlobFileNumber &&
|
||||
IsBlobFileInVersion(blob_file_number)) {
|
||||
blob_file_meta_deltas_[blob_file_number].LinkSst(file_number);
|
||||
}
|
||||
|
||||
table_file_levels_[file_number] = level;
|
||||
@@ -811,7 +651,7 @@ class VersionBuilder::Rep {
|
||||
}
|
||||
|
||||
// Apply all of the edits in *edit to the current state.
|
||||
Status Apply(const VersionEdit* edit) {
|
||||
Status Apply(VersionEdit* edit) {
|
||||
{
|
||||
const Status s = CheckConsistency(base_vstorage_);
|
||||
if (!s.ok()) {
|
||||
@@ -864,11 +704,65 @@ class VersionBuilder::Rep {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static std::shared_ptr<BlobFileMetaData> CreateBlobFileMetaData(
|
||||
const MutableBlobFileMetaData& mutable_meta) {
|
||||
return BlobFileMetaData::Create(
|
||||
mutable_meta.GetSharedMeta(), mutable_meta.GetLinkedSsts(),
|
||||
mutable_meta.GetGarbageBlobCount(), mutable_meta.GetGarbageBlobBytes());
|
||||
static BlobFileMetaData::LinkedSsts ApplyLinkedSstChanges(
|
||||
const BlobFileMetaData::LinkedSsts& base,
|
||||
const std::unordered_set<uint64_t>& newly_linked,
|
||||
const std::unordered_set<uint64_t>& newly_unlinked) {
|
||||
BlobFileMetaData::LinkedSsts result(base);
|
||||
|
||||
for (uint64_t sst_file_number : newly_unlinked) {
|
||||
assert(result.find(sst_file_number) != result.end());
|
||||
|
||||
result.erase(sst_file_number);
|
||||
}
|
||||
|
||||
for (uint64_t sst_file_number : newly_linked) {
|
||||
assert(result.find(sst_file_number) == result.end());
|
||||
|
||||
result.emplace(sst_file_number);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::shared_ptr<BlobFileMetaData> CreateMetaDataForNewBlobFile(
|
||||
const BlobFileMetaDataDelta& delta) {
|
||||
auto shared_meta = delta.GetSharedMeta();
|
||||
assert(shared_meta);
|
||||
|
||||
assert(delta.GetNewlyUnlinkedSsts().empty());
|
||||
|
||||
auto meta = BlobFileMetaData::Create(
|
||||
std::move(shared_meta), delta.GetNewlyLinkedSsts(),
|
||||
delta.GetAdditionalGarbageCount(), delta.GetAdditionalGarbageBytes());
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
static std::shared_ptr<BlobFileMetaData>
|
||||
GetOrCreateMetaDataForExistingBlobFile(
|
||||
const std::shared_ptr<BlobFileMetaData>& base_meta,
|
||||
const BlobFileMetaDataDelta& delta) {
|
||||
assert(base_meta);
|
||||
assert(!delta.GetSharedMeta());
|
||||
|
||||
if (delta.IsEmpty()) {
|
||||
return base_meta;
|
||||
}
|
||||
|
||||
auto shared_meta = base_meta->GetSharedMeta();
|
||||
assert(shared_meta);
|
||||
|
||||
auto linked_ssts = ApplyLinkedSstChanges(base_meta->GetLinkedSsts(),
|
||||
delta.GetNewlyLinkedSsts(),
|
||||
delta.GetNewlyUnlinkedSsts());
|
||||
|
||||
auto meta = BlobFileMetaData::Create(
|
||||
std::move(shared_meta), std::move(linked_ssts),
|
||||
base_meta->GetGarbageBlobCount() + delta.GetAdditionalGarbageCount(),
|
||||
base_meta->GetGarbageBlobBytes() + delta.GetAdditionalGarbageBytes());
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
// Add the blob file specified by meta to *vstorage if it is determined to
|
||||
@@ -905,52 +799,39 @@ class VersionBuilder::Rep {
|
||||
auto base_it = base_blob_files.begin();
|
||||
const auto base_it_end = base_blob_files.end();
|
||||
|
||||
auto mutable_it = mutable_blob_file_metas_.begin();
|
||||
const auto mutable_it_end = mutable_blob_file_metas_.end();
|
||||
auto delta_it = blob_file_meta_deltas_.begin();
|
||||
const auto delta_it_end = blob_file_meta_deltas_.end();
|
||||
|
||||
while (base_it != base_it_end && mutable_it != mutable_it_end) {
|
||||
while (base_it != base_it_end && delta_it != delta_it_end) {
|
||||
const uint64_t base_blob_file_number = base_it->first;
|
||||
const uint64_t mutable_blob_file_number = mutable_it->first;
|
||||
const uint64_t delta_blob_file_number = delta_it->first;
|
||||
|
||||
if (base_blob_file_number < mutable_blob_file_number) {
|
||||
if (base_blob_file_number < delta_blob_file_number) {
|
||||
const auto& base_meta = base_it->second;
|
||||
|
||||
AddBlobFileIfNeeded(vstorage, base_meta, &found_first_non_empty);
|
||||
|
||||
++base_it;
|
||||
} else if (mutable_blob_file_number < base_blob_file_number) {
|
||||
const auto& mutable_meta = mutable_it->second;
|
||||
} else if (delta_blob_file_number < base_blob_file_number) {
|
||||
const auto& delta = delta_it->second;
|
||||
|
||||
auto meta = CreateBlobFileMetaData(mutable_meta);
|
||||
auto meta = CreateMetaDataForNewBlobFile(delta);
|
||||
|
||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
||||
|
||||
++mutable_it;
|
||||
++delta_it;
|
||||
} else {
|
||||
assert(base_blob_file_number == mutable_blob_file_number);
|
||||
assert(base_blob_file_number == delta_blob_file_number);
|
||||
|
||||
const auto& base_meta = base_it->second;
|
||||
const auto& mutable_meta = mutable_it->second;
|
||||
const auto& delta = delta_it->second;
|
||||
|
||||
assert(base_meta);
|
||||
assert(base_meta->GetSharedMeta() == mutable_meta.GetSharedMeta());
|
||||
auto meta = GetOrCreateMetaDataForExistingBlobFile(base_meta, delta);
|
||||
|
||||
if (!mutable_meta.HasDelta()) {
|
||||
assert(base_meta->GetGarbageBlobCount() ==
|
||||
mutable_meta.GetGarbageBlobCount());
|
||||
assert(base_meta->GetGarbageBlobBytes() ==
|
||||
mutable_meta.GetGarbageBlobBytes());
|
||||
assert(base_meta->GetLinkedSsts() == mutable_meta.GetLinkedSsts());
|
||||
|
||||
AddBlobFileIfNeeded(vstorage, base_meta, &found_first_non_empty);
|
||||
} else {
|
||||
auto meta = CreateBlobFileMetaData(mutable_meta);
|
||||
|
||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
||||
}
|
||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
||||
|
||||
++base_it;
|
||||
++mutable_it;
|
||||
++delta_it;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -962,19 +843,18 @@ class VersionBuilder::Rep {
|
||||
++base_it;
|
||||
}
|
||||
|
||||
while (mutable_it != mutable_it_end) {
|
||||
const auto& mutable_meta = mutable_it->second;
|
||||
while (delta_it != delta_it_end) {
|
||||
const auto& delta = delta_it->second;
|
||||
|
||||
auto meta = CreateBlobFileMetaData(mutable_meta);
|
||||
auto meta = CreateMetaDataForNewBlobFile(delta);
|
||||
|
||||
AddBlobFileIfNeeded(vstorage, meta, &found_first_non_empty);
|
||||
|
||||
++mutable_it;
|
||||
++delta_it;
|
||||
}
|
||||
}
|
||||
|
||||
void MaybeAddFile(VersionStorageInfo* vstorage, int level,
|
||||
FileMetaData* f) const {
|
||||
void MaybeAddFile(VersionStorageInfo* vstorage, int level, FileMetaData* f) {
|
||||
const uint64_t file_number = f->fd.GetNumber();
|
||||
|
||||
const auto& level_state = levels_[level];
|
||||
@@ -999,52 +879,52 @@ class VersionBuilder::Rep {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Cmp>
|
||||
void SaveSSTFilesTo(VersionStorageInfo* vstorage, int level, Cmp cmp) const {
|
||||
// Merge the set of added files with the set of pre-existing files.
|
||||
// Drop any deleted files. Store the result in *vstorage.
|
||||
const auto& base_files = base_vstorage_->LevelFiles(level);
|
||||
const auto& unordered_added_files = levels_[level].added_files;
|
||||
vstorage->Reserve(level, base_files.size() + unordered_added_files.size());
|
||||
void SaveSSTFilesTo(VersionStorageInfo* vstorage) {
|
||||
for (int level = 0; level < num_levels_; level++) {
|
||||
const auto& cmp = (level == 0) ? level_zero_cmp_ : level_nonzero_cmp_;
|
||||
// Merge the set of added files with the set of pre-existing files.
|
||||
// Drop any deleted files. Store the result in *v.
|
||||
const auto& base_files = base_vstorage_->LevelFiles(level);
|
||||
const auto& unordered_added_files = levels_[level].added_files;
|
||||
vstorage->Reserve(level,
|
||||
base_files.size() + unordered_added_files.size());
|
||||
|
||||
// Sort added files for the level.
|
||||
std::vector<FileMetaData*> added_files;
|
||||
added_files.reserve(unordered_added_files.size());
|
||||
for (const auto& pair : unordered_added_files) {
|
||||
added_files.push_back(pair.second);
|
||||
}
|
||||
std::sort(added_files.begin(), added_files.end(), cmp);
|
||||
// Sort added files for the level.
|
||||
std::vector<FileMetaData*> added_files;
|
||||
added_files.reserve(unordered_added_files.size());
|
||||
for (const auto& pair : unordered_added_files) {
|
||||
added_files.push_back(pair.second);
|
||||
}
|
||||
std::sort(added_files.begin(), added_files.end(), cmp);
|
||||
|
||||
auto base_iter = base_files.begin();
|
||||
auto base_end = base_files.end();
|
||||
auto added_iter = added_files.begin();
|
||||
auto added_end = added_files.end();
|
||||
while (added_iter != added_end || base_iter != base_end) {
|
||||
if (base_iter == base_end ||
|
||||
(added_iter != added_end && cmp(*added_iter, *base_iter))) {
|
||||
MaybeAddFile(vstorage, level, *added_iter++);
|
||||
} else {
|
||||
MaybeAddFile(vstorage, level, *base_iter++);
|
||||
#ifndef NDEBUG
|
||||
FileMetaData* prev_added_file = nullptr;
|
||||
for (const auto& added : added_files) {
|
||||
if (level > 0 && prev_added_file != nullptr) {
|
||||
assert(base_vstorage_->InternalComparator()->Compare(
|
||||
prev_added_file->smallest, added->smallest) <= 0);
|
||||
}
|
||||
prev_added_file = added;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto base_iter = base_files.begin();
|
||||
auto base_end = base_files.end();
|
||||
auto added_iter = added_files.begin();
|
||||
auto added_end = added_files.end();
|
||||
while (added_iter != added_end || base_iter != base_end) {
|
||||
if (base_iter == base_end ||
|
||||
(added_iter != added_end && cmp(*added_iter, *base_iter))) {
|
||||
MaybeAddFile(vstorage, level, *added_iter++);
|
||||
} else {
|
||||
MaybeAddFile(vstorage, level, *base_iter++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SaveSSTFilesTo(VersionStorageInfo* vstorage) const {
|
||||
assert(vstorage);
|
||||
|
||||
if (!num_levels_) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaveSSTFilesTo(vstorage, /* level */ 0, level_zero_cmp_);
|
||||
|
||||
for (int level = 1; level < num_levels_; ++level) {
|
||||
SaveSSTFilesTo(vstorage, level, level_nonzero_cmp_);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the current state in *vstorage.
|
||||
Status SaveTo(VersionStorageInfo* vstorage) const {
|
||||
Status SaveTo(VersionStorageInfo* vstorage) {
|
||||
Status s = CheckConsistency(base_vstorage_);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
@@ -1181,11 +1061,9 @@ bool VersionBuilder::CheckConsistencyForNumLevels() {
|
||||
return rep_->CheckConsistencyForNumLevels();
|
||||
}
|
||||
|
||||
Status VersionBuilder::Apply(const VersionEdit* edit) {
|
||||
return rep_->Apply(edit);
|
||||
}
|
||||
Status VersionBuilder::Apply(VersionEdit* edit) { return rep_->Apply(edit); }
|
||||
|
||||
Status VersionBuilder::SaveTo(VersionStorageInfo* vstorage) const {
|
||||
Status VersionBuilder::SaveTo(VersionStorageInfo* vstorage) {
|
||||
return rep_->SaveTo(vstorage);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ class VersionBuilder {
|
||||
~VersionBuilder();
|
||||
|
||||
bool CheckConsistencyForNumLevels();
|
||||
Status Apply(const VersionEdit* edit);
|
||||
Status SaveTo(VersionStorageInfo* vstorage) const;
|
||||
Status Apply(VersionEdit* edit);
|
||||
Status SaveTo(VersionStorageInfo* vstorage);
|
||||
Status LoadTableHandlers(InternalStats* internal_stats, int max_threads,
|
||||
bool prefetch_index_and_filter_in_cache,
|
||||
bool is_initial_load,
|
||||
@@ -66,4 +66,5 @@ class BaseReferencedVersionBuilder {
|
||||
Version* version_;
|
||||
};
|
||||
|
||||
extern bool NewestFirstBySeqNo(FileMetaData* a, FileMetaData* b);
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -149,7 +149,7 @@ class VersionBuilderTest : public testing::Test {
|
||||
}
|
||||
|
||||
void UpdateVersionStorageInfo() {
|
||||
vstorage_.UpdateFilesByCompactionPri(ioptions_, mutable_cf_options_);
|
||||
vstorage_.UpdateFilesByCompactionPri(ioptions_.compaction_pri);
|
||||
vstorage_.UpdateNumNonEmptyLevels();
|
||||
vstorage_.GenerateFileIndexer();
|
||||
vstorage_.GenerateLevelFilesBrief();
|
||||
@@ -923,69 +923,6 @@ TEST_F(VersionBuilderTest, ApplyBlobFileGarbageFileNotFound) {
|
||||
ASSERT_TRUE(std::strstr(s.getState(), "Blob file #1234 not found"));
|
||||
}
|
||||
|
||||
TEST_F(VersionBuilderTest, BlobFileGarbageOverflow) {
|
||||
// Test that VersionEdits that would result in the count/total size of garbage
|
||||
// exceeding the count/total size of all blobs are rejected.
|
||||
|
||||
EnvOptions env_options;
|
||||
constexpr TableCache* table_cache = nullptr;
|
||||
constexpr VersionSet* version_set = nullptr;
|
||||
|
||||
VersionBuilder builder(env_options, &ioptions_, table_cache, &vstorage_,
|
||||
version_set);
|
||||
|
||||
VersionEdit addition;
|
||||
|
||||
constexpr uint64_t blob_file_number = 1234;
|
||||
constexpr uint64_t total_blob_count = 5678;
|
||||
constexpr uint64_t total_blob_bytes = 999999;
|
||||
constexpr char checksum_method[] = "SHA1";
|
||||
constexpr char checksum_value[] =
|
||||
"\xbd\xb7\xf3\x4a\x59\xdf\xa1\x59\x2c\xe7\xf5\x2e\x99\xf9\x8c\x57\x0c\x52"
|
||||
"\x5c\xbd";
|
||||
|
||||
addition.AddBlobFile(blob_file_number, total_blob_count, total_blob_bytes,
|
||||
checksum_method, checksum_value);
|
||||
|
||||
// Add dummy table file to ensure the blob file is referenced.
|
||||
constexpr uint64_t table_file_number = 1;
|
||||
AddDummyFileToEdit(&addition, table_file_number, blob_file_number);
|
||||
|
||||
ASSERT_OK(builder.Apply(&addition));
|
||||
|
||||
{
|
||||
// Garbage blob count overflow
|
||||
constexpr uint64_t garbage_blob_count = 5679;
|
||||
constexpr uint64_t garbage_blob_bytes = 999999;
|
||||
|
||||
VersionEdit garbage;
|
||||
|
||||
garbage.AddBlobFileGarbage(blob_file_number, garbage_blob_count,
|
||||
garbage_blob_bytes);
|
||||
|
||||
const Status s = builder.Apply(&garbage);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(
|
||||
std::strstr(s.getState(), "Garbage overflow for blob file #1234"));
|
||||
}
|
||||
|
||||
{
|
||||
// Garbage blob bytes overflow
|
||||
constexpr uint64_t garbage_blob_count = 5678;
|
||||
constexpr uint64_t garbage_blob_bytes = 1000000;
|
||||
|
||||
VersionEdit garbage;
|
||||
|
||||
garbage.AddBlobFileGarbage(blob_file_number, garbage_blob_count,
|
||||
garbage_blob_bytes);
|
||||
|
||||
const Status s = builder.Apply(&garbage);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(
|
||||
std::strstr(s.getState(), "Garbage overflow for blob file #1234"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(VersionBuilderTest, SaveBlobFilesTo) {
|
||||
// Add three blob files to base version.
|
||||
for (uint64_t i = 3; i >= 1; --i) {
|
||||
|
||||
+48
-34
@@ -20,13 +20,12 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "compaction/compaction.h"
|
||||
#include "db/blob/blob_fetcher.h"
|
||||
#include "db/blob/blob_file_cache.h"
|
||||
#include "db/blob/blob_file_reader.h"
|
||||
#include "db/blob/blob_index.h"
|
||||
#include "db/blob/blob_log_format.h"
|
||||
#include "db/compaction/compaction.h"
|
||||
#include "db/compaction/file_pri.h"
|
||||
#include "db/internal_stats.h"
|
||||
#include "db/log_reader.h"
|
||||
#include "db/log_writer.h"
|
||||
@@ -120,9 +119,10 @@ Status OverlapWithIterator(const Comparator* ucmp,
|
||||
// are MergeInProgress).
|
||||
class FilePicker {
|
||||
public:
|
||||
FilePicker(const Slice& user_key, const Slice& ikey,
|
||||
autovector<LevelFilesBrief>* file_levels, unsigned int num_levels,
|
||||
FileIndexer* file_indexer, const Comparator* user_comparator,
|
||||
FilePicker(std::vector<FileMetaData*>* files, const Slice& user_key,
|
||||
const Slice& ikey, autovector<LevelFilesBrief>* file_levels,
|
||||
unsigned int num_levels, FileIndexer* file_indexer,
|
||||
const Comparator* user_comparator,
|
||||
const InternalKeyComparator* internal_comparator)
|
||||
: num_levels_(num_levels),
|
||||
curr_level_(static_cast<unsigned int>(-1)),
|
||||
@@ -130,6 +130,9 @@ class FilePicker {
|
||||
hit_file_level_(static_cast<unsigned int>(-1)),
|
||||
search_left_bound_(0),
|
||||
search_right_bound_(FileIndexer::kLevelMaxIndex),
|
||||
#ifndef NDEBUG
|
||||
files_(files),
|
||||
#endif
|
||||
level_files_brief_(file_levels),
|
||||
is_hit_file_last_in_level_(false),
|
||||
curr_file_level_(nullptr),
|
||||
@@ -138,6 +141,9 @@ class FilePicker {
|
||||
file_indexer_(file_indexer),
|
||||
user_comparator_(user_comparator),
|
||||
internal_comparator_(internal_comparator) {
|
||||
#ifdef NDEBUG
|
||||
(void)files;
|
||||
#endif
|
||||
// Setup member variables to search first level.
|
||||
search_ended_ = !PrepareNextLevel();
|
||||
if (!search_ended_) {
|
||||
@@ -207,7 +213,23 @@ class FilePicker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Sanity check to make sure that the files are correctly sorted
|
||||
if (prev_file_) {
|
||||
if (curr_level_ != 0) {
|
||||
int comp_sign = internal_comparator_->Compare(
|
||||
prev_file_->largest_key, f->smallest_key);
|
||||
assert(comp_sign < 0);
|
||||
} else {
|
||||
// level == 0, the current file cannot be newer than the previous
|
||||
// one. Use compressed data structure, has no attribute seqNo
|
||||
assert(curr_index_in_curr_level_ > 0);
|
||||
assert(!NewestFirstBySeqNo(files_[0][curr_index_in_curr_level_],
|
||||
files_[0][curr_index_in_curr_level_-1]));
|
||||
}
|
||||
}
|
||||
prev_file_ = f;
|
||||
#endif
|
||||
returned_file_level_ = curr_level_;
|
||||
if (curr_level_ > 0 && cmp_largest < 0) {
|
||||
// No more files to search in this level.
|
||||
@@ -239,6 +261,9 @@ class FilePicker {
|
||||
unsigned int hit_file_level_;
|
||||
int32_t search_left_bound_;
|
||||
int32_t search_right_bound_;
|
||||
#ifndef NDEBUG
|
||||
std::vector<FileMetaData*>* files_;
|
||||
#endif
|
||||
autovector<LevelFilesBrief>* level_files_brief_;
|
||||
bool search_ended_;
|
||||
bool is_hit_file_last_in_level_;
|
||||
@@ -250,6 +275,9 @@ class FilePicker {
|
||||
FileIndexer* file_indexer_;
|
||||
const Comparator* user_comparator_;
|
||||
const InternalKeyComparator* internal_comparator_;
|
||||
#ifndef NDEBUG
|
||||
FdWithKeyRange* prev_file_;
|
||||
#endif
|
||||
|
||||
// Setup local variables to search next level.
|
||||
// Returns false if there are no more levels to search.
|
||||
@@ -319,7 +347,9 @@ class FilePicker {
|
||||
}
|
||||
start_index_in_curr_level_ = start_index;
|
||||
curr_index_in_curr_level_ = start_index;
|
||||
|
||||
#ifndef NDEBUG
|
||||
prev_file_ = nullptr;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
// curr_level_ = num_levels_. So, no more levels to search.
|
||||
@@ -1991,10 +2021,10 @@ void Version::Get(const ReadOptions& read_options, const LookupKey& k,
|
||||
pinned_iters_mgr.StartPinning();
|
||||
}
|
||||
|
||||
FilePicker fp(user_key, ikey, &storage_info_.level_files_brief_,
|
||||
storage_info_.num_non_empty_levels_,
|
||||
&storage_info_.file_indexer_, user_comparator(),
|
||||
internal_comparator());
|
||||
FilePicker fp(
|
||||
storage_info_.files_, user_key, ikey, &storage_info_.level_files_brief_,
|
||||
storage_info_.num_non_empty_levels_, &storage_info_.file_indexer_,
|
||||
user_comparator(), internal_comparator());
|
||||
FdWithKeyRange* f = fp.GetNextFile();
|
||||
|
||||
while (f != nullptr) {
|
||||
@@ -2396,8 +2426,7 @@ void Version::PrepareApply(
|
||||
UpdateAccumulatedStats(update_stats);
|
||||
storage_info_.UpdateNumNonEmptyLevels();
|
||||
storage_info_.CalculateBaseBytes(*cfd_->ioptions(), mutable_cf_options);
|
||||
storage_info_.UpdateFilesByCompactionPri(*cfd_->ioptions(),
|
||||
mutable_cf_options);
|
||||
storage_info_.UpdateFilesByCompactionPri(cfd_->ioptions()->compaction_pri);
|
||||
storage_info_.GenerateFileIndexer();
|
||||
storage_info_.GenerateLevelFilesBrief();
|
||||
storage_info_.GenerateLevel0NonOverlapping();
|
||||
@@ -3109,22 +3138,11 @@ namespace {
|
||||
// Sort `temp` based on ratio of overlapping size over file size
|
||||
void SortFileByOverlappingRatio(
|
||||
const InternalKeyComparator& icmp, const std::vector<FileMetaData*>& files,
|
||||
const std::vector<FileMetaData*>& next_level_files, SystemClock* clock,
|
||||
int level, int num_non_empty_levels, uint64_t ttl,
|
||||
const std::vector<FileMetaData*>& next_level_files,
|
||||
std::vector<Fsize>* temp) {
|
||||
std::unordered_map<uint64_t, uint64_t> file_to_order;
|
||||
auto next_level_it = next_level_files.begin();
|
||||
|
||||
int64_t curr_time;
|
||||
Status status = clock->GetCurrentTime(&curr_time);
|
||||
if (!status.ok()) {
|
||||
// If we can't get time, disable TTL.
|
||||
ttl = 0;
|
||||
}
|
||||
|
||||
FileTtlBooster ttl_booster(static_cast<uint64_t>(curr_time), ttl,
|
||||
num_non_empty_levels, level);
|
||||
|
||||
for (auto& file : files) {
|
||||
uint64_t overlapping_bytes = 0;
|
||||
// Skip files in next level that is smaller than current file
|
||||
@@ -3144,12 +3162,9 @@ void SortFileByOverlappingRatio(
|
||||
next_level_it++;
|
||||
}
|
||||
|
||||
uint64_t ttl_boost_score = (ttl > 0) ? ttl_booster.GetBoostScore(file) : 1;
|
||||
assert(ttl_boost_score > 0);
|
||||
assert(file->compensated_file_size != 0);
|
||||
file_to_order[file->fd.GetNumber()] = overlapping_bytes * 1024U /
|
||||
file->compensated_file_size /
|
||||
ttl_boost_score;
|
||||
file_to_order[file->fd.GetNumber()] =
|
||||
overlapping_bytes * 1024u / file->compensated_file_size;
|
||||
}
|
||||
|
||||
std::sort(temp->begin(), temp->end(),
|
||||
@@ -3161,7 +3176,7 @@ void SortFileByOverlappingRatio(
|
||||
} // namespace
|
||||
|
||||
void VersionStorageInfo::UpdateFilesByCompactionPri(
|
||||
const ImmutableOptions& ioptions, const MutableCFOptions& options) {
|
||||
CompactionPri compaction_pri) {
|
||||
if (compaction_style_ == kCompactionStyleNone ||
|
||||
compaction_style_ == kCompactionStyleFIFO ||
|
||||
compaction_style_ == kCompactionStyleUniversal) {
|
||||
@@ -3186,7 +3201,7 @@ void VersionStorageInfo::UpdateFilesByCompactionPri(
|
||||
if (num > temp.size()) {
|
||||
num = temp.size();
|
||||
}
|
||||
switch (ioptions.compaction_pri) {
|
||||
switch (compaction_pri) {
|
||||
case kByCompensatedSize:
|
||||
std::partial_sort(temp.begin(), temp.begin() + num, temp.end(),
|
||||
CompareCompensatedSizeDescending);
|
||||
@@ -3207,8 +3222,7 @@ void VersionStorageInfo::UpdateFilesByCompactionPri(
|
||||
break;
|
||||
case kMinOverlappingRatio:
|
||||
SortFileByOverlappingRatio(*internal_comparator_, files_[level],
|
||||
files_[level + 1], ioptions.clock, level,
|
||||
num_non_empty_levels_, options.ttl, &temp);
|
||||
files_[level + 1], &temp);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
||||
+2
-3
@@ -197,8 +197,7 @@ class VersionStorageInfo {
|
||||
// Sort all files for this version based on their file size and
|
||||
// record results in files_by_compaction_pri_. The largest files are listed
|
||||
// first.
|
||||
void UpdateFilesByCompactionPri(const ImmutableOptions& immutable_options,
|
||||
const MutableCFOptions& mutable_cf_options);
|
||||
void UpdateFilesByCompactionPri(CompactionPri compaction_pri);
|
||||
|
||||
void GenerateLevel0NonOverlapping();
|
||||
bool level0_non_overlapping() const {
|
||||
@@ -491,7 +490,7 @@ class VersionStorageInfo {
|
||||
next_file_to_compact_by_size_[level] = 0;
|
||||
}
|
||||
|
||||
const InternalKeyComparator* InternalComparator() const {
|
||||
const InternalKeyComparator* InternalComparator() {
|
||||
return internal_comparator_;
|
||||
}
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ class VersionStorageInfoTestBase : public testing::Test {
|
||||
void Finalize() {
|
||||
vstorage_.UpdateNumNonEmptyLevels();
|
||||
vstorage_.CalculateBaseBytes(ioptions_, mutable_cf_options_);
|
||||
vstorage_.UpdateFilesByCompactionPri(ioptions_, mutable_cf_options_);
|
||||
vstorage_.UpdateFilesByCompactionPri(ioptions_.compaction_pri);
|
||||
vstorage_.GenerateFileIndexer();
|
||||
vstorage_.GenerateLevelFilesBrief();
|
||||
vstorage_.GenerateLevel0NonOverlapping();
|
||||
@@ -2083,7 +2083,7 @@ class VersionSetAtomicGroupTest : public VersionSetTestBase,
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionEditHandlerBase::Iterate:Finish", [&](void* arg) {
|
||||
num_recovered_edits_ = *reinterpret_cast<size_t*>(arg);
|
||||
num_recovered_edits_ = *reinterpret_cast<int*>(arg);
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"AtomicGroupReadBuffer::AddEdit:AtomicGroup",
|
||||
@@ -2123,7 +2123,7 @@ class VersionSetAtomicGroupTest : public VersionSetTestBase,
|
||||
bool first_in_atomic_group_ = false;
|
||||
bool last_in_atomic_group_ = false;
|
||||
int num_edits_in_atomic_group_ = 0;
|
||||
size_t num_recovered_edits_ = 0;
|
||||
int num_recovered_edits_ = 0;
|
||||
VersionEdit corrupted_edit_;
|
||||
VersionEdit edit_with_incorrect_group_size_;
|
||||
std::unique_ptr<log::Writer> log_writer_;
|
||||
|
||||
@@ -1812,10 +1812,6 @@ void StressTest::TestCompactFiles(ThreadState* thread,
|
||||
ROCKSDB_NAMESPACE::ColumnFamilyMetaData cf_meta_data;
|
||||
db_->GetColumnFamilyMetaData(column_family, &cf_meta_data);
|
||||
|
||||
if (cf_meta_data.levels.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Randomly compact up to three consecutive files from a level
|
||||
const int kMaxRetry = 3;
|
||||
for (int attempt = 0; attempt < kMaxRetry; ++attempt) {
|
||||
|
||||
Vendored
+1
-1
@@ -272,7 +272,7 @@ class CompositeDirectoryWrapper : public Directory {
|
||||
Status Fsync() override {
|
||||
IOOptions io_opts;
|
||||
IODebugContext dbg;
|
||||
return target_->FsyncWithDirOptions(io_opts, &dbg, DirFsyncOptions());
|
||||
return target_->Fsync(io_opts, &dbg);
|
||||
}
|
||||
size_t GetUniqueId(char* id, size_t max_size) const override {
|
||||
return target_->GetUniqueId(id, max_size);
|
||||
|
||||
Vendored
+1
-2
@@ -324,8 +324,7 @@ class LegacyFileSystemWrapper : public FileSystem {
|
||||
explicit LegacyFileSystemWrapper(Env* t) : target_(t) {}
|
||||
~LegacyFileSystemWrapper() override {}
|
||||
|
||||
static const char* kClassName() { return "LegacyFileSystem"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
const char* Name() const override { return "Legacy File System"; }
|
||||
|
||||
// Return the target to which this Env forwards all calls
|
||||
Env* target() const { return target_; }
|
||||
|
||||
Vendored
+54
-73
@@ -13,35 +13,20 @@
|
||||
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "env/fs_remap.h"
|
||||
#include "rocksdb/utilities/options_type.h"
|
||||
#include "util/string_util.h" // errnoStr
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
static std::unordered_map<std::string, OptionTypeInfo> chroot_fs_type_info = {
|
||||
{"chroot_dir", {0, OptionType::kString}}};
|
||||
} // namespace
|
||||
ChrootFileSystem::ChrootFileSystem(const std::shared_ptr<FileSystem>& base,
|
||||
const std::string& chroot_dir)
|
||||
: RemapFileSystem(base), chroot_dir_(chroot_dir) {
|
||||
RegisterOptions("chroot_dir", &chroot_dir_, &chroot_fs_type_info);
|
||||
}
|
||||
|
||||
Status ChrootFileSystem::PrepareOptions(const ConfigOptions& options) {
|
||||
Status s = FileSystemWrapper::PrepareOptions(options);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
} else if (chroot_dir_.empty()) {
|
||||
s = Status::InvalidArgument("ChRootFileSystem requires a chroot dir");
|
||||
} else {
|
||||
s = target_->FileExists(chroot_dir_, IOOptions(), nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
class ChrootFileSystem : public RemapFileSystem {
|
||||
public:
|
||||
ChrootFileSystem(const std::shared_ptr<FileSystem>& base,
|
||||
const std::string& chroot_dir)
|
||||
: RemapFileSystem(base) {
|
||||
#if defined(OS_AIX)
|
||||
char resolvedName[PATH_MAX];
|
||||
char* real_chroot_dir = realpath(chroot_dir_.c_str(), resolvedName);
|
||||
char* real_chroot_dir = realpath(chroot_dir.c_str(), resolvedName);
|
||||
#else
|
||||
char* real_chroot_dir = realpath(chroot_dir_.c_str(), nullptr);
|
||||
char* real_chroot_dir = realpath(chroot_dir.c_str(), nullptr);
|
||||
#endif
|
||||
// chroot_dir must exist so realpath() returns non-nullptr.
|
||||
assert(real_chroot_dir != nullptr);
|
||||
@@ -50,32 +35,32 @@ Status ChrootFileSystem::PrepareOptions(const ConfigOptions& options) {
|
||||
free(real_chroot_dir);
|
||||
#endif
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
IOStatus ChrootFileSystem::GetTestDirectory(const IOOptions& options,
|
||||
std::string* path,
|
||||
IODebugContext* dbg) {
|
||||
// Adapted from PosixEnv's implementation since it doesn't provide a way to
|
||||
// create directory in the chroot.
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "/rocksdbtest-%d", static_cast<int>(geteuid()));
|
||||
*path = buf;
|
||||
const char* Name() const override { return "ChrootFS"; }
|
||||
|
||||
// Directory may already exist, so ignore return
|
||||
return CreateDirIfMissing(*path, options, dbg);
|
||||
}
|
||||
IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
|
||||
IODebugContext* dbg) override {
|
||||
// Adapted from PosixEnv's implementation since it doesn't provide a way to
|
||||
// create directory in the chroot.
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "/rocksdbtest-%d", static_cast<int>(geteuid()));
|
||||
*path = buf;
|
||||
|
||||
// Directory may already exist, so ignore return
|
||||
return CreateDirIfMissing(*path, options, dbg);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Returns status and expanded absolute path including the chroot directory.
|
||||
// Checks whether the provided path breaks out of the chroot. If it returns
|
||||
// non-OK status, the returned path should not be used.
|
||||
std::pair<IOStatus, std::string> ChrootFileSystem::EncodePath(
|
||||
const std::string& path) {
|
||||
if (path.empty() || path[0] != '/') {
|
||||
return {IOStatus::InvalidArgument(path, "Not an absolute path"), ""};
|
||||
}
|
||||
std::pair<IOStatus, std::string> res;
|
||||
res.second = chroot_dir_ + path;
|
||||
std::pair<IOStatus, std::string> EncodePath(
|
||||
const std::string& path) override {
|
||||
if (path.empty() || path[0] != '/') {
|
||||
return {IOStatus::InvalidArgument(path, "Not an absolute path"), ""};
|
||||
}
|
||||
std::pair<IOStatus, std::string> res;
|
||||
res.second = chroot_dir_ + path;
|
||||
#if defined(OS_AIX)
|
||||
char resolvedName[PATH_MAX];
|
||||
char* normalized_path = realpath(res.second.c_str(), resolvedName);
|
||||
@@ -96,51 +81,47 @@ std::pair<IOStatus, std::string> ChrootFileSystem::EncodePath(
|
||||
free(normalized_path);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// Similar to EncodePath() except assumes the basename in the path hasn't been
|
||||
// created yet.
|
||||
std::pair<IOStatus, std::string> ChrootFileSystem::EncodePathWithNewBasename(
|
||||
const std::string& path) {
|
||||
if (path.empty() || path[0] != '/') {
|
||||
return {IOStatus::InvalidArgument(path, "Not an absolute path"), ""};
|
||||
}
|
||||
// Basename may be followed by trailing slashes
|
||||
size_t final_idx = path.find_last_not_of('/');
|
||||
if (final_idx == std::string::npos) {
|
||||
// It's only slashes so no basename to extract
|
||||
return EncodePath(path);
|
||||
std::pair<IOStatus, std::string> EncodePathWithNewBasename(
|
||||
const std::string& path) override {
|
||||
if (path.empty() || path[0] != '/') {
|
||||
return {IOStatus::InvalidArgument(path, "Not an absolute path"), ""};
|
||||
}
|
||||
// Basename may be followed by trailing slashes
|
||||
size_t final_idx = path.find_last_not_of('/');
|
||||
if (final_idx == std::string::npos) {
|
||||
// It's only slashes so no basename to extract
|
||||
return EncodePath(path);
|
||||
}
|
||||
|
||||
// Pull off the basename temporarily since realname(3) (used by
|
||||
// EncodePath()) requires a path that exists
|
||||
size_t base_sep = path.rfind('/', final_idx);
|
||||
auto status_and_enc_path = EncodePath(path.substr(0, base_sep + 1));
|
||||
status_and_enc_path.second.append(path.substr(base_sep + 1));
|
||||
return status_and_enc_path;
|
||||
}
|
||||
|
||||
// Pull off the basename temporarily since realname(3) (used by
|
||||
// EncodePath()) requires a path that exists
|
||||
size_t base_sep = path.rfind('/', final_idx);
|
||||
auto status_and_enc_path = EncodePath(path.substr(0, base_sep + 1));
|
||||
status_and_enc_path.second.append(path.substr(base_sep + 1));
|
||||
return status_and_enc_path;
|
||||
}
|
||||
private:
|
||||
std::string chroot_dir_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<FileSystem> NewChrootFileSystem(
|
||||
const std::shared_ptr<FileSystem>& base, const std::string& chroot_dir) {
|
||||
auto chroot_fs = std::make_shared<ChrootFileSystem>(base, chroot_dir);
|
||||
Status s = chroot_fs->PrepareOptions(ConfigOptions());
|
||||
if (s.ok()) {
|
||||
return chroot_fs;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<ChrootFileSystem>(base, chroot_dir);
|
||||
}
|
||||
|
||||
Env* NewChrootEnv(Env* base_env, const std::string& chroot_dir) {
|
||||
if (!base_env->FileExists(chroot_dir).ok()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto chroot_fs = NewChrootFileSystem(base_env->GetFileSystem(), chroot_dir);
|
||||
if (chroot_fs != nullptr) {
|
||||
return new CompositeEnvWrapper(base_env, chroot_fs);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
std::shared_ptr<FileSystem> chroot_fs =
|
||||
NewChrootFileSystem(base_env->GetFileSystem(), chroot_dir);
|
||||
return new CompositeEnvWrapper(base_env, chroot_fs);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
Vendored
+1
-31
@@ -9,37 +9,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "env/fs_remap.h"
|
||||
#include "rocksdb/file_system.h"
|
||||
#include "rocksdb/env.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class ChrootFileSystem : public RemapFileSystem {
|
||||
public:
|
||||
ChrootFileSystem(const std::shared_ptr<FileSystem>& base,
|
||||
const std::string& chroot_dir);
|
||||
|
||||
static const char* kClassName() { return "ChrootFS"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
|
||||
IODebugContext* dbg) override;
|
||||
|
||||
Status PrepareOptions(const ConfigOptions& options) override;
|
||||
|
||||
protected:
|
||||
// Returns status and expanded absolute path including the chroot directory.
|
||||
// Checks whether the provided path breaks out of the chroot. If it returns
|
||||
// non-OK status, the returned path should not be used.
|
||||
std::pair<IOStatus, std::string> EncodePath(const std::string& path) override;
|
||||
|
||||
// Similar to EncodePath() except assumes the basename in the path hasn't been
|
||||
// created yet.
|
||||
std::pair<IOStatus, std::string> EncodePathWithNewBasename(
|
||||
const std::string& path) override;
|
||||
|
||||
private:
|
||||
std::string chroot_dir_;
|
||||
};
|
||||
|
||||
// Returns an Env that translates paths such that the root directory appears to
|
||||
// be chroot_dir. chroot_dir should refer to an existing directory.
|
||||
@@ -47,8 +19,6 @@ class ChrootFileSystem : public RemapFileSystem {
|
||||
// This class has not been fully analyzed for providing strong security
|
||||
// guarantees.
|
||||
Env* NewChrootEnv(Env* base_env, const std::string& chroot_dir);
|
||||
std::shared_ptr<FileSystem> NewChrootFileSystem(
|
||||
const std::shared_ptr<FileSystem>& base, const std::string& chroot_dir);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
|
||||
Vendored
+2
-30
@@ -438,20 +438,11 @@ IOStatus EncryptedRandomRWFile::Close(const IOOptions& options,
|
||||
}
|
||||
|
||||
namespace {
|
||||
static std::unordered_map<std::string, OptionTypeInfo> encrypted_fs_type_info =
|
||||
{
|
||||
{"provider",
|
||||
OptionTypeInfo::AsCustomSharedPtr<EncryptionProvider>(
|
||||
0 /* No offset, whole struct*/, OptionVerificationType::kByName,
|
||||
OptionTypeFlags::kNone)},
|
||||
};
|
||||
// EncryptedFileSystemImpl implements an FileSystemWrapper that adds encryption
|
||||
// to files stored on disk.
|
||||
class EncryptedFileSystemImpl : public EncryptedFileSystem {
|
||||
public:
|
||||
const char* Name() const override {
|
||||
return EncryptedFileSystem::kClassName();
|
||||
}
|
||||
const char* Name() const override { return "EncryptedFS"; }
|
||||
// Returns the raw encryption provider that should be used to write the input
|
||||
// encrypted file. If there is no such provider, NotFound is returned.
|
||||
IOStatus GetWritableProvider(const std::string& /*fname*/,
|
||||
@@ -673,7 +664,6 @@ class EncryptedFileSystemImpl : public EncryptedFileSystem {
|
||||
const std::shared_ptr<EncryptionProvider>& provider)
|
||||
: EncryptedFileSystem(base) {
|
||||
provider_ = provider;
|
||||
RegisterOptions("EncryptionProvider", &provider_, &encrypted_fs_type_info);
|
||||
}
|
||||
|
||||
Status AddCipher(const std::string& descriptor, const char* cipher,
|
||||
@@ -920,28 +910,10 @@ class EncryptedFileSystemImpl : public EncryptedFileSystem {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
Status NewEncryptedFileSystemImpl(
|
||||
const std::shared_ptr<FileSystem>& base,
|
||||
const std::shared_ptr<EncryptionProvider>& provider,
|
||||
std::unique_ptr<FileSystem>* result) {
|
||||
result->reset(new EncryptedFileSystemImpl(base, provider));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::shared_ptr<FileSystem> NewEncryptedFS(
|
||||
const std::shared_ptr<FileSystem>& base,
|
||||
const std::shared_ptr<EncryptionProvider>& provider) {
|
||||
std::unique_ptr<FileSystem> efs;
|
||||
Status s = NewEncryptedFileSystemImpl(base, provider, &efs);
|
||||
if (s.ok()) {
|
||||
s = efs->PrepareOptions(ConfigOptions());
|
||||
}
|
||||
if (s.ok()) {
|
||||
std::shared_ptr<FileSystem> result(efs.release());
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<EncryptedFileSystemImpl>(base, provider);
|
||||
}
|
||||
// Returns an Env that encrypts data when stored on disk and decrypts data when
|
||||
// read from disk.
|
||||
|
||||
Vendored
-6
@@ -105,12 +105,6 @@ class CTREncryptionProvider : public EncryptionProvider {
|
||||
uint64_t initialCounter, const Slice& iv, const Slice& prefix,
|
||||
std::unique_ptr<BlockAccessCipherStream>* result);
|
||||
};
|
||||
|
||||
Status NewEncryptedFileSystemImpl(
|
||||
const std::shared_ptr<FileSystem>& base_fs,
|
||||
const std::shared_ptr<EncryptionProvider>& provider,
|
||||
std::unique_ptr<FileSystem>* fs);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // !defined(ROCKSDB_LITE)
|
||||
Vendored
+10
-161
@@ -39,7 +39,6 @@
|
||||
#include "env/emulated_clock.h"
|
||||
#include "env/env_chroot.h"
|
||||
#include "env/env_encryption_ctr.h"
|
||||
#include "env/fs_readonly.h"
|
||||
#include "env/unique_id_gen.h"
|
||||
#include "logging/log_buffer.h"
|
||||
#include "logging/logging.h"
|
||||
@@ -60,7 +59,6 @@
|
||||
#include "util/mutexlock.h"
|
||||
#include "util/random.h"
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/env_timed.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
#include "utilities/fault_injection_fs.h"
|
||||
|
||||
@@ -2235,17 +2233,14 @@ INSTANTIATE_TEST_CASE_P(DefaultEnvWithDirectIO, EnvPosixTestWithParam,
|
||||
#endif // !defined(ROCKSDB_LITE)
|
||||
|
||||
#if !defined(ROCKSDB_LITE) && !defined(OS_WIN)
|
||||
static Env* GetChrootEnv() {
|
||||
static std::unique_ptr<Env> chroot_env(
|
||||
NewChrootEnv(Env::Default(), test::TmpDir(Env::Default())));
|
||||
return chroot_env.get();
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(ChrootEnvWithoutDirectIO, EnvPosixTestWithParam,
|
||||
::testing::Values(std::pair<Env*, bool>(GetChrootEnv(),
|
||||
false)));
|
||||
INSTANTIATE_TEST_CASE_P(ChrootEnvWithDirectIO, EnvPosixTestWithParam,
|
||||
::testing::Values(std::pair<Env*, bool>(GetChrootEnv(),
|
||||
true)));
|
||||
static std::unique_ptr<Env> chroot_env(
|
||||
NewChrootEnv(Env::Default(), test::TmpDir(Env::Default())));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ChrootEnvWithoutDirectIO, EnvPosixTestWithParam,
|
||||
::testing::Values(std::pair<Env*, bool>(chroot_env.get(), false)));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ChrootEnvWithDirectIO, EnvPosixTestWithParam,
|
||||
::testing::Values(std::pair<Env*, bool>(chroot_env.get(), true)));
|
||||
#endif // !defined(ROCKSDB_LITE) && !defined(OS_WIN)
|
||||
|
||||
class EnvFSTestWithParam
|
||||
@@ -2497,6 +2492,7 @@ TEST_F(CreateEnvTest, CreateMockSystemClock) {
|
||||
guard->reset(new MockSystemClock(nullptr));
|
||||
return guard->get();
|
||||
});
|
||||
|
||||
ASSERT_OK(SystemClock::CreateFromString(
|
||||
config_options_, EmulatedSystemClock::kClassName(), &mock));
|
||||
ASSERT_NE(mock, nullptr);
|
||||
@@ -2522,154 +2518,6 @@ TEST_F(CreateEnvTest, CreateMockSystemClock) {
|
||||
ASSERT_OK(SystemClock::CreateFromString(
|
||||
config_options_, EmulatedSystemClock::kClassName(), &mock));
|
||||
}
|
||||
|
||||
TEST_F(CreateEnvTest, CreateReadOnlyFileSystem) {
|
||||
std::shared_ptr<FileSystem> fs, copy;
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(
|
||||
config_options_, ReadOnlyFileSystem::kClassName(), &fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), ReadOnlyFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner(), FileSystem::Default().get());
|
||||
|
||||
std::string opts_str = fs->ToString(config_options_);
|
||||
std::string mismatch;
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(
|
||||
config_options_,
|
||||
std::string("id=") + ReadOnlyFileSystem::kClassName() +
|
||||
"; target=" + TimedFileSystem::kClassName(),
|
||||
&fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
opts_str = fs->ToString(config_options_);
|
||||
ASSERT_STREQ(fs->Name(), ReadOnlyFileSystem::kClassName());
|
||||
ASSERT_NE(fs->Inner(), nullptr);
|
||||
ASSERT_STREQ(fs->Inner()->Name(), TimedFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner()->Inner(), FileSystem::Default().get());
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
}
|
||||
|
||||
TEST_F(CreateEnvTest, CreateTimedFileSystem) {
|
||||
std::shared_ptr<FileSystem> fs, copy;
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_,
|
||||
TimedFileSystem::kClassName(), &fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), TimedFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner(), FileSystem::Default().get());
|
||||
|
||||
std::string opts_str = fs->ToString(config_options_);
|
||||
std::string mismatch;
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(
|
||||
config_options_,
|
||||
std::string("id=") + TimedFileSystem::kClassName() +
|
||||
"; target=" + ReadOnlyFileSystem::kClassName(),
|
||||
&fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
opts_str = fs->ToString(config_options_);
|
||||
ASSERT_STREQ(fs->Name(), TimedFileSystem::kClassName());
|
||||
ASSERT_NE(fs->Inner(), nullptr);
|
||||
ASSERT_STREQ(fs->Inner()->Name(), ReadOnlyFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner()->Inner(), FileSystem::Default().get());
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
}
|
||||
#ifndef OS_WIN
|
||||
TEST_F(CreateEnvTest, CreateChrootFileSystem) {
|
||||
std::shared_ptr<FileSystem> fs, copy;
|
||||
auto tmp_dir = test::TmpDir(Env::Default());
|
||||
// The Chroot FileSystem has a required "chroot_dir" option.
|
||||
ASSERT_NOK(FileSystem::CreateFromString(config_options_,
|
||||
ChrootFileSystem::kClassName(), &fs));
|
||||
|
||||
// ChrootFileSystem fails with an invalid directory
|
||||
ASSERT_NOK(FileSystem::CreateFromString(
|
||||
config_options_,
|
||||
std::string("chroot_dir=/No/Such/Directory; id=") +
|
||||
ChrootFileSystem::kClassName(),
|
||||
&fs));
|
||||
std::string chroot_opts = std::string("chroot_dir=") + tmp_dir +
|
||||
std::string("; id=") +
|
||||
ChrootFileSystem::kClassName();
|
||||
|
||||
// Create a valid ChrootFileSystem with an inner Default
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, chroot_opts, &fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), ChrootFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner(), FileSystem::Default().get());
|
||||
std::string opts_str = fs->ToString(config_options_);
|
||||
std::string mismatch;
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
|
||||
// Create a valid ChrootFileSystem with an inner TimedFileSystem
|
||||
ASSERT_OK(FileSystem::CreateFromString(
|
||||
config_options_,
|
||||
chroot_opts + "; target=" + TimedFileSystem::kClassName(), &fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), ChrootFileSystem::kClassName());
|
||||
ASSERT_NE(fs->Inner(), nullptr);
|
||||
ASSERT_STREQ(fs->Inner()->Name(), TimedFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner()->Inner(), FileSystem::Default().get());
|
||||
opts_str = fs->ToString(config_options_);
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
|
||||
// Create a TimedFileSystem with an inner ChrootFileSystem
|
||||
ASSERT_OK(FileSystem::CreateFromString(
|
||||
config_options_,
|
||||
"target={" + chroot_opts + "}; id=" + TimedFileSystem::kClassName(),
|
||||
&fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), TimedFileSystem::kClassName());
|
||||
ASSERT_NE(fs->Inner(), nullptr);
|
||||
ASSERT_STREQ(fs->Inner()->Name(), ChrootFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner()->Inner(), FileSystem::Default().get());
|
||||
opts_str = fs->ToString(config_options_);
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
TEST_F(CreateEnvTest, CreateEncryptedFileSystem) {
|
||||
std::shared_ptr<FileSystem> fs, copy;
|
||||
|
||||
std::string base_opts =
|
||||
std::string("provider=1://test; id=") + EncryptedFileSystem::kClassName();
|
||||
// The EncryptedFileSystem requires a "provider" option.
|
||||
ASSERT_NOK(FileSystem::CreateFromString(
|
||||
config_options_, EncryptedFileSystem::kClassName(), &fs));
|
||||
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, base_opts, &fs));
|
||||
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), EncryptedFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner(), FileSystem::Default().get());
|
||||
std::string opts_str = fs->ToString(config_options_);
|
||||
std::string mismatch;
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
ASSERT_OK(FileSystem::CreateFromString(
|
||||
config_options_, base_opts + "; target=" + TimedFileSystem::kClassName(),
|
||||
&fs));
|
||||
ASSERT_NE(fs, nullptr);
|
||||
ASSERT_STREQ(fs->Name(), EncryptedFileSystem::kClassName());
|
||||
ASSERT_NE(fs->Inner(), nullptr);
|
||||
ASSERT_STREQ(fs->Inner()->Name(), TimedFileSystem::kClassName());
|
||||
ASSERT_EQ(fs->Inner()->Inner(), FileSystem::Default().get());
|
||||
opts_str = fs->ToString(config_options_);
|
||||
ASSERT_OK(FileSystem::CreateFromString(config_options_, opts_str, ©));
|
||||
ASSERT_TRUE(fs->AreEquivalent(config_options_, copy.get(), &mismatch));
|
||||
}
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
namespace {
|
||||
@@ -2894,6 +2742,7 @@ TEST_F(EnvTest, FailureToCreateLockFile) {
|
||||
// Clean up
|
||||
ASSERT_OK(DestroyDir(env, dir));
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
Vendored
+9
-115
@@ -6,17 +6,9 @@
|
||||
#include "rocksdb/file_system.h"
|
||||
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "env/env_chroot.h"
|
||||
#include "env/env_encryption_ctr.h"
|
||||
#include "env/fs_readonly.h"
|
||||
#include "env/mock_env.h"
|
||||
#include "options/db_options.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/utilities/customizable_util.h"
|
||||
#include "rocksdb/utilities/object_registry.h"
|
||||
#include "rocksdb/utilities/options_type.h"
|
||||
#include "util/string_util.h"
|
||||
#include "utilities/env_timed.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -29,63 +21,19 @@ Status FileSystem::Load(const std::string& value,
|
||||
return CreateFromString(ConfigOptions(), value, result);
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
static int RegisterBuiltinFileSystems(ObjectLibrary& library,
|
||||
const std::string& /*arg*/) {
|
||||
library.Register<FileSystem>(
|
||||
TimedFileSystem::kClassName(),
|
||||
[](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard,
|
||||
std::string* /* errmsg */) {
|
||||
guard->reset(new TimedFileSystem(nullptr));
|
||||
return guard->get();
|
||||
});
|
||||
library.Register<FileSystem>(
|
||||
ReadOnlyFileSystem::kClassName(),
|
||||
[](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard,
|
||||
std::string* /* errmsg */) {
|
||||
guard->reset(new ReadOnlyFileSystem(nullptr));
|
||||
return guard->get();
|
||||
});
|
||||
library.Register<FileSystem>(
|
||||
EncryptedFileSystem::kClassName(),
|
||||
[](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard,
|
||||
std::string* errmsg) {
|
||||
Status s = NewEncryptedFileSystemImpl(nullptr, nullptr, guard);
|
||||
if (!s.ok()) {
|
||||
*errmsg = s.ToString();
|
||||
}
|
||||
return guard->get();
|
||||
});
|
||||
#ifndef OS_WIN
|
||||
library.Register<FileSystem>(
|
||||
ChrootFileSystem::kClassName(),
|
||||
[](const std::string& /*uri*/, std::unique_ptr<FileSystem>* guard,
|
||||
std::string* /* errmsg */) {
|
||||
guard->reset(new ChrootFileSystem(nullptr, ""));
|
||||
return guard->get();
|
||||
});
|
||||
#endif // OS_WIN
|
||||
size_t num_types;
|
||||
return static_cast<int>(library.GetFactoryCount(&num_types));
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
Status FileSystem::CreateFromString(const ConfigOptions& config_options,
|
||||
const std::string& value,
|
||||
std::shared_ptr<FileSystem>* result) {
|
||||
auto default_fs = FileSystem::Default();
|
||||
if (default_fs->IsInstanceOf(value)) {
|
||||
*result = default_fs;
|
||||
return Status::OK();
|
||||
} else {
|
||||
Status s;
|
||||
#ifndef ROCKSDB_LITE
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
RegisterBuiltinFileSystems(*(ObjectLibrary::Default().get()), "");
|
||||
});
|
||||
#endif // ROCKSDB_LITE
|
||||
return LoadSharedObject<FileSystem>(config_options, value, nullptr, result);
|
||||
}
|
||||
(void)config_options;
|
||||
s = ObjectRegistry::NewInstance()->NewSharedObject<FileSystem>(value, result);
|
||||
#else
|
||||
(void)config_options;
|
||||
(void)result;
|
||||
s = Status::NotSupported("Cannot load FileSystem in LITE mode", value);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
IOStatus FileSystem::ReuseWritableFile(const std::string& fname,
|
||||
@@ -199,58 +147,4 @@ IOStatus ReadFileToString(FileSystem* fs, const std::string& fname,
|
||||
return s;
|
||||
}
|
||||
|
||||
namespace {
|
||||
static std::unordered_map<std::string, OptionTypeInfo> fs_wrapper_type_info = {
|
||||
#ifndef ROCKSDB_LITE
|
||||
{"target",
|
||||
OptionTypeInfo::AsCustomSharedPtr<FileSystem>(
|
||||
0, OptionVerificationType::kByName, OptionTypeFlags::kDontSerialize)},
|
||||
#endif // ROCKSDB_LITE
|
||||
};
|
||||
} // namespace
|
||||
FileSystemWrapper::FileSystemWrapper(const std::shared_ptr<FileSystem>& t)
|
||||
: target_(t) {
|
||||
RegisterOptions("", &target_, &fs_wrapper_type_info);
|
||||
}
|
||||
|
||||
Status FileSystemWrapper::PrepareOptions(const ConfigOptions& options) {
|
||||
if (target_ == nullptr) {
|
||||
target_ = FileSystem::Default();
|
||||
}
|
||||
return FileSystem::PrepareOptions(options);
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
std::string FileSystemWrapper::SerializeOptions(
|
||||
const ConfigOptions& config_options, const std::string& header) const {
|
||||
auto parent = FileSystem::SerializeOptions(config_options, "");
|
||||
if (config_options.IsShallow() || target_ == nullptr ||
|
||||
target_->IsInstanceOf(FileSystem::kDefaultName())) {
|
||||
return parent;
|
||||
} else {
|
||||
std::string result = header;
|
||||
if (!StartsWith(parent, OptionTypeInfo::kIdPropName())) {
|
||||
result.append(OptionTypeInfo::kIdPropName()).append("=");
|
||||
}
|
||||
result.append(parent);
|
||||
if (!EndsWith(result, config_options.delimiter)) {
|
||||
result.append(config_options.delimiter);
|
||||
}
|
||||
result.append("target=").append(target_->ToString(config_options));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
DirFsyncOptions::DirFsyncOptions() { reason = kDefault; }
|
||||
|
||||
DirFsyncOptions::DirFsyncOptions(std::string file_renamed_new_name) {
|
||||
reason = kFileRenamed;
|
||||
renamed_new_name = file_renamed_new_name;
|
||||
}
|
||||
|
||||
DirFsyncOptions::DirFsyncOptions(FsyncReason fsync_reason) {
|
||||
assert(fsync_reason != kFileRenamed);
|
||||
reason = fsync_reason;
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
-3
@@ -27,9 +27,6 @@ class FileSystemTracingWrapper : public FileSystemWrapper {
|
||||
|
||||
~FileSystemTracingWrapper() override {}
|
||||
|
||||
static const char* kClassName() { return "FileSystemTracing"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
IOStatus NewSequentialFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSSequentialFile>* result,
|
||||
|
||||
Vendored
+7
-11
@@ -141,9 +141,7 @@ class PosixFileSystem : public FileSystem {
|
||||
public:
|
||||
PosixFileSystem();
|
||||
|
||||
static const char* kClassName() { return "PosixFileSystem"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
const char* NickName() const override { return kDefaultName(); }
|
||||
const char* Name() const override { return "Posix File System"; }
|
||||
|
||||
~PosixFileSystem() override {}
|
||||
|
||||
@@ -620,8 +618,7 @@ class PosixFileSystem : public FileSystem {
|
||||
return IOStatus::NotFound();
|
||||
default:
|
||||
assert(err == EIO || err == ENOMEM);
|
||||
return IOStatus::IOError("Unexpected error(" +
|
||||
ROCKSDB_NAMESPACE::ToString(err) +
|
||||
return IOStatus::IOError("Unexpected error(" + ToString(err) +
|
||||
") accessing file `" + fname + "' ");
|
||||
}
|
||||
}
|
||||
@@ -822,12 +819,11 @@ class PosixFileSystem : public FileSystem {
|
||||
errno = ENOLCK;
|
||||
// Note that the thread ID printed is the same one as the one in
|
||||
// posix logger, but posix logger prints it hex format.
|
||||
return IOError(
|
||||
"lock hold by current process, acquire time " +
|
||||
ROCKSDB_NAMESPACE::ToString(prev_info.acquire_time) +
|
||||
" acquiring thread " +
|
||||
ROCKSDB_NAMESPACE::ToString(prev_info.acquiring_thread),
|
||||
fname, errno);
|
||||
return IOError("lock hold by current process, acquire time " +
|
||||
ToString(prev_info.acquire_time) +
|
||||
" acquiring thread " +
|
||||
ToString(prev_info.acquiring_thread),
|
||||
fname, errno);
|
||||
}
|
||||
|
||||
IOStatus result = IOStatus::OK();
|
||||
|
||||
Vendored
-3
@@ -26,9 +26,6 @@ class ReadOnlyFileSystem : public FileSystemWrapper {
|
||||
explicit ReadOnlyFileSystem(const std::shared_ptr<FileSystem>& base)
|
||||
: FileSystemWrapper(base) {}
|
||||
|
||||
static const char* kClassName() { return "ReadOnlyFileSystem"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
IOStatus NewWritableFile(const std::string& /*fname*/,
|
||||
const FileOptions& /*options*/,
|
||||
std::unique_ptr<FSWritableFile>* /*result*/,
|
||||
|
||||
Vendored
-8
@@ -39,14 +39,6 @@ class RemapFileSystem : public FileSystemWrapper {
|
||||
public:
|
||||
// Left abstract:
|
||||
// const char* Name() const override { ... }
|
||||
static const char* kClassName() { return "RemapFileSystem"; }
|
||||
bool IsInstanceOf(const std::string& id) const override {
|
||||
if (id == kClassName()) {
|
||||
return true;
|
||||
} else {
|
||||
return FileSystemWrapper::IsInstanceOf(id);
|
||||
}
|
||||
}
|
||||
|
||||
Status RegisterDbPaths(const std::vector<std::string>& paths) override;
|
||||
|
||||
|
||||
Vendored
+4
-48
@@ -1534,61 +1534,17 @@ PosixMemoryMappedFileBuffer::~PosixMemoryMappedFileBuffer() {
|
||||
/*
|
||||
* PosixDirectory
|
||||
*/
|
||||
#if !defined(BTRFS_SUPER_MAGIC)
|
||||
// The magic number for BTRFS is fixed, if it's not defined, define it here
|
||||
#define BTRFS_SUPER_MAGIC 0x9123683E
|
||||
#endif
|
||||
PosixDirectory::PosixDirectory(int fd) : fd_(fd) {
|
||||
is_btrfs_ = false;
|
||||
#ifdef OS_LINUX
|
||||
struct statfs buf;
|
||||
int ret = fstatfs(fd, &buf);
|
||||
is_btrfs_ = (ret == 0 && buf.f_type == BTRFS_SUPER_MAGIC);
|
||||
#endif
|
||||
}
|
||||
|
||||
PosixDirectory::~PosixDirectory() { close(fd_); }
|
||||
|
||||
IOStatus PosixDirectory::Fsync(const IOOptions& opts, IODebugContext* dbg) {
|
||||
return FsyncWithDirOptions(opts, dbg, DirFsyncOptions());
|
||||
}
|
||||
|
||||
IOStatus PosixDirectory::FsyncWithDirOptions(
|
||||
const IOOptions& /*opts*/, IODebugContext* /*dbg*/,
|
||||
const DirFsyncOptions& dir_fsync_options) {
|
||||
IOStatus s = IOStatus::OK();
|
||||
IOStatus PosixDirectory::Fsync(const IOOptions& /*opts*/,
|
||||
IODebugContext* /*dbg*/) {
|
||||
#ifndef OS_AIX
|
||||
if (is_btrfs_) {
|
||||
// skip dir fsync for new file creation, which is not needed for btrfs
|
||||
if (dir_fsync_options.reason == DirFsyncOptions::kNewFileSynced) {
|
||||
return s;
|
||||
}
|
||||
// skip dir fsync for renaming file, only need to sync new file
|
||||
if (dir_fsync_options.reason == DirFsyncOptions::kFileRenamed) {
|
||||
std::string new_name = dir_fsync_options.renamed_new_name;
|
||||
assert(!new_name.empty());
|
||||
int fd;
|
||||
do {
|
||||
IOSTATS_TIMER_GUARD(open_nanos);
|
||||
fd = open(new_name.c_str(), O_RDONLY);
|
||||
} while (fd < 0 && errno == EINTR);
|
||||
if (fd < 0) {
|
||||
s = IOError("While open renaming file", new_name, errno);
|
||||
} else if (fsync(fd) < 0) {
|
||||
s = IOError("While fsync renaming file", new_name, errno);
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
s = IOError("While closing file after fsync", new_name, errno);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
// fallback to dir-fsync for kDefault, kDirRenamed and kFileDeleted
|
||||
}
|
||||
if (fsync(fd_) == -1) {
|
||||
s = IOError("While fsync", "a directory", errno);
|
||||
return IOError("While fsync", "a directory", errno);
|
||||
}
|
||||
#endif
|
||||
return s;
|
||||
return IOStatus::OK();
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif
|
||||
Vendored
+1
-6
@@ -391,17 +391,12 @@ struct PosixMemoryMappedFileBuffer : public MemoryMappedFileBuffer {
|
||||
|
||||
class PosixDirectory : public FSDirectory {
|
||||
public:
|
||||
explicit PosixDirectory(int fd);
|
||||
explicit PosixDirectory(int fd) : fd_(fd) {}
|
||||
~PosixDirectory();
|
||||
virtual IOStatus Fsync(const IOOptions& opts, IODebugContext* dbg) override;
|
||||
|
||||
virtual IOStatus FsyncWithDirOptions(
|
||||
const IOOptions&, IODebugContext*,
|
||||
const DirFsyncOptions& dir_fsync_options) override;
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
bool is_btrfs_;
|
||||
};
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
+121
-28
@@ -565,39 +565,132 @@ class TestMemLogger : public Logger {
|
||||
}
|
||||
size_t GetLogFileSize() const override { return log_size_; }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
MockFileSystem::MockFileSystem(const std::shared_ptr<SystemClock>& clock,
|
||||
bool supports_direct_io)
|
||||
: system_clock_(clock), supports_direct_io_(supports_direct_io) {
|
||||
clock_ = system_clock_.get();
|
||||
}
|
||||
|
||||
MockFileSystem::~MockFileSystem() {
|
||||
for (auto i = file_map_.begin(); i != file_map_.end(); ++i) {
|
||||
i->second->Unref();
|
||||
class MockFileSystem : public FileSystem {
|
||||
public:
|
||||
explicit MockFileSystem(const std::shared_ptr<SystemClock>& clock,
|
||||
bool supports_direct_io = true)
|
||||
: system_clock_(clock), supports_direct_io_(supports_direct_io) {
|
||||
clock_ = system_clock_.get();
|
||||
}
|
||||
}
|
||||
IOStatus MockFileSystem::GetAbsolutePath(const std::string& db_path,
|
||||
const IOOptions& /*options*/,
|
||||
std::string* output_path,
|
||||
IODebugContext* /*dbg*/) {
|
||||
*output_path = NormalizeMockPath(db_path);
|
||||
if (output_path->at(0) != '/') {
|
||||
return IOStatus::NotSupported("GetAbsolutePath");
|
||||
} else {
|
||||
return IOStatus::OK();
|
||||
}
|
||||
}
|
||||
|
||||
std::string MockFileSystem::NormalizeMockPath(const std::string& path) {
|
||||
std::string p = NormalizePath(path);
|
||||
if (p.back() == kFilePathSeparator && p.size() > 1) {
|
||||
p.pop_back();
|
||||
~MockFileSystem() override {
|
||||
for (auto i = file_map_.begin(); i != file_map_.end(); ++i) {
|
||||
i->second->Unref();
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
const char* Name() const override { return "Memory"; }
|
||||
IOStatus NewSequentialFile(const std::string& f, const FileOptions& file_opts,
|
||||
std::unique_ptr<FSSequentialFile>* r,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewRandomAccessFile(const std::string& f,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* r,
|
||||
IODebugContext* dbg) override;
|
||||
|
||||
IOStatus NewRandomRWFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomRWFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus ReuseWritableFile(const std::string& fname,
|
||||
const std::string& old_fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewWritableFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus ReopenWritableFile(const std::string& fname,
|
||||
const FileOptions& options,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewDirectory(const std::string& /*name*/, const IOOptions& io_opts,
|
||||
std::unique_ptr<FSDirectory>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus FileExists(const std::string& fname, const IOOptions& /*io_opts*/,
|
||||
IODebugContext* /*dbg*/) override;
|
||||
IOStatus GetChildren(const std::string& dir, const IOOptions& options,
|
||||
std::vector<std::string>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus DeleteFile(const std::string& fname, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus Truncate(const std::string& fname, size_t size,
|
||||
const IOOptions& options, IODebugContext* dbg) override;
|
||||
IOStatus CreateDir(const std::string& dirname, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus CreateDirIfMissing(const std::string& dirname,
|
||||
const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus DeleteDir(const std::string& dirname, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
|
||||
IOStatus GetFileSize(const std::string& fname, const IOOptions& options,
|
||||
uint64_t* file_size, IODebugContext* dbg) override;
|
||||
|
||||
IOStatus GetFileModificationTime(const std::string& fname,
|
||||
const IOOptions& options,
|
||||
uint64_t* file_mtime,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus RenameFile(const std::string& src, const std::string& target,
|
||||
const IOOptions& options, IODebugContext* dbg) override;
|
||||
IOStatus LinkFile(const std::string& /*src*/, const std::string& /*target*/,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override;
|
||||
IOStatus LockFile(const std::string& fname, const IOOptions& options,
|
||||
FileLock** lock, IODebugContext* dbg) override;
|
||||
IOStatus UnlockFile(FileLock* lock, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewLogger(const std::string& fname, const IOOptions& io_opts,
|
||||
std::shared_ptr<Logger>* result,
|
||||
IODebugContext* dbg) override;
|
||||
// Get full directory name for this db.
|
||||
IOStatus GetAbsolutePath(const std::string& db_path,
|
||||
const IOOptions& /*options*/,
|
||||
std::string* output_path,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
*output_path = NormalizeMockPath(db_path);
|
||||
if (output_path->at(0) != '/') {
|
||||
return IOStatus::NotSupported("GetAbsolutePath");
|
||||
} else {
|
||||
return IOStatus::OK();
|
||||
}
|
||||
}
|
||||
IOStatus IsDirectory(const std::string& /*path*/,
|
||||
const IOOptions& /*options*/, bool* /*is_dir*/,
|
||||
IODebugContext* /*dgb*/) override {
|
||||
return IOStatus::NotSupported("IsDirectory");
|
||||
}
|
||||
|
||||
Status CorruptBuffer(const std::string& fname);
|
||||
|
||||
private:
|
||||
bool RenameFileInternal(const std::string& src, const std::string& dest);
|
||||
void DeleteFileInternal(const std::string& fname);
|
||||
bool GetChildrenInternal(const std::string& fname,
|
||||
std::vector<std::string>* results);
|
||||
|
||||
std::string NormalizeMockPath(const std::string& path) {
|
||||
std::string p = NormalizePath(path);
|
||||
if (p.back() == kFilePathSeparator && p.size() > 1) {
|
||||
p.pop_back();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
// Map from filenames to MemFile objects, representing a simple file system.
|
||||
port::Mutex mutex_;
|
||||
std::map<std::string, MemFile*> file_map_; // Protected by mutex_.
|
||||
std::shared_ptr<SystemClock> system_clock_;
|
||||
SystemClock* clock_;
|
||||
bool supports_direct_io_;
|
||||
};
|
||||
|
||||
} // Anonymous namespace
|
||||
// Partial implementation of the FileSystem interface.
|
||||
IOStatus MockFileSystem::NewSequentialFile(
|
||||
const std::string& fname, const FileOptions& file_opts,
|
||||
|
||||
Vendored
-106
@@ -14,117 +14,11 @@
|
||||
#include <vector>
|
||||
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/system_clock.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class MemFile;
|
||||
class MockFileSystem : public FileSystem {
|
||||
public:
|
||||
explicit MockFileSystem(const std::shared_ptr<SystemClock>& clock,
|
||||
bool supports_direct_io = true);
|
||||
~MockFileSystem() override;
|
||||
|
||||
static const char* kClassName() { return "MemoryFileSystem"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
IOStatus NewSequentialFile(const std::string& f, const FileOptions& file_opts,
|
||||
std::unique_ptr<FSSequentialFile>* r,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewRandomAccessFile(const std::string& f,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* r,
|
||||
IODebugContext* dbg) override;
|
||||
|
||||
IOStatus NewRandomRWFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomRWFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus ReuseWritableFile(const std::string& fname,
|
||||
const std::string& old_fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewWritableFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus ReopenWritableFile(const std::string& fname,
|
||||
const FileOptions& options,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewDirectory(const std::string& /*name*/, const IOOptions& io_opts,
|
||||
std::unique_ptr<FSDirectory>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus FileExists(const std::string& fname, const IOOptions& /*io_opts*/,
|
||||
IODebugContext* /*dbg*/) override;
|
||||
IOStatus GetChildren(const std::string& dir, const IOOptions& options,
|
||||
std::vector<std::string>* result,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus DeleteFile(const std::string& fname, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus Truncate(const std::string& fname, size_t size,
|
||||
const IOOptions& options, IODebugContext* dbg) override;
|
||||
IOStatus CreateDir(const std::string& dirname, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus CreateDirIfMissing(const std::string& dirname,
|
||||
const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus DeleteDir(const std::string& dirname, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
|
||||
IOStatus GetFileSize(const std::string& fname, const IOOptions& options,
|
||||
uint64_t* file_size, IODebugContext* dbg) override;
|
||||
|
||||
IOStatus GetFileModificationTime(const std::string& fname,
|
||||
const IOOptions& options,
|
||||
uint64_t* file_mtime,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus RenameFile(const std::string& src, const std::string& target,
|
||||
const IOOptions& options, IODebugContext* dbg) override;
|
||||
IOStatus LinkFile(const std::string& /*src*/, const std::string& /*target*/,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override;
|
||||
IOStatus LockFile(const std::string& fname, const IOOptions& options,
|
||||
FileLock** lock, IODebugContext* dbg) override;
|
||||
IOStatus UnlockFile(FileLock* lock, const IOOptions& options,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus GetTestDirectory(const IOOptions& options, std::string* path,
|
||||
IODebugContext* dbg) override;
|
||||
IOStatus NewLogger(const std::string& fname, const IOOptions& io_opts,
|
||||
std::shared_ptr<Logger>* result,
|
||||
IODebugContext* dbg) override;
|
||||
// Get full directory name for this db.
|
||||
IOStatus GetAbsolutePath(const std::string& db_path,
|
||||
const IOOptions& /*options*/,
|
||||
std::string* output_path,
|
||||
IODebugContext* /*dbg*/) override;
|
||||
IOStatus IsDirectory(const std::string& /*path*/,
|
||||
const IOOptions& /*options*/, bool* /*is_dir*/,
|
||||
IODebugContext* /*dgb*/) override {
|
||||
return IOStatus::NotSupported("IsDirectory");
|
||||
}
|
||||
|
||||
Status CorruptBuffer(const std::string& fname);
|
||||
|
||||
private:
|
||||
bool RenameFileInternal(const std::string& src, const std::string& dest);
|
||||
void DeleteFileInternal(const std::string& fname);
|
||||
bool GetChildrenInternal(const std::string& fname,
|
||||
std::vector<std::string>* results);
|
||||
|
||||
std::string NormalizeMockPath(const std::string& path);
|
||||
|
||||
private:
|
||||
// Map from filenames to MemFile objects, representing a simple file system.
|
||||
port::Mutex mutex_;
|
||||
std::map<std::string, MemFile*> file_map_; // Protected by mutex_.
|
||||
std::shared_ptr<SystemClock> system_clock_;
|
||||
SystemClock* clock_;
|
||||
bool supports_direct_io_;
|
||||
};
|
||||
|
||||
class MockEnv : public CompositeEnvWrapper {
|
||||
public:
|
||||
static MockEnv* Create(Env* base);
|
||||
|
||||
@@ -357,9 +357,7 @@ Status DeleteScheduler::DeleteTrashFile(const std::string& path_in_trash,
|
||||
s = fs_->NewDirectory(dir_to_sync, IOOptions(), &dir_obj, nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = dir_obj->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr,
|
||||
DirFsyncOptions(DirFsyncOptions::FsyncReason::kFileDeleted));
|
||||
s = dir_obj->Fsync(IOOptions(), nullptr);
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"DeleteScheduler::DeleteTrashFile::AfterSyncDir",
|
||||
reinterpret_cast<void*>(const_cast<std::string*>(&dir_to_sync)));
|
||||
|
||||
+2
-13
@@ -405,8 +405,7 @@ IOStatus SetCurrentFile(FileSystem* fs, const std::string& dbname,
|
||||
}
|
||||
if (s.ok()) {
|
||||
if (directory_to_fsync != nullptr) {
|
||||
s = directory_to_fsync->FsyncWithDirOptions(
|
||||
IOOptions(), nullptr, DirFsyncOptions(CurrentFileName(dbname)));
|
||||
s = directory_to_fsync->Fsync(IOOptions(), nullptr);
|
||||
}
|
||||
} else {
|
||||
fs->DeleteFile(tmp, IOOptions(), nullptr)
|
||||
@@ -429,19 +428,9 @@ Status SetIdentityFile(Env* env, const std::string& dbname,
|
||||
assert(!id.empty());
|
||||
// Reserve the filename dbname/000000.dbtmp for the temporary identity file
|
||||
std::string tmp = TempFileName(dbname, 0);
|
||||
std::string identify_file_name = IdentityFileName(dbname);
|
||||
Status s = WriteStringToFile(env, id, tmp, true);
|
||||
if (s.ok()) {
|
||||
s = env->RenameFile(tmp, identify_file_name);
|
||||
}
|
||||
std::unique_ptr<FSDirectory> dir_obj;
|
||||
if (s.ok()) {
|
||||
s = env->GetFileSystem()->NewDirectory(dbname, IOOptions(), &dir_obj,
|
||||
nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = dir_obj->FsyncWithDirOptions(IOOptions(), nullptr,
|
||||
DirFsyncOptions(identify_file_name));
|
||||
s = env->RenameFile(tmp, IdentityFileName(dbname));
|
||||
}
|
||||
if (!s.ok()) {
|
||||
env->DeleteFile(tmp).PermitUncheckedError();
|
||||
|
||||
@@ -39,9 +39,6 @@ class MockFS : public FileSystemWrapper {
|
||||
bool support_prefetch)
|
||||
: FileSystemWrapper(wrapped), support_prefetch_(support_prefetch) {}
|
||||
|
||||
static const char* kClassName() { return "MockFS"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
IOStatus NewRandomAccessFile(const std::string& fname,
|
||||
const FileOptions& opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* result,
|
||||
|
||||
@@ -105,14 +105,9 @@ struct CompressionOptions {
|
||||
//
|
||||
// When compression dictionary is disabled, we compress and write each block
|
||||
// before buffering data for the next one. When compression dictionary is
|
||||
// enabled, we buffer SST file data in-memory so we can sample it, as data
|
||||
// enabled, we buffer all SST file data in-memory so we can sample it, as data
|
||||
// can only be compressed and written after the dictionary has been finalized.
|
||||
//
|
||||
// The amount of data buffered can be limited by `max_dict_buffer_bytes`. This
|
||||
// buffered memory is charged to the block cache when there is a block cache.
|
||||
// If block cache insertion fails with `Status::Incomplete` (i.e., it is
|
||||
// full), we finalize the dictionary with whatever data we have and then stop
|
||||
// buffering.
|
||||
// So users of this feature may see increased memory usage.
|
||||
//
|
||||
// Default: 0.
|
||||
uint32_t max_dict_bytes;
|
||||
@@ -312,39 +307,35 @@ struct AdvancedColumnFamilyOptions {
|
||||
// delta_value - Delta value to be merged with the existing_value.
|
||||
// Stored in transaction logs.
|
||||
// merged_value - Set when delta is applied on the previous value.
|
||||
//
|
||||
|
||||
// Applicable only when inplace_update_support is true,
|
||||
// this callback function is called at the time of updating the memtable
|
||||
// as part of a Put operation, lets say Put(key, delta_value). It allows the
|
||||
// 'delta_value' specified as part of the Put operation to be merged with
|
||||
// an 'existing_value' of the key in the database.
|
||||
//
|
||||
|
||||
// If the merged value is smaller in size that the 'existing_value',
|
||||
// then this function can update the 'existing_value' buffer inplace and
|
||||
// the corresponding 'existing_value'_size pointer, if it wishes to.
|
||||
// The callback should return UpdateStatus::UPDATED_INPLACE.
|
||||
// In this case. (In this case, the snapshot-semantics of the rocksdb
|
||||
// Iterator is not atomic anymore).
|
||||
//
|
||||
|
||||
// If the merged value is larger in size than the 'existing_value' or the
|
||||
// application does not wish to modify the 'existing_value' buffer inplace,
|
||||
// then the merged value should be returned via *merge_value. It is set by
|
||||
// merging the 'existing_value' and the Put 'delta_value'. The callback should
|
||||
// return UpdateStatus::UPDATED in this case. This merged value will be added
|
||||
// to the memtable.
|
||||
//
|
||||
|
||||
// If merging fails or the application does not wish to take any action,
|
||||
// then the callback should return UpdateStatus::UPDATE_FAILED.
|
||||
//
|
||||
|
||||
// Please remember that the original call from the application is Put(key,
|
||||
// delta_value). So the transaction log (if enabled) will still contain (key,
|
||||
// delta_value). The 'merged_value' is not stored in the transaction log.
|
||||
// Hence the inplace_callback function should be consistent across db reopens.
|
||||
//
|
||||
// RocksDB callbacks are NOT exception-safe. A callback completing with an
|
||||
// exception can lead to undefined behavior in RocksDB, including data loss,
|
||||
// unreported corruption, deadlocks, and more.
|
||||
//
|
||||
|
||||
// Default: nullptr
|
||||
UpdateStatus (*inplace_callback)(char* existing_value,
|
||||
uint32_t* existing_value_size,
|
||||
|
||||
@@ -170,10 +170,6 @@ class Cache {
|
||||
// The SizeCallback takes a void* pointer to the object and returns the size
|
||||
// of the persistable data. It can be used by the secondary cache to allocate
|
||||
// memory if needed.
|
||||
//
|
||||
// RocksDB callbacks are NOT exception-safe. A callback completing with an
|
||||
// exception can lead to undefined behavior in RocksDB, including data loss,
|
||||
// unreported corruption, deadlocks, and more.
|
||||
using SizeCallback = size_t (*)(void* obj);
|
||||
|
||||
// The SaveToCallback takes a void* object pointer and saves the persistable
|
||||
|
||||
@@ -24,10 +24,7 @@ class SliceTransform;
|
||||
|
||||
// CompactionFilter allows an application to modify/delete a key-value during
|
||||
// table file creation.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
|
||||
class CompactionFilter : public Customizable {
|
||||
public:
|
||||
enum ValueType {
|
||||
@@ -222,10 +219,6 @@ class CompactionFilter : public Customizable {
|
||||
// `CompactionFilter` according to `ShouldFilterTableFileCreation()`. This
|
||||
// allows the application to know about the different ongoing threads of work
|
||||
// and makes it unnecessary for `CompactionFilter` to provide thread-safety.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class CompactionFilterFactory : public Customizable {
|
||||
public:
|
||||
virtual ~CompactionFilterFactory() {}
|
||||
|
||||
@@ -21,10 +21,6 @@ class Slice;
|
||||
// used as keys in an sstable or a database. A Comparator implementation
|
||||
// must be thread-safe since rocksdb may invoke its methods concurrently
|
||||
// from multiple threads.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class Comparator : public Customizable {
|
||||
public:
|
||||
Comparator() : timestamp_size_(0) {}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// This is NOT an extensible interface but a public interface for result of
|
||||
// NewConcurrentTaskLimiter. Any derived classes must be RocksDB internal.
|
||||
class ConcurrentTaskLimiter {
|
||||
public:
|
||||
virtual ~ConcurrentTaskLimiter() {}
|
||||
|
||||
@@ -145,9 +145,6 @@ struct EnvOptions {
|
||||
RateLimiter* rate_limiter = nullptr;
|
||||
};
|
||||
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class Env {
|
||||
public:
|
||||
struct FileAttributes {
|
||||
@@ -1153,10 +1150,6 @@ enum InfoLogLevel : unsigned char {
|
||||
};
|
||||
|
||||
// An interface for writing log messages.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class Logger {
|
||||
public:
|
||||
size_t kDoNotSupportGetLogFileSize = (std::numeric_limits<size_t>::max)();
|
||||
|
||||
@@ -24,9 +24,6 @@ struct ConfigOptions;
|
||||
// read from disk.
|
||||
Env* NewEncryptedEnv(Env* base_env,
|
||||
const std::shared_ptr<EncryptionProvider>& provider);
|
||||
std::shared_ptr<FileSystem> NewEncryptedFS(
|
||||
const std::shared_ptr<FileSystem>& base_fs,
|
||||
const std::shared_ptr<EncryptionProvider>& provider);
|
||||
|
||||
// BlockAccessCipherStream is the base class for any cipher stream that
|
||||
// supports random access at block level (without requiring data from other
|
||||
@@ -62,10 +59,6 @@ class BlockAccessCipherStream {
|
||||
};
|
||||
|
||||
// BlockCipher
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class BlockCipher : public Customizable {
|
||||
public:
|
||||
virtual ~BlockCipher(){};
|
||||
@@ -109,10 +102,6 @@ class BlockCipher : public Customizable {
|
||||
// The encryption provider is used to create a cipher stream for a specific
|
||||
// file. The returned cipher stream will be used for actual
|
||||
// encryption/decryption actions.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class EncryptionProvider : public Customizable {
|
||||
public:
|
||||
virtual ~EncryptionProvider(){};
|
||||
@@ -451,14 +440,6 @@ class EncryptedFileSystem : public FileSystemWrapper {
|
||||
// otherwise
|
||||
virtual Status AddCipher(const std::string& descriptor, const char* cipher,
|
||||
size_t len, bool for_write) = 0;
|
||||
static const char* kClassName() { return "EncryptedFileSystem"; }
|
||||
bool IsInstanceOf(const std::string& name) const override {
|
||||
if (name == kClassName()) {
|
||||
return true;
|
||||
} else {
|
||||
return FileSystemWrapper::IsInstanceOf(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@ struct FileChecksumGenContext {
|
||||
// * Finalize is called at most once during the life of the object
|
||||
// * All calls to Update come before Finalize
|
||||
// * All calls to GetChecksum come after Finalize
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class FileChecksumGenerator {
|
||||
public:
|
||||
virtual ~FileChecksumGenerator() {}
|
||||
@@ -68,10 +64,6 @@ class FileChecksumGenerator {
|
||||
};
|
||||
|
||||
// Create the FileChecksumGenerator object for each SST file.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class FileChecksumGenFactory : public Customizable {
|
||||
public:
|
||||
virtual ~FileChecksumGenFactory() {}
|
||||
@@ -94,10 +86,6 @@ class FileChecksumGenFactory : public Customizable {
|
||||
// the checksum information of all valid SST file of a DB instance. It can
|
||||
// also be used to store the checksum information of a list of SST files to
|
||||
// be ingested.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class FileChecksumList {
|
||||
public:
|
||||
virtual ~FileChecksumList() {}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "rocksdb/customizable.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/io_status.h"
|
||||
#include "rocksdb/options.h"
|
||||
@@ -100,36 +99,7 @@ struct IOOptions {
|
||||
// such as NewRandomAccessFile and NewWritableFile.
|
||||
std::unordered_map<std::string, std::string> property_bag;
|
||||
|
||||
// Force directory fsync, some file systems like btrfs may skip directory
|
||||
// fsync, set this to force the fsync
|
||||
bool force_dir_fsync;
|
||||
|
||||
IOOptions() : IOOptions(false) {}
|
||||
|
||||
explicit IOOptions(bool force_dir_fsync_)
|
||||
: timeout(std::chrono::microseconds::zero()),
|
||||
prio(IOPriority::kIOLow),
|
||||
type(IOType::kUnknown),
|
||||
force_dir_fsync(force_dir_fsync_) {}
|
||||
};
|
||||
|
||||
struct DirFsyncOptions {
|
||||
enum FsyncReason : uint8_t {
|
||||
kNewFileSynced,
|
||||
kFileRenamed,
|
||||
kDirRenamed,
|
||||
kFileDeleted,
|
||||
kDefault,
|
||||
} reason;
|
||||
|
||||
std::string renamed_new_name; // for kFileRenamed
|
||||
// add other options for other FsyncReason
|
||||
|
||||
DirFsyncOptions();
|
||||
|
||||
explicit DirFsyncOptions(std::string file_renamed_new_name);
|
||||
|
||||
explicit DirFsyncOptions(FsyncReason fsync_reason);
|
||||
IOOptions() : timeout(0), prio(IOPriority::kIOLow), type(IOType::kUnknown) {}
|
||||
};
|
||||
|
||||
// File scope options that control how a file is opened/created and accessed
|
||||
@@ -165,7 +135,7 @@ struct FileOptions : EnvOptions {
|
||||
temperature(opts.temperature),
|
||||
handoff_checksum_type(opts.handoff_checksum_type) {}
|
||||
|
||||
FileOptions& operator=(const FileOptions& opts) = default;
|
||||
FileOptions& operator=(const FileOptions&) = default;
|
||||
};
|
||||
|
||||
// A structure to pass back some debugging information from the FileSystem
|
||||
@@ -237,11 +207,7 @@ struct IODebugContext {
|
||||
// retryable.
|
||||
// NewCompositeEnv can be used to create an Env with a custom FileSystem for
|
||||
// DBOptions::env.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class FileSystem : public Customizable {
|
||||
class FileSystem {
|
||||
public:
|
||||
FileSystem();
|
||||
|
||||
@@ -250,8 +216,9 @@ class FileSystem : public Customizable {
|
||||
|
||||
virtual ~FileSystem();
|
||||
|
||||
virtual const char* Name() const = 0;
|
||||
|
||||
static const char* Type() { return "FileSystem"; }
|
||||
static const char* kDefaultName() { return "DefaultFileSystem"; }
|
||||
|
||||
// Loads the FileSystem specified by the input value into the result
|
||||
// The CreateFromString alternative should be used; this method may be
|
||||
@@ -763,11 +730,10 @@ class FSRandomAccessFile {
|
||||
// Read a bunch of blocks as described by reqs. The blocks can
|
||||
// optionally be read in parallel. This is a synchronous call, i.e it
|
||||
// should return after all reads have completed. The reads will be
|
||||
// non-overlapping but can be in any order. If the function return Status
|
||||
// is not ok, status of individual requests will be ignored and return
|
||||
// status will be assumed for all read requests. The function return status
|
||||
// is only meant for errors that occur before processing individual read
|
||||
// requests.
|
||||
// non-overlapping. If the function return Status is not ok, status of
|
||||
// individual requests will be ignored and return status will be assumed
|
||||
// for all read requests. The function return status is only meant for any
|
||||
// any errors that occur before even processing specific read requests
|
||||
virtual IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
|
||||
const IOOptions& options, IODebugContext* dbg) {
|
||||
assert(reqs != nullptr);
|
||||
@@ -1140,15 +1106,6 @@ class FSDirectory {
|
||||
// Fsync directory. Can be called concurrently from multiple threads.
|
||||
virtual IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) = 0;
|
||||
|
||||
// FsyncWithDirOptions after renaming a file. Depends on the filesystem, it
|
||||
// may fsync directory or just the renaming file (e.g. btrfs). By default, it
|
||||
// just calls directory fsync.
|
||||
virtual IOStatus FsyncWithDirOptions(
|
||||
const IOOptions& options, IODebugContext* dbg,
|
||||
const DirFsyncOptions& /*dir_fsync_options*/) {
|
||||
return Fsync(options, dbg);
|
||||
}
|
||||
|
||||
virtual size_t GetUniqueId(char* /*id*/, size_t /*max_size*/) const {
|
||||
return 0;
|
||||
}
|
||||
@@ -1190,9 +1147,12 @@ class FSDirectory {
|
||||
class FileSystemWrapper : public FileSystem {
|
||||
public:
|
||||
// Initialize an EnvWrapper that delegates all calls to *t
|
||||
explicit FileSystemWrapper(const std::shared_ptr<FileSystem>& t);
|
||||
explicit FileSystemWrapper(const std::shared_ptr<FileSystem>& t)
|
||||
: target_(t) {}
|
||||
~FileSystemWrapper() override {}
|
||||
|
||||
const char* Name() const override { return target_->Name(); }
|
||||
|
||||
// Return the target to which this Env forwards all calls
|
||||
FileSystem* target() const { return target_.get(); }
|
||||
|
||||
@@ -1383,13 +1343,7 @@ class FileSystemWrapper : public FileSystem {
|
||||
return target_->IsDirectory(path, options, is_dir, dbg);
|
||||
}
|
||||
|
||||
const Customizable* Inner() const override { return target_.get(); }
|
||||
Status PrepareOptions(const ConfigOptions& options) override;
|
||||
#ifndef ROCKSDB_LITE
|
||||
std::string SerializeOptions(const ConfigOptions& config_options,
|
||||
const std::string& header) const override;
|
||||
#endif // ROCKSDB_LITE
|
||||
protected:
|
||||
private:
|
||||
std::shared_ptr<FileSystem> target_;
|
||||
};
|
||||
|
||||
@@ -1661,13 +1615,6 @@ class FSDirectoryWrapper : public FSDirectory {
|
||||
IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override {
|
||||
return target_->Fsync(options, dbg);
|
||||
}
|
||||
|
||||
IOStatus FsyncWithDirOptions(
|
||||
const IOOptions& options, IODebugContext* dbg,
|
||||
const DirFsyncOptions& dir_fsync_options) override {
|
||||
return target_->FsyncWithDirOptions(options, dbg, dir_fsync_options);
|
||||
}
|
||||
|
||||
size_t GetUniqueId(char* id, size_t max_size) const override {
|
||||
return target_->GetUniqueId(id, max_size);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ struct ConfigOptions;
|
||||
struct Options;
|
||||
|
||||
// FlushBlockPolicy provides a configurable way to determine when to flush a
|
||||
// block in the block based tables.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
// block in the block based tables,
|
||||
class FlushBlockPolicy {
|
||||
public:
|
||||
// Keep track of the key/value sequences and return the boolean value to
|
||||
|
||||
@@ -476,10 +476,6 @@ struct ExternalFileIngestionInfo {
|
||||
// the current thread holding any DB mutex. This is to prevent potential
|
||||
// deadlock and performance issue when using EventListener callback
|
||||
// in a complex way.
|
||||
//
|
||||
// [Exceptions] Exceptions MUST NOT propagate out of overridden functions into
|
||||
// RocksDB, because RocksDB is not exception-safe. This could cause undefined
|
||||
// behavior including data loss, unreported corruption, deadlocks, and more.
|
||||
class EventListener : public Customizable {
|
||||
public:
|
||||
static const char* Type() { return "EventListener"; }
|
||||
|
||||
@@ -44,9 +44,6 @@ class Logger;
|
||||
//
|
||||
// Refer to rocksdb-merge wiki for more details and example implementations.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class MergeOperator : public Customizable {
|
||||
public:
|
||||
virtual ~MergeOperator() {}
|
||||
|
||||
@@ -396,9 +396,6 @@ struct CompactionServiceJobInfo {
|
||||
priority(priority_) {}
|
||||
};
|
||||
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class CompactionService : public Customizable {
|
||||
public:
|
||||
static const char* Type() { return "CompactionService"; }
|
||||
@@ -934,7 +931,7 @@ struct DBOptions {
|
||||
size_t random_access_max_buffer_size = 1024 * 1024;
|
||||
|
||||
// This is the maximum buffer size that is used by WritableFileWriter.
|
||||
// With direct IO, we need to maintain an aligned buffer for writes.
|
||||
// On Windows, we need to maintain an aligned buffer for writes.
|
||||
// We allow the buffer to grow until it's size hits the limit in buffered
|
||||
// IO and fix the buffer size when using direct IO to ensure alignment of
|
||||
// write requests if the logical sector size is unusual
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class RateLimiter {
|
||||
public:
|
||||
enum class OpType {
|
||||
@@ -66,8 +63,7 @@ class RateLimiter {
|
||||
// Requests token to read or write bytes and potentially updates statistics.
|
||||
//
|
||||
// If this request can not be satisfied, the call is blocked. Caller is
|
||||
// responsible to make sure bytes <= GetSingleBurstBytes()
|
||||
// and bytes >= 0.
|
||||
// responsible to make sure bytes <= GetSingleBurstBytes().
|
||||
virtual void Request(const int64_t bytes, const Env::IOPriority pri,
|
||||
Statistics* stats, OpType op_type) {
|
||||
if (IsRateLimited(op_type)) {
|
||||
|
||||
@@ -43,10 +43,6 @@ class SecondaryCacheResultHandle {
|
||||
//
|
||||
// Cache interface for caching blocks on a secondary tier (which can include
|
||||
// non-volatile media, or alternate forms of caching such as compressed data)
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class SecondaryCache : public Customizable {
|
||||
public:
|
||||
virtual ~SecondaryCache() {}
|
||||
|
||||
@@ -25,14 +25,12 @@ namespace ROCKSDB_NAMESPACE {
|
||||
class Slice;
|
||||
struct ConfigOptions;
|
||||
|
||||
// A SliceTransform is a generic pluggable way of transforming one string
|
||||
// to another. Its primary use-case is in configuring rocksdb
|
||||
// to store prefix blooms by setting prefix_extractor in
|
||||
// ColumnFamilyOptions.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
/*
|
||||
* A SliceTransform is a generic pluggable way of transforming one string
|
||||
* to another. Its primary use-case is in configuring rocksdb
|
||||
* to store prefix blooms by setting prefix_extractor in
|
||||
* ColumnFamilyOptions.
|
||||
*/
|
||||
class SliceTransform : public Customizable {
|
||||
public:
|
||||
virtual ~SliceTransform(){};
|
||||
|
||||
@@ -21,8 +21,7 @@ class Logger;
|
||||
|
||||
// SstFileManager is used to track SST and blob files in the DB and control
|
||||
// their deletion rate. All SstFileManager public functions are thread-safe.
|
||||
// SstFileManager is NOT an extensible interface but a public interface for
|
||||
// result of NewSstFileManager. Any derived classes must be RocksDB internal.
|
||||
// SstFileManager is not extensible.
|
||||
class SstFileManager {
|
||||
public:
|
||||
virtual ~SstFileManager() {}
|
||||
|
||||
@@ -78,9 +78,6 @@ class SstPartitioner {
|
||||
};
|
||||
};
|
||||
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class SstPartitionerFactory : public Customizable {
|
||||
public:
|
||||
virtual ~SstPartitionerFactory() {}
|
||||
|
||||
@@ -573,10 +573,6 @@ enum StatsLevel : uint8_t {
|
||||
// options.statistics->getTickerCount(NUMBER_BLOCK_COMPRESSED);
|
||||
// HistogramData hist;
|
||||
// options.statistics->histogramData(FLUSH_TIME, &hist);
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class Statistics : public Customizable {
|
||||
public:
|
||||
virtual ~Statistics() {}
|
||||
|
||||
@@ -49,7 +49,6 @@ enum ChecksumType : char {
|
||||
kCRC32c = 0x1,
|
||||
kxxHash = 0x2,
|
||||
kxxHash64 = 0x3,
|
||||
kXXH3 = 0x4, // Supported since RocksDB 6.27
|
||||
};
|
||||
|
||||
// `PinningTier` is used to specify which tier of block-based tables should
|
||||
@@ -118,10 +117,9 @@ struct BlockBasedTableOptions {
|
||||
// caching as they should now apply to range tombstone and compression
|
||||
// dictionary meta-blocks, in addition to index and filter meta-blocks.
|
||||
//
|
||||
// Whether to put index/filter blocks in the block cache. When false,
|
||||
// each "table reader" object will pre-load index/filter blocks during
|
||||
// table initialization. Index and filter partition blocks always use
|
||||
// block cache regardless of this option.
|
||||
// Indicating if we'd put index/filter blocks to the block cache.
|
||||
// If not specified, each "table reader" object will pre-load index/filter
|
||||
// block during table initialization.
|
||||
bool cache_index_and_filter_blocks = false;
|
||||
|
||||
// If cache_index_and_filter_blocks is enabled, cache index and filter
|
||||
@@ -192,8 +190,6 @@ struct BlockBasedTableOptions {
|
||||
kHashSearch = 0x01,
|
||||
|
||||
// A two-level index implementation. Both levels are binary search indexes.
|
||||
// Second level index blocks ("partitions") use block cache even when
|
||||
// cache_index_and_filter_blocks=false.
|
||||
kTwoLevelIndexSearch = 0x02,
|
||||
|
||||
// Like kBinarySearch, but index also contains first key of each block.
|
||||
@@ -289,8 +285,7 @@ struct BlockBasedTableOptions {
|
||||
// well.
|
||||
// TODO(myabandeh): remove the note above once the limitation is lifted
|
||||
// Use partitioned full filters for each SST file. This option is
|
||||
// incompatible with block-based filters. Filter partition blocks use
|
||||
// block cache even when cache_index_and_filter_blocks=false.
|
||||
// incompatible with block-based filters.
|
||||
bool partition_filters = false;
|
||||
|
||||
// Option to generate Bloom/Ribbon filters that minimize memory
|
||||
|
||||
@@ -80,14 +80,7 @@ extern const std::string kRangeDelBlock;
|
||||
// a collection of callback functions that will be invoked during table
|
||||
// building. It is constructed with TablePropertiesCollectorFactory. The methods
|
||||
// don't need to be thread-safe, as we will create exactly one
|
||||
// TablePropertiesCollector object per table and then call it sequentially.
|
||||
//
|
||||
// Statuses from these callbacks are currently logged when not OK, but
|
||||
// otherwise ignored by RocksDB.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
// TablePropertiesCollector object per table and then call it sequentially
|
||||
class TablePropertiesCollector {
|
||||
public:
|
||||
virtual ~TablePropertiesCollector() {}
|
||||
@@ -140,10 +133,6 @@ class TablePropertiesCollector {
|
||||
|
||||
// Constructs TablePropertiesCollector. Internals create a new
|
||||
// TablePropertiesCollector for each new table
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class TablePropertiesCollectorFactory : public Customizable {
|
||||
public:
|
||||
struct Context {
|
||||
|
||||
@@ -262,10 +262,6 @@ struct CreateBackupOptions {
|
||||
bool flush_before_backup = false;
|
||||
|
||||
// Callback for reporting progress, based on callback_trigger_interval_size.
|
||||
//
|
||||
// RocksDB callbacks are NOT exception-safe. A callback completing with an
|
||||
// exception can lead to undefined behavior in RocksDB, including data loss,
|
||||
// unreported corruption, deadlocks, and more.
|
||||
std::function<void()> progress_callback = []() {};
|
||||
|
||||
// If false, background_thread_cpu_priority is ignored.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#define ROCKSDB_MAJOR 6
|
||||
#define ROCKSDB_MINOR 26
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_PATCH 1
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
@@ -19,10 +19,6 @@ struct ConfigOptions;
|
||||
// WALFilter allows an application to inspect write-ahead-log (WAL)
|
||||
// records or modify their processing on recovery.
|
||||
// Please see the details below.
|
||||
//
|
||||
// Exceptions MUST NOT propagate out of overridden functions into RocksDB,
|
||||
// because RocksDB is not exception-safe. This could cause undefined behavior
|
||||
// including data loss, unreported corruption, deadlocks, and more.
|
||||
class WalFilter : public Customizable {
|
||||
public:
|
||||
static const char* Type() { return "WalFilter"; }
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class CacheReservationManager;
|
||||
|
||||
// Interface to block and signal DB instances, intended for RocksDB
|
||||
// internal use only. Each DB instance contains ptr to StallInterface.
|
||||
// Interface to block and signal DB instances.
|
||||
// Each DB instance contains ptr to StallInterface.
|
||||
class StallInterface {
|
||||
public:
|
||||
virtual ~StallInterface() {}
|
||||
@@ -34,7 +34,7 @@ class StallInterface {
|
||||
virtual void Signal() = 0;
|
||||
};
|
||||
|
||||
class WriteBufferManager final {
|
||||
class WriteBufferManager {
|
||||
public:
|
||||
// Parameters:
|
||||
// _buffer_size: _buffer_size = 0 indicates no limit. Memory won't be capped.
|
||||
|
||||
@@ -50,7 +50,6 @@ NATIVE_JAVA_CLASSES = \
|
||||
org.rocksdb.OptimisticTransactionDB\
|
||||
org.rocksdb.OptimisticTransactionOptions\
|
||||
org.rocksdb.Options\
|
||||
org.rocksdb.OptionsString\
|
||||
org.rocksdb.OptionsUtil\
|
||||
org.rocksdb.PersistentCache\
|
||||
org.rocksdb.PlainTableConfig\
|
||||
@@ -112,7 +111,6 @@ JAVA_TESTS = \
|
||||
org.rocksdb.BlobOptionsTest\
|
||||
org.rocksdb.BlockBasedTableConfigTest\
|
||||
org.rocksdb.BuiltinComparatorTest\
|
||||
org.rocksdb.BytewiseComparatorRegressionTest\
|
||||
org.rocksdb.util.BytewiseComparatorTest\
|
||||
org.rocksdb.util.BytewiseComparatorIntTest\
|
||||
org.rocksdb.CheckPointTest\
|
||||
|
||||
@@ -3837,30 +3837,6 @@ jdouble Java_org_rocksdb_Options_blobGarbageCollectionAgeCutoff(JNIEnv*,
|
||||
return static_cast<jdouble>(opts->blob_garbage_collection_age_cutoff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_Options
|
||||
* Method: setBlobGarbageCollectionForceThreshold
|
||||
* Signature: (JD)V
|
||||
*/
|
||||
void Java_org_rocksdb_Options_setBlobGarbageCollectionForceThreshold(
|
||||
JNIEnv*, jobject, jlong jhandle,
|
||||
jdouble jblob_garbage_collection_force_threshold) {
|
||||
auto* opts = reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle);
|
||||
opts->blob_garbage_collection_force_threshold =
|
||||
static_cast<double>(jblob_garbage_collection_force_threshold);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_Options
|
||||
* Method: blobGarbageCollectionForceThreshold
|
||||
* Signature: (J)D
|
||||
*/
|
||||
jdouble Java_org_rocksdb_Options_blobGarbageCollectionForceThreshold(
|
||||
JNIEnv*, jobject, jlong jhandle) {
|
||||
auto* opts = reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle);
|
||||
return static_cast<jdouble>(opts->blob_garbage_collection_force_threshold);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ROCKSDB_NAMESPACE::ColumnFamilyOptions
|
||||
|
||||
@@ -5569,33 +5545,6 @@ jdouble Java_org_rocksdb_ColumnFamilyOptions_blobGarbageCollectionAgeCutoff(
|
||||
return static_cast<jdouble>(opts->blob_garbage_collection_age_cutoff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyOptions
|
||||
* Method: setBlobGarbageCollectionForceThreshold
|
||||
* Signature: (JD)V
|
||||
*/
|
||||
void Java_org_rocksdb_ColumnFamilyOptions_setBlobGarbageCollectionForceThreshold(
|
||||
JNIEnv*, jobject, jlong jhandle,
|
||||
jdouble jblob_garbage_collection_force_threshold) {
|
||||
auto* opts =
|
||||
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jhandle);
|
||||
opts->blob_garbage_collection_force_threshold =
|
||||
static_cast<double>(jblob_garbage_collection_force_threshold);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_ColumnFamilyOptions
|
||||
* Method: blobGarbageCollectionAgeCutoff
|
||||
* Signature: (J)D
|
||||
*/
|
||||
jdouble
|
||||
Java_org_rocksdb_ColumnFamilyOptions_blobGarbageCollectionForceThreshold(
|
||||
JNIEnv*, jobject, jlong jhandle) {
|
||||
auto* opts =
|
||||
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jhandle);
|
||||
return static_cast<jdouble>(opts->blob_garbage_collection_force_threshold);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// ROCKSDB_NAMESPACE::DBOptions
|
||||
|
||||
|
||||
@@ -16,15 +16,14 @@
|
||||
* Signature: (JJ)J
|
||||
*/
|
||||
jlong Java_org_rocksdb_WriteBufferManager_newWriteBufferManager(
|
||||
JNIEnv* /*env*/, jclass /*jclazz*/, jlong jbuffer_size, jlong jcache_handle,
|
||||
jboolean allow_stall) {
|
||||
JNIEnv* /*env*/, jclass /*jclazz*/, jlong jbuffer_size, jlong jcache_handle) {
|
||||
auto* cache_ptr =
|
||||
reinterpret_cast<std::shared_ptr<ROCKSDB_NAMESPACE::Cache>*>(
|
||||
jcache_handle);
|
||||
auto* write_buffer_manager =
|
||||
new std::shared_ptr<ROCKSDB_NAMESPACE::WriteBufferManager>(
|
||||
std::make_shared<ROCKSDB_NAMESPACE::WriteBufferManager>(
|
||||
jbuffer_size, *cache_ptr, allow_stall));
|
||||
std::make_shared<ROCKSDB_NAMESPACE::WriteBufferManager>(jbuffer_size,
|
||||
*cache_ptr));
|
||||
return reinterpret_cast<jlong>(write_buffer_manager);
|
||||
}
|
||||
|
||||
|
||||
@@ -341,11 +341,8 @@ public abstract class AbstractMutableOptions {
|
||||
return setIntArray(key, value);
|
||||
|
||||
case ENUM:
|
||||
final Optional<CompressionType> compressionType =
|
||||
CompressionType.getFromInternal(valueStr);
|
||||
if (compressionType.isPresent()) {
|
||||
return setEnum(key, compressionType.get());
|
||||
}
|
||||
final CompressionType compressionType = CompressionType.getFromInternal(valueStr);
|
||||
return setEnum(key, compressionType);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(key + " has unknown value type: " + key.getValueType());
|
||||
|
||||
@@ -687,31 +687,6 @@ public interface AdvancedMutableColumnFamilyOptionsInterface<
|
||||
*/
|
||||
double blobGarbageCollectionAgeCutoff();
|
||||
|
||||
/**
|
||||
* If the ratio of garbage in the oldest blob files exceeds this threshold,
|
||||
* targeted compactions are scheduled in order to force garbage collecting
|
||||
* the blob files in question, assuming they are all eligible based on the
|
||||
* value of {@link #blobGarbageCollectionAgeCutoff} above. This option is
|
||||
* currently only supported with leveled compactions.
|
||||
*
|
||||
* Note that {@link #enableBlobGarbageCollection} has to be set in order for this
|
||||
* option to have any effect.
|
||||
*
|
||||
* Default: 1.0
|
||||
*
|
||||
* Dynamically changeable through the SetOptions() API
|
||||
*
|
||||
* @param blobGarbageCollectionForceThreshold new value for the threshold
|
||||
* @return the reference to the current options
|
||||
*/
|
||||
T setBlobGarbageCollectionForceThreshold(double blobGarbageCollectionForceThreshold);
|
||||
|
||||
/**
|
||||
* Get the current value for the {@link #blobGarbageCollectionForceThreshold}
|
||||
* @return the current threshold at which garbage collection of blobs is forced
|
||||
*/
|
||||
double blobGarbageCollectionForceThreshold();
|
||||
|
||||
//
|
||||
// END options for blobs (integrated BlobDB)
|
||||
//
|
||||
|
||||
@@ -1164,39 +1164,6 @@ public class ColumnFamilyOptions extends RocksObject
|
||||
return blobGarbageCollectionAgeCutoff(nativeHandle_);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the ratio of garbage in the oldest blob files exceeds this threshold,
|
||||
* targeted compactions are scheduled in order to force garbage collecting
|
||||
* the blob files in question, assuming they are all eligible based on the
|
||||
* value of {@link #blobGarbageCollectionAgeCutoff} above. This option is
|
||||
* currently only supported with leveled compactions.
|
||||
*
|
||||
* Note that {@link #enableBlobGarbageCollection} has to be set in order for this
|
||||
* option to have any effect.
|
||||
*
|
||||
* Default: 1.0
|
||||
*
|
||||
* Dynamically changeable through the SetOptions() API
|
||||
*
|
||||
* @param blobGarbageCollectionForceThreshold new value for the threshold
|
||||
* @return the reference to the current options
|
||||
*/
|
||||
@Override
|
||||
public ColumnFamilyOptions setBlobGarbageCollectionForceThreshold(
|
||||
final double blobGarbageCollectionForceThreshold) {
|
||||
setBlobGarbageCollectionForceThreshold(nativeHandle_, blobGarbageCollectionForceThreshold);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current value for the {@link #blobGarbageCollectionForceThreshold}
|
||||
* @return the current threshold at which garbage collection of blobs is forced
|
||||
*/
|
||||
@Override
|
||||
public double blobGarbageCollectionForceThreshold() {
|
||||
return blobGarbageCollectionForceThreshold(nativeHandle_);
|
||||
}
|
||||
|
||||
//
|
||||
// END options for blobs (integrated BlobDB)
|
||||
//
|
||||
@@ -1391,9 +1358,6 @@ public class ColumnFamilyOptions extends RocksObject
|
||||
private native void setBlobGarbageCollectionAgeCutoff(
|
||||
final long nativeHandle_, final double blobGarbageCollectionAgeCutoff);
|
||||
private native double blobGarbageCollectionAgeCutoff(final long nativeHandle_);
|
||||
private native void setBlobGarbageCollectionForceThreshold(
|
||||
final long nativeHandle_, final double blobGarbageCollectionForceThreshold);
|
||||
private native double blobGarbageCollectionForceThreshold(final long nativeHandle_);
|
||||
|
||||
// instance variables
|
||||
// NOTE: If you add new member variables, please update the copy constructor above!
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
package org.rocksdb;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Enum CompressionType
|
||||
*
|
||||
@@ -81,13 +79,15 @@ public enum CompressionType {
|
||||
*
|
||||
* @return CompressionType instance (optional)
|
||||
*/
|
||||
public static Optional<CompressionType> getFromInternal(final String internalName) {
|
||||
static CompressionType getFromInternal(final String internalName) {
|
||||
for (final CompressionType compressionType : CompressionType.values()) {
|
||||
if (compressionType.internalName_.equals(internalName)) {
|
||||
return Optional.of(compressionType);
|
||||
return compressionType;
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal internalName '" + internalName + " ' provided for CompressionType.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -119,8 +119,7 @@ public class MutableColumnFamilyOptions
|
||||
blob_file_size(ValueType.LONG),
|
||||
blob_compression_type(ValueType.ENUM),
|
||||
enable_blob_garbage_collection(ValueType.BOOLEAN),
|
||||
blob_garbage_collection_age_cutoff(ValueType.DOUBLE),
|
||||
blob_garbage_collection_force_threshold(ValueType.DOUBLE);
|
||||
blob_garbage_collection_age_cutoff(ValueType.DOUBLE);
|
||||
|
||||
private final ValueType valueType;
|
||||
BlobOption(final ValueType valueType) {
|
||||
@@ -547,17 +546,5 @@ public class MutableColumnFamilyOptions
|
||||
public double blobGarbageCollectionAgeCutoff() {
|
||||
return getDouble(BlobOption.blob_garbage_collection_age_cutoff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutableColumnFamilyOptionsBuilder setBlobGarbageCollectionForceThreshold(
|
||||
final double blobGarbageCollectionForceThreshold) {
|
||||
return setDouble(
|
||||
BlobOption.blob_garbage_collection_force_threshold, blobGarbageCollectionForceThreshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double blobGarbageCollectionForceThreshold() {
|
||||
return getDouble(BlobOption.blob_garbage_collection_force_threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2077,7 +2077,7 @@ public class Options extends RocksObject
|
||||
}
|
||||
|
||||
@Override
|
||||
public Options setBlobGarbageCollectionAgeCutoff(final double blobGarbageCollectionAgeCutoff) {
|
||||
public Options setBlobGarbageCollectionAgeCutoff(double blobGarbageCollectionAgeCutoff) {
|
||||
setBlobGarbageCollectionAgeCutoff(nativeHandle_, blobGarbageCollectionAgeCutoff);
|
||||
return this;
|
||||
}
|
||||
@@ -2087,18 +2087,6 @@ public class Options extends RocksObject
|
||||
return blobGarbageCollectionAgeCutoff(nativeHandle_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Options setBlobGarbageCollectionForceThreshold(
|
||||
final double blobGarbageCollectionForceThreshold) {
|
||||
setBlobGarbageCollectionForceThreshold(nativeHandle_, blobGarbageCollectionForceThreshold);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double blobGarbageCollectionForceThreshold() {
|
||||
return blobGarbageCollectionForceThreshold(nativeHandle_);
|
||||
}
|
||||
|
||||
//
|
||||
// END options for blobs (integrated BlobDB)
|
||||
//
|
||||
@@ -2529,11 +2517,8 @@ public class Options extends RocksObject
|
||||
final long nativeHandle_, final boolean enableBlobGarbageCollection);
|
||||
private native boolean enableBlobGarbageCollection(final long nativeHandle_);
|
||||
private native void setBlobGarbageCollectionAgeCutoff(
|
||||
final long nativeHandle_, final double blobGarbageCollectionAgeCutoff);
|
||||
final long nativeHandle_, double blobGarbageCollectionAgeCutoff);
|
||||
private native double blobGarbageCollectionAgeCutoff(final long nativeHandle_);
|
||||
private native void setBlobGarbageCollectionForceThreshold(
|
||||
final long nativeHandle_, final double blobGarbageCollectionForceThreshold);
|
||||
private native double blobGarbageCollectionForceThreshold(final long nativeHandle_);
|
||||
|
||||
// instance variables
|
||||
// NOTE: If you add new member variables, please update the copy constructor above!
|
||||
|
||||
Loaded 100 of 155 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user