mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-07 11:32:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5997edef44 | ||
|
|
1ab38a19df | ||
|
|
9b2b87ec15 | ||
|
|
1fe5ac3468 | ||
|
|
3efc6fd641 | ||
|
|
3a3f4801d0 | ||
|
|
87b20cbba0 | ||
|
|
c2c92f3013 |
No files matched your search
+11
-20
@@ -5,9 +5,9 @@ orbs:
|
||||
slack: circleci/slack@3.4.2
|
||||
|
||||
aliases:
|
||||
- ¬ify-on-main-failure
|
||||
- ¬ify-on-master-failure
|
||||
fail_only: true
|
||||
only_for_branches: main
|
||||
only_for_branches: master
|
||||
|
||||
commands:
|
||||
install-pyenv-on-macos:
|
||||
@@ -60,7 +60,7 @@ commands:
|
||||
|
||||
post-steps:
|
||||
steps:
|
||||
- slack/status: *notify-on-main-failure
|
||||
- slack/status: *notify-on-master-failure
|
||||
- store_test_results: # store test result if there's any
|
||||
path: /tmp/test-results
|
||||
- store_artifacts: # store LOG for debugging if there's any
|
||||
@@ -98,13 +98,6 @@ commands:
|
||||
command: |
|
||||
sudo apt-get update -y && sudo apt-get install -y libbenchmark-dev
|
||||
|
||||
install-librados:
|
||||
steps:
|
||||
- run:
|
||||
name: Install librados
|
||||
command: |
|
||||
sudo apt-get update -y && sudo apt-get install -y librados-dev
|
||||
|
||||
upgrade-cmake:
|
||||
steps:
|
||||
- run:
|
||||
@@ -178,15 +171,14 @@ jobs:
|
||||
- run: make V=1 J=32 -j32 check | .circleci/cat_ignore_eagain
|
||||
- post-steps
|
||||
|
||||
build-linux-mem-env-librados:
|
||||
build-linux-mem-env:
|
||||
machine:
|
||||
image: ubuntu-1604:202104-01
|
||||
resource_class: 2xlarge
|
||||
steps:
|
||||
- pre-steps
|
||||
- install-gflags
|
||||
- install-librados
|
||||
- run: MEM_ENV=1 ROCKSDB_USE_LIBRADOS=1 make V=1 J=32 -j32 check | .circleci/cat_ignore_eagain
|
||||
- run: MEM_ENV=1 make V=1 J=32 -j32 check | .circleci/cat_ignore_eagain
|
||||
- post-steps
|
||||
|
||||
build-linux-encrypted-env:
|
||||
@@ -336,7 +328,7 @@ jobs:
|
||||
- run: (mkdir build && cd build && cmake -DWITH_GFLAGS=1 -DWITH_BENCHMARK=1 .. && make V=1 -j20 && ctest -j20 && make microbench) | .circleci/cat_ignore_eagain
|
||||
- post-steps
|
||||
|
||||
build-linux-unity-and-headers:
|
||||
build-linux-unity:
|
||||
docker: # executor type
|
||||
- image: gcc:latest
|
||||
resource_class: large
|
||||
@@ -344,7 +336,6 @@ jobs:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: apt-get update -y && apt-get install -y libgflags-dev
|
||||
- run: TEST_TMPDIR=/dev/shm && make V=1 -j8 unity_test | .circleci/cat_ignore_eagain
|
||||
- run: make V=1 -j8 -k check-headers | .circleci/cat_ignore_eagain # could be moved to a different build
|
||||
- post-steps
|
||||
|
||||
build-linux-gcc-4_8-no_test_run:
|
||||
@@ -706,9 +697,9 @@ workflows:
|
||||
jobs:
|
||||
- build-linux-cmake
|
||||
- build-linux-cmake-ubuntu-20
|
||||
build-linux-mem-env-librados:
|
||||
build-linux-mem-env:
|
||||
jobs:
|
||||
- build-linux-mem-env-librados
|
||||
- build-linux-mem-env
|
||||
build-linux-encrypted-env:
|
||||
jobs:
|
||||
- build-linux-encrypted-env
|
||||
@@ -739,9 +730,9 @@ workflows:
|
||||
build-linux-clang10-clang-analyze:
|
||||
jobs:
|
||||
- build-linux-clang10-clang-analyze
|
||||
build-linux-unity-and-headers:
|
||||
build-linux-unity:
|
||||
jobs:
|
||||
- build-linux-unity-and-headers
|
||||
- build-linux-unity
|
||||
build-windows-vs2019:
|
||||
jobs:
|
||||
- build-windows:
|
||||
@@ -810,7 +801,7 @@ workflows:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
- master
|
||||
jobs:
|
||||
- build-format-compatible
|
||||
- build-linux-arm-test-full
|
||||
@@ -39,6 +39,3 @@ jobs:
|
||||
|
||||
- name: Compare buckify output
|
||||
run: make check-buck-targets
|
||||
|
||||
- name: Simple source code checks
|
||||
run: make check-sources
|
||||
@@ -624,7 +624,6 @@ find_package(Threads REQUIRED)
|
||||
set(SOURCES
|
||||
cache/cache.cc
|
||||
cache/cache_entry_roles.cc
|
||||
cache/cache_reservation_manager.cc
|
||||
cache/clock_cache.cc
|
||||
cache/lru_cache.cc
|
||||
cache/sharded_cache.cc
|
||||
@@ -713,7 +712,6 @@ set(SOURCES
|
||||
env/file_system_tracer.cc
|
||||
env/fs_remap.cc
|
||||
env/mock_env.cc
|
||||
env/unique_id.cc
|
||||
file/delete_scheduler.cc
|
||||
file/file_prefetch_buffer.cc
|
||||
file/file_util.cc
|
||||
@@ -836,7 +834,6 @@ set(SOURCES
|
||||
util/random.cc
|
||||
util/rate_limiter.cc
|
||||
util/ribbon_config.cc
|
||||
util/regex.cc
|
||||
util/slice.cc
|
||||
util/file_checksum_helper.cc
|
||||
util/status.cc
|
||||
@@ -1126,7 +1123,6 @@ if(WITH_TESTS)
|
||||
)
|
||||
if(WITH_ALL_TESTS)
|
||||
list(APPEND TESTS
|
||||
cache/cache_reservation_manager_test.cc
|
||||
cache/cache_test.cc
|
||||
cache/lru_cache_test.cc
|
||||
db/blob/blob_counting_iterator_test.cc
|
||||
|
||||
+7
-53
@@ -1,57 +1,11 @@
|
||||
# Rocksdb Change Log
|
||||
## 6.25.3 (2021-10-14)
|
||||
## 6.24.2 (2021-09-16)
|
||||
### Bug Fixes
|
||||
* Fixed bug in calls to `IngestExternalFiles()` with files for multiple column families. The bug could have introduced a delay in ingested file keys becoming visible after `IngestExternalFiles()` returned. Furthermore, mutations to ingested file keys while they were invisible could have been dropped (not necessarily immediately).
|
||||
* Fixed a possible race condition impacting users of `WriteBufferManager` who constructed it with `allow_stall == true`. The race condition led to undefined behavior (in our experience, typically a process crash).
|
||||
* Fixed a bug where stalled writes would remain stalled forever after the user calls `WriteBufferManager::SetBufferSize()` with `new_size == 0` to dynamically disable memory limiting.
|
||||
|
||||
## 6.25.2 (2021-10-11)
|
||||
### Bug Fixes
|
||||
* Fix `DisableManualCompaction()` to cancel compactions even when they are waiting on automatic compactions to drain due to `CompactRangeOptions::exclusive_manual_compactions == true`.
|
||||
* Fix contract of `Env::ReopenWritableFile()` and `FileSystem::ReopenWritableFile()` to specify any existing file must not be deleted or truncated.
|
||||
|
||||
## 6.25.1 (2021-09-28)
|
||||
### Bug Fixes
|
||||
* Fixes a bug in directed IO mode when calling MultiGet() for blobs in the same blob file. The bug is caused by not sorting the blob read requests by file offsets.
|
||||
|
||||
## 6.25.0 (2021-09-20)
|
||||
### Bug Fixes
|
||||
* Allow secondary instance to refresh iterator. Assign read seq after referencing SuperVersion.
|
||||
* Fixed a bug of secondary instance's last_sequence going backward, and reads on the secondary fail to see recent updates from the primary.
|
||||
* Fixed a bug that could lead to duplicate DB ID or DB session ID in POSIX environments without /proc/sys/kernel/random/uuid.
|
||||
* Fix a race in DumpStats() with column family destruction due to not taking a Ref on each entry while iterating the ColumnFamilySet.
|
||||
* Fix a race in item ref counting in LRUCache when promoting an item from the SecondaryCache.
|
||||
* Fix a race in BackupEngine if RateLimiter is reconfigured during concurrent Restore operations.
|
||||
* Fix a bug on POSIX in which failure to create a lock file (e.g. out of space) can prevent future LockFile attempts in the same process on the same file from succeeding.
|
||||
* Fix a bug that backup_rate_limiter and restore_rate_limiter in BackupEngine could not limit read rates.
|
||||
* Fix the implementation of `prepopulate_block_cache = kFlushOnly` to only apply to flushes rather than to all generated files.
|
||||
* Fix WAL log data corruption when using DBOptions.manual_wal_flush(true) and WriteOptions.sync(true) together. The sync WAL should work with locked log_write_mutex_.
|
||||
* Add checks for validity of the IO uring completion queue entries, and fail the BlockBasedTableReader MultiGet sub-batch if there's an invalid completion
|
||||
* Add an interface RocksDbIOUringEnable() that, if defined by the user, will allow them to enable/disable the use of IO uring by RocksDB
|
||||
* Fix the bug that when direct I/O is used and MultiRead() returns a short result, RandomAccessFileReader::MultiRead() still returns full size buffer, with returned short value together with some data in original buffer. This bug is unlikely cause incorrect results, because (1) since FileSystem layer is expected to retry on short result, returning short results is only possible when asking more bytes in the end of the file, which RocksDB doesn't do when using MultiRead(); (2) checksum is unlikely to match.
|
||||
|
||||
### New Features
|
||||
* RemoteCompaction's interface now includes `db_name`, `db_id`, `session_id`, which could help the user uniquely identify compaction job between db instances and sessions.
|
||||
* Added a ticker statistic, "rocksdb.verify_checksum.read.bytes", reporting how many bytes were read from file to serve `VerifyChecksum()` and `VerifyFileChecksums()` queries.
|
||||
* Added ticker statistics, "rocksdb.backup.read.bytes" and "rocksdb.backup.write.bytes", reporting how many bytes were read and written during backup.
|
||||
* Added properties for BlobDB: `rocksdb.num-blob-files`, `rocksdb.blob-stats`, `rocksdb.total-blob-file-size`, and `rocksdb.live-blob-file-size`. The existing property `rocksdb.estimate_live-data-size` was also extended to include live bytes residing in blob files.
|
||||
* Added two new RateLimiter IOPriorities: `Env::IO_USER`,`Env::IO_MID`. `Env::IO_USER` will have superior priority over all other RateLimiter IOPriorities without being subject to fair scheduling constraint.
|
||||
* `SstFileWriter` now supports `Put`s and `Delete`s with user-defined timestamps. Note that the ingestion logic itself is not timestamp-aware yet.
|
||||
* Allow a single write batch to include keys from multiple column families whose timestamps' formats can differ. For example, some column families may disable timestamp, while others enable timestamp.
|
||||
* Add compaction priority information in RemoteCompaction, which can be used to schedule high priority job first.
|
||||
* Added new callback APIs `OnBlobFileCreationStarted`,`OnBlobFileCreated`and `OnBlobFileDeleted` in `EventListener` class of listener.h. It notifies listeners during creation/deletion of individual blob files in Integrated BlobDB. It also log blob file creation finished event and deletion event in LOG file.
|
||||
* Batch blob read requests for `DB::MultiGet` using `MultiRead`.
|
||||
* Add support for fallback to local compaction, the user can return `CompactionServiceJobStatus::kUseLocal` to instruct RocksDB to run the compaction locally instead of waiting for the remote compaction result.
|
||||
* Add built-in rate limiter's implementation of `RateLimiter::GetTotalPendingRequest(int64_t* total_pending_requests, const Env::IOPriority pri)` for the total number of requests that are pending for bytes in the rate limiter.
|
||||
* Charge memory usage during data buffering, from which training samples are gathered for dictionary compression, to block cache. Unbuffering data can now be triggered if the block cache becomes full and `strict_capacity_limit=true` for the block cache, in addition to existing conditions that can trigger unbuffering.
|
||||
|
||||
### Public API change
|
||||
* Remove obsolete implementation details FullKey and ParseFullKey from public API
|
||||
* Change `SstFileMetaData::size` from `size_t` to `uint64_t`.
|
||||
* Made Statistics extend the Customizable class and added a CreateFromString method. Implementations of Statistics need to be registered with the ObjectRegistry and to implement a Name() method in order to be created via this method.
|
||||
* Extended `FlushJobInfo` and `CompactionJobInfo` in listener.h to provide information about the blob files generated by a flush/compaction and garbage collected during compaction in Integrated BlobDB. Added struct members `blob_file_addition_infos` and `blob_file_garbage_infos` that contain this information.
|
||||
* Extended parameter `output_file_names` of `CompactFiles` API to also include paths of the blob files generated by the compaction in Integrated BlobDB.
|
||||
* Most `BackupEngine` functions now return `IOStatus` instead of `Status`. Most existing code should be compatible with this change but some calls might need to be updated.
|
||||
## 6.24.1 (2021-08-31)
|
||||
### Bug Fixes
|
||||
* Fix a race in item ref counting in LRUCache when promoting an item from the SecondaryCache.
|
||||
|
||||
## 6.24.0 (2021-08-20)
|
||||
### Bug Fixes
|
||||
@@ -63,7 +17,7 @@
|
||||
* Fixed a bug affecting the batched `MultiGet` API when used with keys spanning multiple column families and `sorted_input == false`.
|
||||
* Fixed a potential incorrect result in opt mode and assertion failures caused by releasing snapshot(s) during compaction.
|
||||
* Fixed passing of BlobFileCompletionCallback to Compaction job and Atomic flush job which was default paramter (nullptr). BlobFileCompletitionCallback is internal callback that manages addition of blob files to SSTFileManager.
|
||||
* Fixed MultiGet not updating the block_read_count and block_read_byte PerfContext counters.
|
||||
* Fixed MultiGet not updating the block_read_count and block_read_byte PerfContext counters
|
||||
|
||||
### New Features
|
||||
* Made the EventListener extend the Customizable class.
|
||||
@@ -74,8 +28,8 @@
|
||||
* Add a comment to suggest btrfs user to disable file preallocation by setting `options.allow_fallocate=false`.
|
||||
* Fast forward option in Trace replay changed to double type to allow replaying at a lower speed, by settings the value between 0 and 1. This option can be set via `ReplayOptions` in `Replayer::Replay()`, or via `--trace_replay_fast_forward` in db_bench.
|
||||
* Add property `LiveSstFilesSizeAtTemperature` to retrieve sst file size at different temperature.
|
||||
* Added a stat rocksdb.secondary.cache.hits.
|
||||
* Added a PerfContext counter secondary_cache_hit_count.
|
||||
* Added a stat rocksdb.secondary.cache.hits
|
||||
* Added a PerfContext counter secondary_cache_hit_count
|
||||
* The integrated BlobDB implementation now supports the tickers `BLOB_DB_BLOB_FILE_BYTES_READ`, `BLOB_DB_GC_NUM_KEYS_RELOCATED`, and `BLOB_DB_GC_BYTES_RELOCATED`, as well as the histograms `BLOB_DB_COMPRESSION_MICROS` and `BLOB_DB_DECOMPRESSION_MICROS`.
|
||||
* Added hybrid configuration of Ribbon filter and Bloom filter where some LSM levels use Ribbon for memory space efficiency and some use Bloom for speed. See NewRibbonFilterPolicy. This also changes the default behavior of NewRibbonFilterPolicy to use Bloom for flushes under Leveled and Universal compaction and Ribbon otherwise. The C API function `rocksdb_filterpolicy_create_ribbon` is unchanged but adds new `rocksdb_filterpolicy_create_ribbon_hybrid`.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
This is the list of all known third-party language bindings for RocksDB. If something is missing, please open a pull request to add it.
|
||||
|
||||
* Java - https://github.com/facebook/rocksdb/tree/main/java
|
||||
* Java - https://github.com/facebook/rocksdb/tree/master/java
|
||||
* Python
|
||||
* http://python-rocksdb.readthedocs.io/en/latest/
|
||||
* http://pyrocksdb.readthedocs.org/en/latest/ (unmaintained)
|
||||
|
||||
@@ -222,7 +222,6 @@ am__v_AR_1 =
|
||||
|
||||
ifdef ROCKSDB_USE_LIBRADOS
|
||||
LIB_SOURCES += utilities/env_librados.cc
|
||||
TEST_MAIN_SOURCES += utilities/env_librados_test.cc
|
||||
LDFLAGS += -lrados
|
||||
endif
|
||||
|
||||
@@ -517,29 +516,6 @@ ifeq ($(USE_FOLLY_DISTRIBUTED_MUTEX),1)
|
||||
ALL_SOURCES += third-party/folly/folly/synchronization/test/DistributedMutexTest.cc
|
||||
endif
|
||||
|
||||
# `make check-headers` to very that each header file includes its own
|
||||
# dependencies
|
||||
ifneq ($(filter check-headers, $(MAKECMDGOALS)),)
|
||||
# TODO: add/support JNI headers
|
||||
DEV_HEADER_DIRS := $(sort include/ hdfs/ $(dir $(ALL_SOURCES)))
|
||||
# Some headers like in port/ are platform-specific
|
||||
DEV_HEADERS := $(shell $(FIND) $(DEV_HEADER_DIRS) -type f -name '*.h' | egrep -v 'port/|plugin/|lua/|range_tree/|tools/rdb/db_wrapper.h|include/rocksdb/utilities/env_librados.h')
|
||||
else
|
||||
DEV_HEADERS :=
|
||||
endif
|
||||
HEADER_OK_FILES = $(patsubst %.h, %.h.ok, $(DEV_HEADERS))
|
||||
|
||||
AM_V_CCH = $(am__v_CCH_$(V))
|
||||
am__v_CCH_ = $(am__v_CCH_$(AM_DEFAULT_VERBOSITY))
|
||||
am__v_CCH_0 = @echo " CC.h " $<;
|
||||
am__v_CCH_1 =
|
||||
|
||||
%.h.ok: %.h # .h.ok not actually created, so re-checked on each invocation
|
||||
# -DROCKSDB_NAMESPACE=42 ensures the namespace header is included
|
||||
$(AM_V_CCH) echo '#include "$<"' | $(CXX) $(CXXFLAGS) -DROCKSDB_NAMESPACE=42 -x c++ -c - -o /dev/null
|
||||
|
||||
check-headers: $(HEADER_OK_FILES)
|
||||
|
||||
# options_settable_test doesn't pass with UBSAN as we use hack in the test
|
||||
ifdef COMPILE_WITH_UBSAN
|
||||
TESTS := $(shell echo $(TESTS) | sed 's/\boptions_settable_test\b//g')
|
||||
@@ -740,7 +716,7 @@ endif # PLATFORM_SHARED_EXT
|
||||
.PHONY: blackbox_crash_test check clean coverage crash_test ldb_tests package \
|
||||
release tags tags0 valgrind_check whitebox_crash_test format static_lib shared_lib all \
|
||||
dbg rocksdbjavastatic rocksdbjava gen-pc install install-static install-shared uninstall \
|
||||
analyze tools tools_lib check-headers \
|
||||
analyze tools tools_lib \
|
||||
blackbox_crash_test_with_atomic_flush whitebox_crash_test_with_atomic_flush \
|
||||
blackbox_crash_test_with_txn whitebox_crash_test_with_txn \
|
||||
blackbox_crash_test_with_best_efforts_recovery \
|
||||
@@ -967,7 +943,6 @@ endif
|
||||
ifndef SKIP_FORMAT_BUCK_CHECKS
|
||||
$(MAKE) check-format
|
||||
$(MAKE) check-buck-targets
|
||||
$(MAKE) check-sources
|
||||
endif
|
||||
|
||||
# TODO add ldb_tests
|
||||
@@ -1245,9 +1220,6 @@ check-format:
|
||||
check-buck-targets:
|
||||
buckifier/check_buck_targets.sh
|
||||
|
||||
check-sources:
|
||||
build_tools/check-sources.sh
|
||||
|
||||
package:
|
||||
bash build_tools/make_package.sh $(SHARED_MAJOR).$(SHARED_MINOR)
|
||||
|
||||
@@ -1926,8 +1898,6 @@ clipping_iterator_test: $(OBJ_DIR)/db/compaction/clipping_iterator_test.o $(TEST
|
||||
ribbon_bench: $(OBJ_DIR)/microbench/ribbon_bench.o $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
cache_reservation_manager_test: $(OBJ_DIR)/cache/cache_reservation_manager_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
#-------------------------------------------------
|
||||
# make install related stuff
|
||||
PREFIX ?= /usr/local
|
||||
@@ -2392,7 +2362,7 @@ build_subset_tests: $(ROCKSDBTESTS_SUBSET)
|
||||
|
||||
# Remove the rules for which dependencies should not be generated and see if any are left.
|
||||
#If so, include the dependencies; if not, do not include the dependency files
|
||||
ROCKS_DEP_RULES=$(filter-out clean format check-format check-buck-targets check-headers check-sources jclean jtest package analyze tags rocksdbjavastatic% unity.% unity_test, $(MAKECMDGOALS))
|
||||
ROCKS_DEP_RULES=$(filter-out clean format check-format check-buck-targets jclean jtest package analyze tags rocksdbjavastatic% unity.% unity_test, $(MAKECMDGOALS))
|
||||
ifneq ("$(ROCKS_DEP_RULES)", "")
|
||||
-include $(DEPFILES)
|
||||
endif
|
||||
@@ -1,8 +1,8 @@
|
||||
## RocksDB: A Persistent Key-Value Store for Flash and RAM Storage
|
||||
|
||||
[](https://circleci.com/gh/facebook/rocksdb)
|
||||
[](https://travis-ci.com/github/facebook/rocksdb)
|
||||
[](https://ci.appveyor.com/project/Facebook/rocksdb/branch/main)
|
||||
[](https://travis-ci.org/facebook/rocksdb)
|
||||
[](https://ci.appveyor.com/project/Facebook/rocksdb/branch/master)
|
||||
[](http://140-211-168-68-openstack.osuosl.org:8080/job/rocksdb)
|
||||
|
||||
RocksDB is developed and maintained by Facebook Database Engineering Team.
|
||||
@@ -17,7 +17,7 @@ and Space-Amplification-Factor (SAF). It has multi-threaded compactions,
|
||||
making it especially suitable for storing multiple terabytes of data in a
|
||||
single database.
|
||||
|
||||
Start with example usage here: https://github.com/facebook/rocksdb/tree/main/examples
|
||||
Start with example usage here: https://github.com/facebook/rocksdb/tree/master/examples
|
||||
|
||||
See the [github wiki](https://github.com/facebook/rocksdb/wiki) for more explanation.
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ cpp_library(
|
||||
srcs = [
|
||||
"cache/cache.cc",
|
||||
"cache/cache_entry_roles.cc",
|
||||
"cache/cache_reservation_manager.cc",
|
||||
"cache/clock_cache.cc",
|
||||
"cache/lru_cache.cc",
|
||||
"cache/sharded_cache.cc",
|
||||
@@ -225,7 +224,6 @@ cpp_library(
|
||||
"env/fs_remap.cc",
|
||||
"env/io_posix.cc",
|
||||
"env/mock_env.cc",
|
||||
"env/unique_id.cc",
|
||||
"file/delete_scheduler.cc",
|
||||
"file/file_prefetch_buffer.cc",
|
||||
"file/file_util.cc",
|
||||
@@ -355,7 +353,6 @@ cpp_library(
|
||||
"util/murmurhash.cc",
|
||||
"util/random.cc",
|
||||
"util/rate_limiter.cc",
|
||||
"util/regex.cc",
|
||||
"util/ribbon_config.cc",
|
||||
"util/slice.cc",
|
||||
"util/status.cc",
|
||||
@@ -455,7 +452,6 @@ cpp_library(
|
||||
srcs = [
|
||||
"cache/cache.cc",
|
||||
"cache/cache_entry_roles.cc",
|
||||
"cache/cache_reservation_manager.cc",
|
||||
"cache/clock_cache.cc",
|
||||
"cache/lru_cache.cc",
|
||||
"cache/sharded_cache.cc",
|
||||
@@ -547,7 +543,6 @@ cpp_library(
|
||||
"env/fs_remap.cc",
|
||||
"env/io_posix.cc",
|
||||
"env/mock_env.cc",
|
||||
"env/unique_id.cc",
|
||||
"file/delete_scheduler.cc",
|
||||
"file/file_prefetch_buffer.cc",
|
||||
"file/file_util.cc",
|
||||
@@ -677,7 +672,6 @@ cpp_library(
|
||||
"util/murmurhash.cc",
|
||||
"util/random.cc",
|
||||
"util/rate_limiter.cc",
|
||||
"util/regex.cc",
|
||||
"util/ribbon_config.cc",
|
||||
"util/slice.cc",
|
||||
"util/status.cc",
|
||||
@@ -1031,13 +1025,6 @@ ROCKS_TESTS = [
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"cache_reservation_manager_test",
|
||||
"cache/cache_reservation_manager_test.cc",
|
||||
"parallel",
|
||||
[],
|
||||
[],
|
||||
],
|
||||
[
|
||||
"cache_simulator_test",
|
||||
"utilities/simulator_cache/cache_simulator_test.cc",
|
||||
|
||||
@@ -115,12 +115,3 @@ LzLabs is using RocksDB as a storage engine in their multi-database distributed
|
||||
## ArangoDB
|
||||
[ArangoDB](https://www.arangodb.com/) is a native multi-model database with flexible data models for documents, graphs, and key-values, for building high performance applications using a convenient SQL-like query language or JavaScript extensions. It uses RocksDB as its sotrage engine.
|
||||
|
||||
## Milvus
|
||||
[Milvus](https://milvus.io/) is an open source vector database for unstructured data. It uses RocksDB not only as one of the supported kv storage engines, but also as a message queue.
|
||||
|
||||
## Kafka
|
||||
[Kafka](https://kafka.apache.org/) is an open-source distributed event streaming platform, it uses RocksDB to store state in Kafka Streams: https://www.confluent.io/blog/how-to-tune-rocksdb-kafka-streams-state-stores-performance/.
|
||||
|
||||
## Others
|
||||
More databases using RocksDB can be found at [dbdb.io](https://dbdb.io/browse?embeds=rocksdb).
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ We strive to achieve the following goals:
|
||||
* make all unit test pass both in debug and release builds.
|
||||
* Note: latest introduction of SyncPoint seems to disable running db_test in Release.
|
||||
* make performance on par with published benchmarks accounting for HW differences
|
||||
* we would like to keep the port code inline with the main branch with no forking
|
||||
* we would like to keep the port code inline with the master branch with no forking
|
||||
|
||||
## Build system
|
||||
We have chosen CMake as a widely accepted build system to build the Windows port. It is very fast and convenient.
|
||||
@@ -66,7 +66,7 @@ We endeavored to make it functionally on par with posix_env. This means we repli
|
||||
Even though Windows provides its own efficient thread-pool implementation we chose to replicate posix logic using `std::thread` primitives. This allows anyone to quickly detect any changes within the posix source code and replicate them within windows env. This has proven to work very well. At the same time for anyone who wishes to replace the built-in thread-pool can do so using RocksDB stackable environments.
|
||||
|
||||
For disk access we implemented all of the functionality present within the posix_env which includes memory mapped files, random access, rate-limiter support etc.
|
||||
The `use_os_buffer` flag on Posix platforms currently denotes disabling read-ahead log via `fadvise` mechanism. Windows does not have `fadvise` system call. What is more, it implements disk cache in a way that differs from Linux greatly. It's not an uncommon practice on Windows to perform un-buffered disk access to gain control of the memory consumption. We think that in our use case this may also be a good configuration option at the expense of disk throughput. To compensate one may increase the configured in-memory cache size instead. Thus we have chosen `use_os_buffer=false` to disable OS disk buffering for `WinWritableFile` and `WinRandomAccessFile`. The OS imposes restrictions on the alignment of the disk offsets, buffers used and the amount of data that is read/written when accessing files in un-buffered mode. When the option is true, the classes behave in a standard way. This allows to perform writes and reads in cases when un-buffered access does not make sense such as WAL and MANIFEST.
|
||||
The `use_os_buffer` flag on Posix platforms currently denotes disabling read-ahead log via `fadvise` mechanism. Windows does not have `fadvise` system call. What is more, it implements disk cache in a way that differs from Linux greatly. It’s not an uncommon practice on Windows to perform un-buffered disk access to gain control of the memory consumption. We think that in our use case this may also be a good configuration option at the expense of disk throughput. To compensate one may increase the configured in-memory cache size instead. Thus we have chosen `use_os_buffer=false` to disable OS disk buffering for `WinWritableFile` and `WinRandomAccessFile`. The OS imposes restrictions on the alignment of the disk offsets, buffers used and the amount of data that is read/written when accessing files in un-buffered mode. When the option is true, the classes behave in a standard way. This allows to perform writes and reads in cases when un-buffered access does not make sense such as WAL and MANIFEST.
|
||||
|
||||
We have replaced `pread/pwrite` with `WriteFile/ReadFile` with `OVERLAPPED` structure so we can atomically seek to the position of the disk operation but still perform the operation synchronously. Thus we able to emulate that functionality of `pread/pwrite` reasonably well. The only difference is that the file pointer is not returned to its original position but that hardly matters given the random nature of access.
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
#
|
||||
# Check for some simple mistakes that should prevent commit or push
|
||||
|
||||
BAD=""
|
||||
|
||||
git grep 'namespace rocksdb' -- '*.[ch]*'
|
||||
if [ "$?" != "1" ]; then
|
||||
echo "^^^^^ Do not hardcode namespace rocksdb. Use ROCKSDB_NAMESPACE"
|
||||
BAD=1
|
||||
fi
|
||||
|
||||
git grep -i 'nocommit' -- ':!build_tools/check-sources.sh'
|
||||
if [ "$?" != "1" ]; then
|
||||
echo "^^^^^ Code was not intended to be committed"
|
||||
BAD=1
|
||||
fi
|
||||
|
||||
git grep '<rocksdb/' -- ':!build_tools/check-sources.sh'
|
||||
if [ "$?" != "1" ]; then
|
||||
echo '^^^^^ Use double-quotes as in #include "rocksdb/something.h"'
|
||||
BAD=1
|
||||
fi
|
||||
|
||||
if [ "$BAD" ]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -102,7 +102,6 @@ export PORTABLE
|
||||
|
||||
BINUTILS="$BINUTILS_BASE/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
AS="$BINUTILS/as"
|
||||
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE $LIBURING_INCLUDE"
|
||||
|
||||
@@ -151,6 +150,7 @@ CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PR
|
||||
CXXFLAGS+=" $CFLAGS"
|
||||
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS $LIBURING_LIBS"
|
||||
EXEC_LDFLAGS+=" -B$BINUTILS"
|
||||
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,/usr/local/fbcode/platform009/lib/ld.so"
|
||||
EXEC_LDFLAGS+=" $LIBUNWIND"
|
||||
EXEC_LDFLAGS+=" -Wl,-rpath=/usr/local/fbcode/platform009/lib"
|
||||
@@ -159,7 +159,6 @@ EXEC_LDFLAGS+=" -Wl,-rpath=$GCC_BASE/lib64"
|
||||
EXEC_LDFLAGS+=" -ldl"
|
||||
|
||||
PLATFORM_LDFLAGS="$LIBGCC_LIBS $GLIBC_LIBS $STDLIBS -lgcc -lstdc++"
|
||||
PLATFORM_LDFLAGS+=" -B$BINUTILS"
|
||||
|
||||
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $TBB_LIBS $LIBURING_LIBS"
|
||||
|
||||
@@ -169,4 +168,4 @@ VALGRIND_VER="$VALGRIND_BASE/bin/"
|
||||
LUA_PATH=
|
||||
LUA_LIB=
|
||||
|
||||
export CC CXX AR AS CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD LUA_PATH LUA_LIB
|
||||
export CC CXX AR CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD LUA_PATH LUA_LIB
|
||||
@@ -120,7 +120,7 @@ uncommitted_code=`git diff HEAD`
|
||||
|
||||
# If there's no uncommitted changes, we assume user are doing post-commit
|
||||
# format check, in which case we'll try to check the modified lines vs. the
|
||||
# facebook/rocksdb.git main branch. Otherwise, we'll check format of the
|
||||
# facebook/rocksdb.git master branch. Otherwise, we'll check format of the
|
||||
# uncommitted code only.
|
||||
if [ -z "$uncommitted_code" ]
|
||||
then
|
||||
@@ -128,8 +128,8 @@ then
|
||||
[ "$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/$(git remote show $FORMAT_REMOTE | sed -n '/HEAD branch/s/.*: //p')"
|
||||
# Use master branch from that remote
|
||||
[ "$FORMAT_UPSTREAM" ] || FORMAT_UPSTREAM="$FORMAT_REMOTE/master"
|
||||
# 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.
|
||||
|
||||
@@ -20,11 +20,26 @@ STAT_FILE=${STAT_FILE:-$(mktemp -t -u rocksdb_test_stats_XXXX)}
|
||||
|
||||
function cleanup {
|
||||
rm -rf $DATA_DIR
|
||||
rm -f $STAT_FILE.*
|
||||
rm -f $STAT_FILE.fillseq
|
||||
rm -f $STAT_FILE.readrandom
|
||||
rm -f $STAT_FILE.overwrite
|
||||
rm -f $STAT_FILE.memtablefillreadrandom
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
if [ -z $GIT_BRANCH ]; then
|
||||
git_br=`git rev-parse --abbrev-ref HEAD`
|
||||
else
|
||||
git_br=$(basename $GIT_BRANCH)
|
||||
fi
|
||||
|
||||
if [ $git_br == "master" ]; then
|
||||
git_br=""
|
||||
else
|
||||
git_br="."$git_br
|
||||
fi
|
||||
|
||||
make release
|
||||
|
||||
# measure fillseq + fill up the DB for overwrite benchmark
|
||||
@@ -271,10 +286,12 @@ common_in_mem_args="--db=/dev/shm/rocksdb \
|
||||
--sync=0 \
|
||||
--verify_checksum=1 \
|
||||
--delete_obsolete_files_period_micros=314572800 \
|
||||
--max_grandparent_overlap_factor=10 \
|
||||
--use_plain_table=1 \
|
||||
--open_files=-1 \
|
||||
--mmap_read=1 \
|
||||
--mmap_write=0 \
|
||||
--memtablerep=prefix_hash \
|
||||
--bloom_bits=10 \
|
||||
--bloom_locality=1 \
|
||||
--perf_level=0"
|
||||
@@ -361,7 +378,7 @@ function send_to_ods {
|
||||
echo >&2 "ERROR: Key $key doesn't have a value."
|
||||
return
|
||||
fi
|
||||
curl --silent "https://www.intern.facebook.com/intern/agent/ods_set.php?entity=rocksdb_build&key=$key&value=$value" \
|
||||
curl --silent "https://www.intern.facebook.com/intern/agent/ods_set.php?entity=rocksdb_build$git_br&key=$key&value=$value" \
|
||||
--connect-timeout 60
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ NON_TSAN_CRASH="CRASH_TEST_EXT_ARGS=--compression_type=zstd"
|
||||
DISABLE_JEMALLOC="DISABLE_JEMALLOC=1"
|
||||
HTTP_PROXY="https_proxy=http://fwdproxy.29.prn1:8080 http_proxy=http://fwdproxy.29.prn1:8080 ftp_proxy=http://fwdproxy.29.prn1:8080"
|
||||
SETUP_JAVA_ENV="export $HTTP_PROXY; export JAVA_HOME=/usr/local/jdk-8u60-64/; export PATH=\$JAVA_HOME/bin:\$PATH"
|
||||
PARSER="'parser':'/usr/bin/env python3 build_tools/error_filter.py $1'"
|
||||
PARSER="'parser':'python build_tools/error_filter.py $1'"
|
||||
|
||||
CONTRUN_NAME="ROCKSDB_CONTRUN_NAME"
|
||||
SKIP_FORMAT_CHECKS="SKIP_FORMAT_BUCK_CHECKS=1"
|
||||
@@ -379,6 +379,23 @@ LITE_BUILD_COMMANDS="[
|
||||
}
|
||||
]"
|
||||
|
||||
#
|
||||
# Report RocksDB lite binary size to scuba
|
||||
REPORT_LITE_BINARY_SIZE_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb Lite Binary Size',
|
||||
'oncall':'$ONCALL',
|
||||
'executeLocal': 'true',
|
||||
'steps': [
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Report RocksDB Lite binary size to scuba',
|
||||
'shell':'cd $WORKING_DIR; tools/report_lite_binary_size.sh',
|
||||
'user':'root',
|
||||
},
|
||||
],
|
||||
]"
|
||||
|
||||
#
|
||||
# RocksDB stress/crash test
|
||||
#
|
||||
@@ -571,7 +588,7 @@ WRITE_STRESS_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Build and run RocksDB write stress tests',
|
||||
'shell':'cd $WORKING_DIR; make write_stress && /usr/bin/env python3 tools/write_stress_runner.py --runtime_sec=3600 --db=/tmp/rocksdb_write_stress || $CONTRUN_NAME=write_stress $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; make write_stress && python tools/write_stress_runner.py --runtime_sec=3600 --db=/tmp/rocksdb_write_stress || $CONTRUN_NAME=write_stress $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
@@ -594,7 +611,7 @@ ASAN_TEST_COMMANDS="[
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
'name':'Test RocksDB debug under ASAN',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && $SHM $ASAN $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM asan_check || $CONTRUN_NAME=asan_check $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; set -o pipefail && ($SHM $ASAN $DEBUG $SKIP_FORMAT_CHECKS make $PARALLELISM asan_check || $CONTRUN_NAME=asan_check $TASK_CREATION_TOOL) |& /usr/facebook/ops/scripts/asan_symbolize.py -d',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
}
|
||||
@@ -1103,7 +1120,7 @@ NO_COMPRESSION_COMMANDS="[
|
||||
#
|
||||
run_regression()
|
||||
{
|
||||
time bash -vx ./build_tools/regression_build_test.sh $(mktemp -d $WORKING_DIR/rocksdb.XXXX) $(mktemp rocksdb_test_stats.XXXX)
|
||||
time -v bash -vx ./build_tools/regression_build_test.sh $(mktemp -d $WORKSPACE/leveldb.XXXX) $(mktemp leveldb_test_stats.XXXX)
|
||||
|
||||
# ======= report size to ODS ========
|
||||
|
||||
@@ -1144,7 +1161,6 @@ REGRESSION_COMMANDS="[
|
||||
{
|
||||
'name':'Rocksdb regression commands',
|
||||
'oncall':'$ONCALL',
|
||||
'executeLocal': 'true',
|
||||
'steps': [
|
||||
$CLEANUP_ENV,
|
||||
{
|
||||
@@ -1191,7 +1207,7 @@ FBCODE_STRESS_CRASH_TEST_COMMANDS="[
|
||||
'steps': [
|
||||
{
|
||||
'name':'Copy RocksDB code to fbcode repo',
|
||||
'shell':'cd internal_repo_rocksdb/repo && git init -b main && git add * && git commit -a -m \"Make internal_repo_rocksdb/repo a git repo\" && cd ../.. && echo Y | python3 rocks/release_script/release_to_fbcode.py -u internal_repo_rocksdb/repo main || $CONTRUN_NAME=db_stress_fbcode $TASK_CREATION_TOOL',
|
||||
'shell':'cd internal_repo_rocksdb/repo && git init && git add * && git commit -a -m \"Make internal_repo_rocksdb/repo a git repo\" && cd ../.. && echo Y | python3 rocks/release_script/release_to_fbcode.py -u internal_repo_rocksdb/repo master || $CONTRUN_NAME=db_stress_fbcode $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1204,7 +1220,7 @@ FBCODE_STRESS_CRASH_TEST_COMMANDS="[
|
||||
{
|
||||
'name':'Run RocksDB whitebox crash tests',
|
||||
'timeout': 86400,
|
||||
'shell':'cd $WORKING_DIR; mkdir /dev/shm/rocksdb_whitebox_crash_test && TEST_TMPDIR=\$(mktemp -d --tmpdir=/dev/shm/rocksdb_whitebox_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 -checkpoint_one_in=0 -backup_one_in=0 -cache_size=134217728 -cache_numshardbits=4 $EXTRA_DB_STRESS_ARGS -logtostderr=false whitebox || $CONTRUN_NAME=db_stress_fbcode $TASK_CREATION_TOOL',
|
||||
'shell':'cd $WORKING_DIR; mkdir /dev/shm/rocksdb_whitebox_crash_test && TEST_TMPDIR=\$(mktemp -d --tmpdir=/dev/shm/rocksdb_whitebox_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 -checkpoint_one_in=0 -backup_one_in=0 -cache_size=134217728 -cache_numshardbits=4 $EXTRA_DB_STRESS_ARGS -logtostderr=false whitebox || $CONTRUN_NAME=whitebox_crash_test $TASK_CREATION_TOOL',
|
||||
'user':'root',
|
||||
$PARSER
|
||||
},
|
||||
@@ -1248,6 +1264,9 @@ case $1 in
|
||||
lite)
|
||||
echo $LITE_BUILD_COMMANDS
|
||||
;;
|
||||
report_lite_binary_size)
|
||||
echo $REPORT_LITE_BINARY_SIZE_COMMANDS
|
||||
;;
|
||||
stress_crash)
|
||||
echo $STRESS_CRASH_TEST_COMMANDS
|
||||
;;
|
||||
@@ -1342,9 +1361,7 @@ case $1 in
|
||||
echo $REGRESSION_COMMANDS
|
||||
;;
|
||||
run_regression)
|
||||
set -e
|
||||
run_regression
|
||||
set +e
|
||||
;;
|
||||
java_build)
|
||||
echo $JAVA_BUILD_TEST_COMMANDS
|
||||
|
||||
Vendored
+1
-1
@@ -13,7 +13,7 @@ int main() {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#include "rocksdb/cache_bench_tool.h"
|
||||
#include <rocksdb/cache_bench_tool.h>
|
||||
int main(int argc, char** argv) {
|
||||
return ROCKSDB_NAMESPACE::cache_bench_tool(argc, argv);
|
||||
}
|
||||
|
||||
Vendored
-2
@@ -19,7 +19,6 @@ std::array<const char*, kNumCacheEntryRoles> kCacheEntryRoleToCamelString{{
|
||||
"IndexBlock",
|
||||
"OtherBlock",
|
||||
"WriteBuffer",
|
||||
"CompressionDictionaryBuildingBuffer",
|
||||
"Misc",
|
||||
}};
|
||||
|
||||
@@ -31,7 +30,6 @@ std::array<const char*, kNumCacheEntryRoles> kCacheEntryRoleToHyphenString{{
|
||||
"index-block",
|
||||
"other-block",
|
||||
"write-buffer",
|
||||
"compression-dictionary-building-buffer",
|
||||
"misc",
|
||||
}};
|
||||
|
||||
|
||||
Vendored
-5
@@ -14,8 +14,6 @@
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Classifications of block cache entries, for reporting statistics
|
||||
// Adding new enum to this class requires corresponding updates to
|
||||
// kCacheEntryRoleToCamelString and kCacheEntryRoleToHyphenString
|
||||
enum class CacheEntryRole {
|
||||
// Block-based table data block
|
||||
kDataBlock,
|
||||
@@ -31,9 +29,6 @@ enum class CacheEntryRole {
|
||||
kOtherBlock,
|
||||
// WriteBufferManager reservations to account for memtable usage
|
||||
kWriteBuffer,
|
||||
// BlockBasedTableBuilder reservations to account for
|
||||
// compression dictionary building buffer's memory usage
|
||||
kCompressionDictionaryBuildingBuffer,
|
||||
// Default bucket, for miscellaneous cache entries. Do not use for
|
||||
// entries that could potentially add up to large usage.
|
||||
kMisc,
|
||||
|
||||
Vendored
-1
@@ -15,7 +15,6 @@
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/system_clock.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/coding_lean.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
Vendored
-131
@@ -1,131 +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).
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
#include "cache/cache_reservation_manager.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "cache/cache_entry_roles.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "table/block_based/block_based_table_reader.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
CacheReservationManager::CacheReservationManager(std::shared_ptr<Cache> cache,
|
||||
bool delayed_decrease)
|
||||
: delayed_decrease_(delayed_decrease), cache_allocated_size_(0) {
|
||||
assert(cache != nullptr);
|
||||
cache_ = cache;
|
||||
std::memset(cache_key_, 0, kCacheKeyPrefixSize + kMaxVarint64Length);
|
||||
EncodeVarint64(cache_key_, cache_->NewId());
|
||||
}
|
||||
|
||||
CacheReservationManager::~CacheReservationManager() {
|
||||
for (auto* handle : dummy_handles_) {
|
||||
cache_->Release(handle, true);
|
||||
}
|
||||
}
|
||||
|
||||
template <CacheEntryRole R>
|
||||
Status CacheReservationManager::UpdateCacheReservation(
|
||||
std::size_t new_mem_used) {
|
||||
std::size_t cur_cache_allocated_size =
|
||||
cache_allocated_size_.load(std::memory_order_relaxed);
|
||||
if (new_mem_used == cur_cache_allocated_size) {
|
||||
return Status::OK();
|
||||
} else if (new_mem_used > cur_cache_allocated_size) {
|
||||
Status s = IncreaseCacheReservation<R>(new_mem_used);
|
||||
return s;
|
||||
} else {
|
||||
// In delayed decrease mode, we don't decrease cache reservation
|
||||
// untill the memory usage is less than 3/4 of what we reserve
|
||||
// in the cache.
|
||||
// We do this because
|
||||
// (1) Dummy entry insertion is expensive in block cache
|
||||
// (2) Delayed releasing previously inserted dummy entries can save such
|
||||
// expensive dummy entry insertion on memory increase in the near future,
|
||||
// which is likely to happen when the memory usage is greater than or equal
|
||||
// to 3/4 of what we reserve
|
||||
if (delayed_decrease_ && new_mem_used >= cur_cache_allocated_size / 4 * 3) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
Status s = DecreaseCacheReservation(new_mem_used);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Explicitly instantiate templates for "CacheEntryRole" values we use.
|
||||
// This makes it possible to keep the template definitions in the .cc file.
|
||||
template Status CacheReservationManager::UpdateCacheReservation<
|
||||
CacheEntryRole::kWriteBuffer>(std::size_t new_mem_used);
|
||||
template Status CacheReservationManager::UpdateCacheReservation<
|
||||
CacheEntryRole::kCompressionDictionaryBuildingBuffer>(
|
||||
std::size_t new_mem_used);
|
||||
// For cache reservation manager unit tests
|
||||
template Status CacheReservationManager::UpdateCacheReservation<
|
||||
CacheEntryRole::kMisc>(std::size_t new_mem_used);
|
||||
|
||||
template <CacheEntryRole R>
|
||||
Status CacheReservationManager::IncreaseCacheReservation(
|
||||
std::size_t new_mem_used) {
|
||||
Status return_status = Status::OK();
|
||||
while (new_mem_used > cache_allocated_size_.load(std::memory_order_relaxed)) {
|
||||
Cache::Handle* handle = nullptr;
|
||||
return_status = cache_->Insert(GetNextCacheKey(), nullptr, kSizeDummyEntry,
|
||||
GetNoopDeleterForRole<R>(), &handle);
|
||||
|
||||
if (return_status != Status::OK()) {
|
||||
return return_status;
|
||||
}
|
||||
|
||||
dummy_handles_.push_back(handle);
|
||||
cache_allocated_size_ += kSizeDummyEntry;
|
||||
}
|
||||
return return_status;
|
||||
}
|
||||
|
||||
Status CacheReservationManager::DecreaseCacheReservation(
|
||||
std::size_t new_mem_used) {
|
||||
Status return_status = Status::OK();
|
||||
|
||||
// Decrease to the smallest multiple of kSizeDummyEntry that is greater than
|
||||
// or equal to new_mem_used We do addition instead of new_mem_used <=
|
||||
// cache_allocated_size_.load(std::memory_order_relaxed) - kSizeDummyEntry to
|
||||
// avoid underflow of size_t when cache_allocated_size_ = 0
|
||||
while (new_mem_used + kSizeDummyEntry <=
|
||||
cache_allocated_size_.load(std::memory_order_relaxed)) {
|
||||
assert(!dummy_handles_.empty());
|
||||
auto* handle = dummy_handles_.back();
|
||||
cache_->Release(handle, true);
|
||||
dummy_handles_.pop_back();
|
||||
cache_allocated_size_ -= kSizeDummyEntry;
|
||||
}
|
||||
return return_status;
|
||||
}
|
||||
|
||||
std::size_t CacheReservationManager::GetTotalReservedCacheSize() {
|
||||
return cache_allocated_size_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
Slice CacheReservationManager::GetNextCacheKey() {
|
||||
// Calling this function will have the side-effect of changing the
|
||||
// underlying cache_key_ that is shared among other keys generated from this
|
||||
// fucntion. Therefore please make sure the previous keys are saved/copied
|
||||
// before calling this function.
|
||||
std::memset(cache_key_ + kCacheKeyPrefixSize, 0, kMaxVarint64Length);
|
||||
char* end =
|
||||
EncodeVarint64(cache_key_ + kCacheKeyPrefixSize, next_cache_key_id_++);
|
||||
return Slice(cache_key_, static_cast<std::size_t>(end - cache_key_));
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
-98
@@ -1,98 +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).
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "cache/cache_entry_roles.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "table/block_based/block_based_table_reader.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// CacheReservationManager is for reserving cache space for the memory used
|
||||
// through inserting/releasing dummy entries in the cache.
|
||||
// This class is not thread-safe.
|
||||
class CacheReservationManager {
|
||||
public:
|
||||
// Construct a CacheReservationManager
|
||||
// @param cache The cache where dummy entries are inserted and released for
|
||||
// reserving cache space
|
||||
// @param delayed_decrease If set true, then dummy entries won't be released
|
||||
// immediately when memory usage decreases.
|
||||
// Instead, it will be released when the memory usage
|
||||
// decreases to 3/4 of what we have reserved so far.
|
||||
// This is for saving some future dummy entry
|
||||
// insertion when memory usage increases are likely to
|
||||
// happen in the near future.
|
||||
explicit CacheReservationManager(std::shared_ptr<Cache> cache,
|
||||
bool delayed_decrease = false);
|
||||
|
||||
// no copy constructor, copy assignment, move constructor, move assignment
|
||||
CacheReservationManager(const CacheReservationManager &) = delete;
|
||||
CacheReservationManager &operator=(const CacheReservationManager &) = delete;
|
||||
CacheReservationManager(CacheReservationManager &&) = delete;
|
||||
CacheReservationManager &operator=(CacheReservationManager &&) = delete;
|
||||
|
||||
~CacheReservationManager();
|
||||
|
||||
template <CacheEntryRole R>
|
||||
|
||||
// Insert and release dummy entries in the cache to
|
||||
// match the size of total dummy entries with the smallest multiple of
|
||||
// kSizeDummyEntry that is greater than or equal to new_mem_used
|
||||
//
|
||||
// Insert dummy entries if new_memory_used > cache_allocated_size_;
|
||||
//
|
||||
// Release dummy entries if new_memory_used < cache_allocated_size_
|
||||
// (and new_memory_used < cache_allocated_size_ * 3/4
|
||||
// when delayed_decrease is set true);
|
||||
//
|
||||
// Keey dummy entries the same if (1) new_memory_used == cache_allocated_size_
|
||||
// or (2) new_memory_used is in the interval of
|
||||
// [cache_allocated_size_ * 3/4, cache_allocated_size) when delayed_decrease
|
||||
// is set true.
|
||||
//
|
||||
// @param new_memory_used The number of bytes used by new memory
|
||||
// @return On inserting dummy entries, it returns Status::OK() if all dummy
|
||||
// entry insertions succeed. Otherwise, it returns the first non-ok status;
|
||||
// On releasing dummy entries, it always returns Status::OK().
|
||||
// On keeping dummy entries the same, it always returns Status::OK().
|
||||
Status UpdateCacheReservation(std::size_t new_memory_used);
|
||||
std::size_t GetTotalReservedCacheSize();
|
||||
|
||||
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
|
||||
// conflict.
|
||||
static const std::size_t kCacheKeyPrefixSize =
|
||||
BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length;
|
||||
|
||||
Slice GetNextCacheKey();
|
||||
template <CacheEntryRole R>
|
||||
Status IncreaseCacheReservation(std::size_t new_mem_used);
|
||||
Status DecreaseCacheReservation(std::size_t new_mem_used);
|
||||
|
||||
std::shared_ptr<Cache> cache_;
|
||||
bool delayed_decrease_;
|
||||
std::atomic<std::size_t> cache_allocated_size_;
|
||||
std::vector<Cache::Handle *> dummy_handles_;
|
||||
std::uint64_t next_cache_key_id_ = 0;
|
||||
// The non-prefix part will be updated according to the ID to use.
|
||||
char cache_key_[kCacheKeyPrefixSize + kMaxVarint64Length];
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
-411
@@ -1,411 +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).
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
#include "cache/cache_reservation_manager.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "cache/cache_entry_roles.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "table/block_based/block_based_table_reader.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class CacheReservationManagerTest : public ::testing::Test {
|
||||
protected:
|
||||
static constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
static constexpr int kNumShardBits = 0; // 2^0 shard
|
||||
|
||||
static constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
static const std::size_t kCacheKeyPrefixSize =
|
||||
BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length;
|
||||
static constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(kOneGigabyte, kNumShardBits);
|
||||
std::unique_ptr<CacheReservationManager> test_cache_rev_mng;
|
||||
|
||||
CacheReservationManagerTest() {
|
||||
test_cache_rev_mng.reset(new CacheReservationManager(cache));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CacheReservationManagerTest, GenerateCacheKey) {
|
||||
// The first cache reservation manager owning the cache will have
|
||||
// cache->NewId() = 1
|
||||
constexpr std::size_t kCacheNewId = 1;
|
||||
// The first key generated inside of cache reservation manager will have
|
||||
// next_cache_key_id = 0
|
||||
constexpr std::size_t kCacheKeyId = 0;
|
||||
|
||||
char expected_cache_key[kCacheKeyPrefixSize + kMaxVarint64Length];
|
||||
std::memset(expected_cache_key, 0, kCacheKeyPrefixSize + kMaxVarint64Length);
|
||||
|
||||
EncodeVarint64(expected_cache_key, kCacheNewId);
|
||||
char* end =
|
||||
EncodeVarint64(expected_cache_key + kCacheKeyPrefixSize, kCacheKeyId);
|
||||
Slice expected_cache_key_slice(
|
||||
expected_cache_key, static_cast<std::size_t>(end - expected_cache_key));
|
||||
|
||||
std::size_t new_mem_used = 1 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry);
|
||||
ASSERT_LT(cache->GetPinnedUsage(),
|
||||
1 * kSizeDummyEntry + kMetaDataChargeOverhead);
|
||||
|
||||
Cache::Handle* handle = cache->Lookup(expected_cache_key_slice);
|
||||
EXPECT_NE(handle, nullptr)
|
||||
<< "Failed to generate the cache key for the dummy entry correctly";
|
||||
// Clean up the returned handle from Lookup() to prevent memory leak
|
||||
cache->Release(handle);
|
||||
}
|
||||
|
||||
TEST_F(CacheReservationManagerTest, KeepCacheReservationTheSame) {
|
||||
std::size_t new_mem_used = 1 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
1 * kSizeDummyEntry);
|
||||
std::size_t initial_pinned_usage = cache->GetPinnedUsage();
|
||||
ASSERT_GE(initial_pinned_usage, 1 * kSizeDummyEntry);
|
||||
ASSERT_LT(initial_pinned_usage,
|
||||
1 * kSizeDummyEntry + kMetaDataChargeOverhead);
|
||||
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to keep cache reservation the same when new_mem_used equals "
|
||||
"to current cache reservation";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
1 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep correctly when new_mem_used equals to current "
|
||||
"cache reservation";
|
||||
EXPECT_EQ(cache->GetPinnedUsage(), initial_pinned_usage)
|
||||
<< "Failed to keep underlying dummy entries the same when new_mem_used "
|
||||
"equals to current cache reservation";
|
||||
}
|
||||
|
||||
TEST_F(CacheReservationManagerTest,
|
||||
IncreaseCacheReservationByMultiplesOfDummyEntrySize) {
|
||||
std::size_t new_mem_used = 2 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to increase cache reservation correctly";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
2 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep cache reservation increase correctly";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry)
|
||||
<< "Failed to increase underlying dummy entries in cache correctly";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
2 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to increase underlying dummy entries in cache correctly";
|
||||
}
|
||||
|
||||
TEST_F(CacheReservationManagerTest,
|
||||
IncreaseCacheReservationNotByMultiplesOfDummyEntrySize) {
|
||||
std::size_t new_mem_used = 2 * kSizeDummyEntry + kSizeDummyEntry / 2;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to increase cache reservation correctly";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
3 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep cache reservation increase correctly";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 3 * kSizeDummyEntry)
|
||||
<< "Failed to increase underlying dummy entries in cache correctly";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
3 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to increase underlying dummy entries in cache correctly";
|
||||
}
|
||||
|
||||
TEST(CacheReservationManagerIncreaseReservcationOnFullCacheTest,
|
||||
IncreaseCacheReservationOnFullCache) {
|
||||
constexpr std::size_t kOneMegabyte = 1024 * 1024;
|
||||
constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
LRUCacheOptions lo;
|
||||
lo.capacity = kOneMegabyte;
|
||||
lo.num_shard_bits = 0; // 2^0 shard
|
||||
lo.strict_capacity_limit = true;
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(lo);
|
||||
std::unique_ptr<CacheReservationManager> test_cache_rev_mng(
|
||||
new CacheReservationManager(cache));
|
||||
|
||||
std::size_t new_mem_used = kOneMegabyte + 1;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::Incomplete())
|
||||
<< "Failed to return status to indicate failure of dummy entry insertion "
|
||||
"during cache reservation on full cache";
|
||||
EXPECT_GE(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
1 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep correctly before cache resevation failure happens "
|
||||
"due to full cache";
|
||||
EXPECT_LE(test_cache_rev_mng->GetTotalReservedCacheSize(), kOneMegabyte)
|
||||
<< "Failed to bookkeep correctly (i.e, bookkeep only successful dummy "
|
||||
"entry insertions) when encountering cache resevation failure due to "
|
||||
"full cache";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
|
||||
<< "Failed to insert underlying dummy entries correctly when "
|
||||
"encountering cache resevation failure due to full cache";
|
||||
EXPECT_LE(cache->GetPinnedUsage(), kOneMegabyte)
|
||||
<< "Failed to insert underlying dummy entries correctly when "
|
||||
"encountering cache resevation failure due to full cache";
|
||||
|
||||
new_mem_used = kOneMegabyte / 2; // 2 dummy entries
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to decrease cache reservation after encountering cache "
|
||||
"reservation failure due to full cache";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
2 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep cache reservation decrease correctly after "
|
||||
"encountering cache reservation due to full cache";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry)
|
||||
<< "Failed to release underlying dummy entries correctly on cache "
|
||||
"reservation decrease after encountering cache resevation failure due "
|
||||
"to full cache";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
2 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to release underlying dummy entries correctly on cache "
|
||||
"reservation decrease after encountering cache resevation failure due "
|
||||
"to full cache";
|
||||
|
||||
// Create cache full again for subsequent tests
|
||||
new_mem_used = kOneMegabyte + 1;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::Incomplete())
|
||||
<< "Failed to return status to indicate failure of dummy entry insertion "
|
||||
"during cache reservation on full cache";
|
||||
EXPECT_GE(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
1 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep correctly before cache resevation failure happens "
|
||||
"due to full cache";
|
||||
EXPECT_LE(test_cache_rev_mng->GetTotalReservedCacheSize(), kOneMegabyte)
|
||||
<< "Failed to bookkeep correctly (i.e, bookkeep only successful dummy "
|
||||
"entry insertions) when encountering cache resevation failure due to "
|
||||
"full cache";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
|
||||
<< "Failed to insert underlying dummy entries correctly when "
|
||||
"encountering cache resevation failure due to full cache";
|
||||
EXPECT_LE(cache->GetPinnedUsage(), kOneMegabyte)
|
||||
<< "Failed to insert underlying dummy entries correctly when "
|
||||
"encountering cache resevation failure due to full cache";
|
||||
|
||||
// Increase cache capacity so the previously failed insertion can fully
|
||||
// succeed
|
||||
cache->SetCapacity(kOneGigabyte);
|
||||
new_mem_used = kOneMegabyte + 1;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to increase cache reservation after increasing cache capacity "
|
||||
"and mitigating cache full error";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
5 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep cache reservation increase correctly after "
|
||||
"increasing cache capacity and mitigating cache full error";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 5 * kSizeDummyEntry)
|
||||
<< "Failed to insert underlying dummy entries correctly after increasing "
|
||||
"cache capacity and mitigating cache full error";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
5 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to insert underlying dummy entries correctly after increasing "
|
||||
"cache capacity and mitigating cache full error";
|
||||
}
|
||||
|
||||
TEST_F(CacheReservationManagerTest,
|
||||
DecreaseCacheReservationByMultiplesOfDummyEntrySize) {
|
||||
std::size_t new_mem_used = 2 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
2 * kSizeDummyEntry);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry);
|
||||
ASSERT_LT(cache->GetPinnedUsage(),
|
||||
2 * kSizeDummyEntry + kMetaDataChargeOverhead);
|
||||
|
||||
new_mem_used = 1 * kSizeDummyEntry;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to decrease cache reservation correctly";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
1 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep cache reservation decrease correctly";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
|
||||
<< "Failed to decrease underlying dummy entries in cache correctly";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
1 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to decrease underlying dummy entries in cache correctly";
|
||||
}
|
||||
|
||||
TEST_F(CacheReservationManagerTest,
|
||||
DecreaseCacheReservationNotByMultiplesOfDummyEntrySize) {
|
||||
std::size_t new_mem_used = 2 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
2 * kSizeDummyEntry);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 2 * kSizeDummyEntry);
|
||||
ASSERT_LT(cache->GetPinnedUsage(),
|
||||
2 * kSizeDummyEntry + kMetaDataChargeOverhead);
|
||||
|
||||
new_mem_used = kSizeDummyEntry / 2;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to decrease cache reservation correctly";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
1 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep cache reservation decrease correctly";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry)
|
||||
<< "Failed to decrease underlying dummy entries in cache correctly";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
1 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to decrease underlying dummy entries in cache correctly";
|
||||
}
|
||||
|
||||
TEST(CacheReservationManagerWithDelayedDecreaseTest,
|
||||
DecreaseCacheReservationWithDelayedDecrease) {
|
||||
constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
LRUCacheOptions lo;
|
||||
lo.capacity = kOneGigabyte;
|
||||
lo.num_shard_bits = 0;
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(lo);
|
||||
std::unique_ptr<CacheReservationManager> test_cache_rev_mng(
|
||||
new CacheReservationManager(cache, true /* delayed_decrease */));
|
||||
|
||||
std::size_t new_mem_used = 8 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
8 * kSizeDummyEntry);
|
||||
std::size_t initial_pinned_usage = cache->GetPinnedUsage();
|
||||
ASSERT_GE(initial_pinned_usage, 8 * kSizeDummyEntry);
|
||||
ASSERT_LT(initial_pinned_usage,
|
||||
8 * kSizeDummyEntry + kMetaDataChargeOverhead);
|
||||
|
||||
new_mem_used = 6 * kSizeDummyEntry;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK()) << "Failed to delay decreasing cache reservation";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
8 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep correctly when delaying cache reservation "
|
||||
"decrease";
|
||||
EXPECT_EQ(cache->GetPinnedUsage(), initial_pinned_usage)
|
||||
<< "Failed to delay decreasing underlying dummy entries in cache";
|
||||
|
||||
new_mem_used = 7 * kSizeDummyEntry;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK()) << "Failed to delay decreasing cache reservation";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
8 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep correctly when delaying cache reservation "
|
||||
"decrease";
|
||||
EXPECT_EQ(cache->GetPinnedUsage(), initial_pinned_usage)
|
||||
<< "Failed to delay decreasing underlying dummy entries in cache";
|
||||
|
||||
new_mem_used = 6 * kSizeDummyEntry - 1;
|
||||
s = test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
EXPECT_EQ(s, Status::OK())
|
||||
<< "Failed to decrease cache reservation correctly when new_mem_used < "
|
||||
"GetTotalReservedCacheSize() * 3 / 4 on delayed decrease mode";
|
||||
EXPECT_EQ(test_cache_rev_mng->GetTotalReservedCacheSize(),
|
||||
6 * kSizeDummyEntry)
|
||||
<< "Failed to bookkeep correctly when new_mem_used < "
|
||||
"GetTotalReservedCacheSize() * 3 / 4 on delayed decrease mode";
|
||||
EXPECT_GE(cache->GetPinnedUsage(), 6 * kSizeDummyEntry)
|
||||
<< "Failed to decrease underlying dummy entries in cache when "
|
||||
"new_mem_used < GetTotalReservedCacheSize() * 3 / 4 on delayed "
|
||||
"decrease mode";
|
||||
EXPECT_LT(cache->GetPinnedUsage(),
|
||||
6 * kSizeDummyEntry + kMetaDataChargeOverhead)
|
||||
<< "Failed to decrease underlying dummy entries in cache when "
|
||||
"new_mem_used < GetTotalReservedCacheSize() * 3 / 4 on delayed "
|
||||
"decrease mode";
|
||||
}
|
||||
|
||||
TEST(CacheReservationManagerDestructorTest,
|
||||
ReleaseRemainingDummyEntriesOnDestruction) {
|
||||
constexpr std::size_t kOneGigabyte = 1024 * 1024 * 1024;
|
||||
constexpr std::size_t kSizeDummyEntry = 256 * 1024;
|
||||
constexpr std::size_t kMetaDataChargeOverhead = 10000;
|
||||
|
||||
LRUCacheOptions lo;
|
||||
lo.capacity = kOneGigabyte;
|
||||
lo.num_shard_bits = 0;
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(lo);
|
||||
{
|
||||
std::unique_ptr<CacheReservationManager> test_cache_rev_mng(
|
||||
new CacheReservationManager(cache));
|
||||
std::size_t new_mem_used = 1 * kSizeDummyEntry;
|
||||
Status s =
|
||||
test_cache_rev_mng
|
||||
->UpdateCacheReservation<ROCKSDB_NAMESPACE::CacheEntryRole::kMisc>(
|
||||
new_mem_used);
|
||||
ASSERT_EQ(s, Status::OK());
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 1 * kSizeDummyEntry);
|
||||
ASSERT_LT(cache->GetPinnedUsage(),
|
||||
1 * kSizeDummyEntry + kMetaDataChargeOverhead);
|
||||
}
|
||||
EXPECT_EQ(cache->GetPinnedUsage(), 0 * kSizeDummyEntry)
|
||||
<< "Failed to release remaining underlying dummy entries in cache in "
|
||||
"CacheReservationManager's destructor";
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Vendored
+1
-1
@@ -260,7 +260,7 @@ struct CleanupContext {
|
||||
class ClockCacheShard final : public CacheShard {
|
||||
public:
|
||||
// Hash map type.
|
||||
using HashTable = tbb::concurrent_hash_map<CacheKey, CacheHandle*, CacheKey>;
|
||||
typedef tbb::concurrent_hash_map<CacheKey, CacheHandle*, CacheKey> HashTable;
|
||||
|
||||
ClockCacheShard();
|
||||
~ClockCacheShard() override;
|
||||
|
||||
@@ -24,7 +24,7 @@ mkdir -p $COVERAGE_DIR
|
||||
|
||||
# Find all gcno files to generate the coverage report
|
||||
|
||||
PYTHON=${1:-`which python3`}
|
||||
PYTHON=${1:-`which python`}
|
||||
echo -e "Using $PYTHON"
|
||||
GCNO_FILES=`find $ROOT -name "*.gcno"`
|
||||
$GCOV --preserve-paths --relative-only --no-output $GCNO_FILES 2>/dev/null |
|
||||
|
||||
@@ -34,13 +34,7 @@ class Version;
|
||||
// the same as the inner DBIter.
|
||||
class ArenaWrappedDBIter : public Iterator {
|
||||
public:
|
||||
virtual ~ArenaWrappedDBIter() {
|
||||
if (db_iter_ != nullptr) {
|
||||
db_iter_->~DBIter();
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
virtual ~ArenaWrappedDBIter() { db_iter_->~DBIter(); }
|
||||
|
||||
// Get the arena to be used to allocate memory for DBIter to be wrapped,
|
||||
// as well as child iterators in it.
|
||||
@@ -96,7 +90,7 @@ class ArenaWrappedDBIter : public Iterator {
|
||||
}
|
||||
|
||||
private:
|
||||
DBIter* db_iter_ = nullptr;
|
||||
DBIter* db_iter_;
|
||||
Arena arena_;
|
||||
uint64_t sv_number_;
|
||||
ColumnFamilyData* cfd_ = nullptr;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "db/blob/blob_index.h"
|
||||
#include "db/blob/blob_log_format.h"
|
||||
#include "db/blob/blob_log_writer.h"
|
||||
#include "db/event_helpers.h"
|
||||
#include "db/version_set.h"
|
||||
#include "file/filename.h"
|
||||
#include "file/read_write_util.h"
|
||||
@@ -37,14 +36,13 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
BlobFileCreationReason creation_reason,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions)
|
||||
: BlobFileBuilder([versions]() { return versions->NewFileNumber(); }, fs,
|
||||
immutable_options, mutable_cf_options, file_options,
|
||||
job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, io_tracer, blob_callback, creation_reason,
|
||||
blob_file_paths, blob_file_additions) {}
|
||||
write_hint, io_tracer, blob_callback, blob_file_paths,
|
||||
blob_file_additions) {}
|
||||
|
||||
BlobFileBuilder::BlobFileBuilder(
|
||||
std::function<uint64_t()> file_number_generator, FileSystem* fs,
|
||||
@@ -55,7 +53,6 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
BlobFileCreationReason creation_reason,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions)
|
||||
: file_number_generator_(std::move(file_number_generator)),
|
||||
@@ -72,7 +69,6 @@ BlobFileBuilder::BlobFileBuilder(
|
||||
write_hint_(write_hint),
|
||||
io_tracer_(io_tracer),
|
||||
blob_callback_(blob_callback),
|
||||
creation_reason_(creation_reason),
|
||||
blob_file_paths_(blob_file_paths),
|
||||
blob_file_additions_(blob_file_additions),
|
||||
blob_count_(0),
|
||||
@@ -165,11 +161,6 @@ Status BlobFileBuilder::OpenBlobFileIfNeeded() {
|
||||
std::string blob_file_path =
|
||||
BlobFileName(immutable_options_->cf_paths.front().path, blob_file_number);
|
||||
|
||||
if (blob_callback_) {
|
||||
blob_callback_->OnBlobFileCreationStarted(
|
||||
blob_file_path, column_family_name_, job_id_, creation_reason_);
|
||||
}
|
||||
|
||||
std::unique_ptr<FSWritableFile> file;
|
||||
|
||||
{
|
||||
@@ -314,13 +305,6 @@ Status BlobFileBuilder::CloseBlobFile() {
|
||||
|
||||
const uint64_t blob_file_number = writer_->get_log_number();
|
||||
|
||||
if (blob_callback_) {
|
||||
s = blob_callback_->OnBlobFileCompleted(
|
||||
blob_file_paths_->back(), column_family_name_, job_id_,
|
||||
blob_file_number, creation_reason_, s, checksum_value, checksum_method,
|
||||
blob_count_, blob_bytes_);
|
||||
}
|
||||
|
||||
assert(blob_file_additions_);
|
||||
blob_file_additions_->emplace_back(blob_file_number, blob_count_, blob_bytes_,
|
||||
std::move(checksum_method),
|
||||
@@ -332,6 +316,9 @@ Status BlobFileBuilder::CloseBlobFile() {
|
||||
" total blobs, %" PRIu64 " total bytes",
|
||||
column_family_name_.c_str(), job_id_, blob_file_number,
|
||||
blob_count_, blob_bytes_);
|
||||
if (blob_callback_) {
|
||||
s = blob_callback_->OnBlobFileCompleted(blob_file_paths_->back());
|
||||
}
|
||||
|
||||
writer_.reset();
|
||||
blob_count_ = 0;
|
||||
@@ -353,18 +340,15 @@ Status BlobFileBuilder::CloseBlobFileIfNeeded() {
|
||||
return CloseBlobFile();
|
||||
}
|
||||
|
||||
void BlobFileBuilder::Abandon(const Status& s) {
|
||||
void BlobFileBuilder::Abandon() {
|
||||
if (!IsBlobFileOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (blob_callback_) {
|
||||
// BlobFileBuilder::Abandon() is called because of error while writing to
|
||||
// Blob files. So we can ignore the below error.
|
||||
blob_callback_
|
||||
->OnBlobFileCompleted(blob_file_paths_->back(), column_family_name_,
|
||||
job_id_, writer_->get_log_number(),
|
||||
creation_reason_, s, "", "", blob_count_,
|
||||
blob_bytes_)
|
||||
blob_callback_->OnBlobFileCompleted(blob_file_paths_->back())
|
||||
.PermitUncheckedError();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "rocksdb/compression_type.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
#include "rocksdb/types.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -42,7 +41,6 @@ class BlobFileBuilder {
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
BlobFileCreationReason creation_reason,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions);
|
||||
|
||||
@@ -56,7 +54,6 @@ class BlobFileBuilder {
|
||||
Env::WriteLifeTimeHint write_hint,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCompletionCallback* blob_callback,
|
||||
BlobFileCreationReason creation_reason,
|
||||
std::vector<std::string>* blob_file_paths,
|
||||
std::vector<BlobFileAddition>* blob_file_additions);
|
||||
|
||||
@@ -67,7 +64,7 @@ class BlobFileBuilder {
|
||||
|
||||
Status Add(const Slice& key, const Slice& value, std::string* blob_index);
|
||||
Status Finish();
|
||||
void Abandon(const Status& s);
|
||||
void Abandon();
|
||||
|
||||
private:
|
||||
bool IsBlobFileOpen() const;
|
||||
@@ -92,7 +89,6 @@ class BlobFileBuilder {
|
||||
Env::WriteLifeTimeHint write_hint_;
|
||||
std::shared_ptr<IOTracer> io_tracer_;
|
||||
BlobFileCompletionCallback* blob_callback_;
|
||||
BlobFileCreationReason creation_reason_;
|
||||
std::vector<std::string>* blob_file_paths_;
|
||||
std::vector<BlobFileAddition>* blob_file_additions_;
|
||||
std::unique_ptr<BlobLogWriter> writer_;
|
||||
|
||||
@@ -145,7 +145,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> expected_key_value_pairs(
|
||||
number_of_blobs);
|
||||
@@ -229,7 +229,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckMultipleFiles) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> expected_key_value_pairs(
|
||||
number_of_blobs);
|
||||
@@ -315,7 +315,7 @@ TEST_F(BlobFileBuilderTest, InlinedValues) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
for (size_t i = 0; i < number_of_blobs; ++i) {
|
||||
const std::string key = std::to_string(i);
|
||||
@@ -368,7 +368,7 @@ TEST_F(BlobFileBuilderTest, Compression) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
const std::string key("1");
|
||||
const std::string uncompressed_value(value_size, 'x');
|
||||
@@ -450,7 +450,7 @@ TEST_F(BlobFileBuilderTest, CompressionError) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack("CompressData:TamperWithReturnValue",
|
||||
[](void* arg) {
|
||||
@@ -528,7 +528,7 @@ TEST_F(BlobFileBuilderTest, Checksum) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
const std::string key("1");
|
||||
const std::string value("deadbeef");
|
||||
@@ -624,7 +624,7 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) {
|
||||
TestFileNumberGenerator(), fs_, &immutable_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id, column_family_name, io_priority,
|
||||
write_hint, nullptr /*IOTracer*/, nullptr /*BlobFileCompletionCallback*/,
|
||||
BlobFileCreationReason::kFlush, &blob_file_paths, &blob_file_additions);
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(sync_point_, [this](void* arg) {
|
||||
Status* const s = static_cast<Status*>(arg);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "db/error_handler.h"
|
||||
#include "db/event_helpers.h"
|
||||
#include "file/sst_file_manager_impl.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
@@ -17,46 +16,23 @@ namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class BlobFileCompletionCallback {
|
||||
public:
|
||||
BlobFileCompletionCallback(
|
||||
SstFileManager* sst_file_manager, InstrumentedMutex* mutex,
|
||||
ErrorHandler* error_handler, EventLogger* event_logger,
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
const std::string& dbname)
|
||||
#ifdef ROCKSDB_LITE
|
||||
BlobFileCompletionCallback(SstFileManager* /*sst_file_manager*/,
|
||||
InstrumentedMutex* /*mutex*/,
|
||||
ErrorHandler* /*error_handler*/) {}
|
||||
Status OnBlobFileCompleted(const std::string& /*file_name*/) {
|
||||
return Status::OK();
|
||||
}
|
||||
#else
|
||||
BlobFileCompletionCallback(SstFileManager* sst_file_manager,
|
||||
InstrumentedMutex* mutex,
|
||||
ErrorHandler* error_handler)
|
||||
: sst_file_manager_(sst_file_manager),
|
||||
mutex_(mutex),
|
||||
error_handler_(error_handler),
|
||||
event_logger_(event_logger),
|
||||
listeners_(listeners),
|
||||
dbname_(dbname) {}
|
||||
error_handler_(error_handler) {}
|
||||
|
||||
void OnBlobFileCreationStarted(const std::string& file_name,
|
||||
const std::string& column_family_name,
|
||||
int job_id,
|
||||
BlobFileCreationReason creation_reason) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
// Notify the listeners.
|
||||
EventHelpers::NotifyBlobFileCreationStarted(listeners_, dbname_,
|
||||
column_family_name, file_name,
|
||||
job_id, creation_reason);
|
||||
#else
|
||||
(void)file_name;
|
||||
(void)column_family_name;
|
||||
(void)job_id;
|
||||
(void)creation_reason;
|
||||
#endif
|
||||
}
|
||||
|
||||
Status OnBlobFileCompleted(const std::string& file_name,
|
||||
const std::string& column_family_name, int job_id,
|
||||
uint64_t file_number,
|
||||
BlobFileCreationReason creation_reason,
|
||||
const Status& report_status,
|
||||
const std::string& checksum_value,
|
||||
const std::string& checksum_method,
|
||||
uint64_t blob_count, uint64_t blob_bytes) {
|
||||
Status OnBlobFileCompleted(const std::string& file_name) {
|
||||
Status s;
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(sst_file_manager_);
|
||||
if (sfm) {
|
||||
// Report new blob files to SstFileManagerImpl
|
||||
@@ -69,17 +45,6 @@ class BlobFileCompletionCallback {
|
||||
error_handler_->SetBGError(s, BackgroundErrorReason::kFlush);
|
||||
}
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
// Notify the listeners.
|
||||
EventHelpers::LogAndNotifyBlobFileCreationFinished(
|
||||
event_logger_, listeners_, dbname_, column_family_name, file_name,
|
||||
job_id, file_number, creation_reason,
|
||||
(!report_status.ok() ? report_status : s),
|
||||
(checksum_value.empty() ? kUnknownFileChecksum : checksum_value),
|
||||
(checksum_method.empty() ? kUnknownFileChecksumFuncName
|
||||
: checksum_method),
|
||||
blob_count, blob_bytes);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -87,8 +52,6 @@ class BlobFileCompletionCallback {
|
||||
SstFileManager* sst_file_manager_;
|
||||
InstrumentedMutex* mutex_;
|
||||
ErrorHandler* error_handler_;
|
||||
EventLogger* event_logger_;
|
||||
std::vector<std::shared_ptr<EventListener>> listeners_;
|
||||
std::string dbname_;
|
||||
#endif // ROCKSDB_LITE
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -351,117 +351,6 @@ Status BlobFileReader::GetBlob(const ReadOptions& read_options,
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void BlobFileReader::MultiGetBlob(
|
||||
const ReadOptions& read_options,
|
||||
const autovector<std::reference_wrapper<const Slice>>& user_keys,
|
||||
const autovector<uint64_t>& offsets,
|
||||
const autovector<uint64_t>& value_sizes, autovector<Status*>& statuses,
|
||||
autovector<PinnableSlice*>& values, uint64_t* bytes_read) const {
|
||||
const size_t num_blobs = user_keys.size();
|
||||
assert(num_blobs == offsets.size());
|
||||
assert(num_blobs == value_sizes.size());
|
||||
assert(num_blobs == statuses.size());
|
||||
assert(num_blobs == values.size());
|
||||
|
||||
std::vector<FSReadRequest> read_reqs(num_blobs);
|
||||
autovector<uint64_t> adjustments;
|
||||
uint64_t total_len = 0;
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
const size_t key_size = user_keys[i].get().size();
|
||||
assert(IsValidBlobOffset(offsets[i], key_size, value_sizes[i], file_size_));
|
||||
const uint64_t adjustment =
|
||||
read_options.verify_checksums
|
||||
? BlobLogRecord::CalculateAdjustmentForRecordHeader(key_size)
|
||||
: 0;
|
||||
assert(offsets[i] >= adjustment);
|
||||
adjustments.push_back(adjustment);
|
||||
read_reqs[i].offset = offsets[i] - adjustment;
|
||||
read_reqs[i].len = value_sizes[i] + adjustment;
|
||||
total_len += read_reqs[i].len;
|
||||
}
|
||||
|
||||
RecordTick(statistics_, BLOB_DB_BLOB_FILE_BYTES_READ, total_len);
|
||||
|
||||
Buffer buf;
|
||||
AlignedBuf aligned_buf;
|
||||
|
||||
Status s;
|
||||
bool direct_io = file_reader_->use_direct_io();
|
||||
if (direct_io) {
|
||||
for (size_t i = 0; i < read_reqs.size(); ++i) {
|
||||
read_reqs[i].scratch = nullptr;
|
||||
}
|
||||
} else {
|
||||
buf.reset(new char[total_len]);
|
||||
std::ptrdiff_t pos = 0;
|
||||
for (size_t i = 0; i < read_reqs.size(); ++i) {
|
||||
read_reqs[i].scratch = buf.get() + pos;
|
||||
pos += read_reqs[i].len;
|
||||
}
|
||||
}
|
||||
TEST_SYNC_POINT("BlobFileReader::MultiGetBlob:ReadFromFile");
|
||||
s = file_reader_->MultiRead(IOOptions(), read_reqs.data(), read_reqs.size(),
|
||||
direct_io ? &aligned_buf : nullptr);
|
||||
if (!s.ok()) {
|
||||
for (auto& req : read_reqs) {
|
||||
req.status.PermitUncheckedError();
|
||||
}
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
assert(statuses[i]);
|
||||
*statuses[i] = s;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(s.ok());
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
auto& req = read_reqs[i];
|
||||
assert(statuses[i]);
|
||||
if (req.status.ok() && req.result.size() != req.len) {
|
||||
req.status = IOStatus::Corruption("Failed to read data from blob file");
|
||||
}
|
||||
*statuses[i] = req.status;
|
||||
}
|
||||
|
||||
if (read_options.verify_checksums) {
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
assert(statuses[i]);
|
||||
if (!statuses[i]->ok()) {
|
||||
continue;
|
||||
}
|
||||
const Slice& record_slice = read_reqs[i].result;
|
||||
s = VerifyBlob(record_slice, user_keys[i], value_sizes[i]);
|
||||
if (!s.ok()) {
|
||||
assert(statuses[i]);
|
||||
*statuses[i] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
assert(statuses[i]);
|
||||
if (!statuses[i]->ok()) {
|
||||
continue;
|
||||
}
|
||||
const Slice& record_slice = read_reqs[i].result;
|
||||
const Slice value_slice(record_slice.data() + adjustments[i],
|
||||
value_sizes[i]);
|
||||
s = UncompressBlobIfNeeded(value_slice, compression_type_, clock_,
|
||||
statistics_, values[i]);
|
||||
if (!s.ok()) {
|
||||
*statuses[i] = s;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_read) {
|
||||
uint64_t total_bytes = 0;
|
||||
for (const auto& req : read_reqs) {
|
||||
total_bytes += req.result.size();
|
||||
}
|
||||
*bytes_read = total_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
Status BlobFileReader::VerifyBlob(const Slice& record_slice,
|
||||
const Slice& user_key, uint64_t value_size) {
|
||||
BlobLogRecord record;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "file/random_access_file_reader.h"
|
||||
#include "rocksdb/compression_type.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -44,17 +43,6 @@ class BlobFileReader {
|
||||
CompressionType compression_type, PinnableSlice* value,
|
||||
uint64_t* bytes_read) const;
|
||||
|
||||
void MultiGetBlob(
|
||||
const ReadOptions& read_options,
|
||||
const autovector<std::reference_wrapper<const Slice>>& user_keys,
|
||||
const autovector<uint64_t>& offsets,
|
||||
const autovector<uint64_t>& value_sizes, autovector<Status*>& statuses,
|
||||
autovector<PinnableSlice*>& values, uint64_t* bytes_read) const;
|
||||
|
||||
CompressionType GetCompressionType() const { return compression_type_; }
|
||||
|
||||
uint64_t GetFileSize() const { return file_size_; }
|
||||
|
||||
private:
|
||||
BlobFileReader(std::unique_ptr<RandomAccessFileReader>&& file_reader,
|
||||
uint64_t file_size, CompressionType compression_type,
|
||||
|
||||
@@ -27,23 +27,23 @@ namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
namespace {
|
||||
|
||||
// Creates a test blob file with `num` blobs in it.
|
||||
// Creates a test blob file with a single blob in it. Note: this method
|
||||
// makes it possible to test various corner cases by allowing the caller
|
||||
// to specify the contents of various blob file header/footer fields.
|
||||
void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
uint32_t column_family_id, bool has_ttl,
|
||||
const ExpirationRange& expiration_range_header,
|
||||
const ExpirationRange& expiration_range_footer,
|
||||
uint64_t blob_file_number, const std::vector<Slice>& keys,
|
||||
const std::vector<Slice>& blobs, CompressionType compression,
|
||||
std::vector<uint64_t>& blob_offsets,
|
||||
std::vector<uint64_t>& blob_sizes) {
|
||||
uint64_t blob_file_number, const Slice& key,
|
||||
const Slice& blob, CompressionType compression_type,
|
||||
uint64_t* blob_offset, uint64_t* blob_size) {
|
||||
assert(!immutable_options.cf_paths.empty());
|
||||
size_t num = keys.size();
|
||||
assert(num == blobs.size());
|
||||
assert(num == blob_offsets.size());
|
||||
assert(num == blob_sizes.size());
|
||||
assert(blob_offset);
|
||||
assert(blob_size);
|
||||
|
||||
const std::string blob_file_path =
|
||||
BlobFileName(immutable_options.cf_paths.front().path, blob_file_number);
|
||||
|
||||
std::unique_ptr<FSWritableFile> file;
|
||||
ASSERT_OK(NewWritableFile(immutable_options.fs.get(), blob_file_path, &file,
|
||||
FileOptions()));
|
||||
@@ -59,77 +59,50 @@ void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
statistics, blob_file_number, use_fsync,
|
||||
do_flush);
|
||||
|
||||
BlobLogHeader header(column_family_id, compression, has_ttl,
|
||||
BlobLogHeader header(column_family_id, compression_type, has_ttl,
|
||||
expiration_range_header);
|
||||
|
||||
ASSERT_OK(blob_log_writer.WriteHeader(header));
|
||||
|
||||
std::vector<std::string> compressed_blobs(num);
|
||||
std::vector<Slice> blobs_to_write(num);
|
||||
if (kNoCompression == compression) {
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
blobs_to_write[i] = blobs[i];
|
||||
blob_sizes[i] = blobs[i].size();
|
||||
}
|
||||
std::string compressed_blob;
|
||||
Slice blob_to_write;
|
||||
|
||||
if (compression_type == kNoCompression) {
|
||||
blob_to_write = blob;
|
||||
*blob_size = blob.size();
|
||||
} else {
|
||||
CompressionOptions opts;
|
||||
CompressionContext context(compression);
|
||||
CompressionContext context(compression_type);
|
||||
constexpr uint64_t sample_for_compression = 0;
|
||||
|
||||
CompressionInfo info(opts, context, CompressionDict::GetEmptyDict(),
|
||||
compression, sample_for_compression);
|
||||
compression_type, sample_for_compression);
|
||||
|
||||
constexpr uint32_t compression_format_version = 2;
|
||||
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
ASSERT_TRUE(CompressData(blobs[i], info, compression_format_version,
|
||||
&compressed_blobs[i]));
|
||||
blobs_to_write[i] = compressed_blobs[i];
|
||||
blob_sizes[i] = compressed_blobs[i].size();
|
||||
}
|
||||
ASSERT_TRUE(
|
||||
CompressData(blob, info, compression_format_version, &compressed_blob));
|
||||
|
||||
blob_to_write = compressed_blob;
|
||||
*blob_size = compressed_blob.size();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
uint64_t key_offset = 0;
|
||||
ASSERT_OK(blob_log_writer.AddRecord(keys[i], blobs_to_write[i], &key_offset,
|
||||
&blob_offsets[i]));
|
||||
}
|
||||
uint64_t key_offset = 0;
|
||||
|
||||
ASSERT_OK(
|
||||
blob_log_writer.AddRecord(key, blob_to_write, &key_offset, blob_offset));
|
||||
|
||||
BlobLogFooter footer;
|
||||
footer.blob_count = num;
|
||||
footer.blob_count = 1;
|
||||
footer.expiration_range = expiration_range_footer;
|
||||
|
||||
std::string checksum_method;
|
||||
std::string checksum_value;
|
||||
|
||||
ASSERT_OK(
|
||||
blob_log_writer.AppendFooter(footer, &checksum_method, &checksum_value));
|
||||
}
|
||||
|
||||
// Creates a test blob file with a single blob in it. Note: this method
|
||||
// makes it possible to test various corner cases by allowing the caller
|
||||
// to specify the contents of various blob file header/footer fields.
|
||||
void WriteBlobFile(const ImmutableOptions& immutable_options,
|
||||
uint32_t column_family_id, bool has_ttl,
|
||||
const ExpirationRange& expiration_range_header,
|
||||
const ExpirationRange& expiration_range_footer,
|
||||
uint64_t blob_file_number, const Slice& key,
|
||||
const Slice& blob, CompressionType compression,
|
||||
uint64_t* blob_offset, uint64_t* blob_size) {
|
||||
std::vector<Slice> keys{key};
|
||||
std::vector<Slice> blobs{blob};
|
||||
std::vector<uint64_t> blob_offsets{0};
|
||||
std::vector<uint64_t> blob_sizes{0};
|
||||
WriteBlobFile(immutable_options, column_family_id, has_ttl,
|
||||
expiration_range_header, expiration_range_footer,
|
||||
blob_file_number, keys, blobs, compression, blob_offsets,
|
||||
blob_sizes);
|
||||
if (blob_offset) {
|
||||
*blob_offset = blob_offsets[0];
|
||||
}
|
||||
if (blob_size) {
|
||||
*blob_size = blob_sizes[0];
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class BlobFileReaderTest : public testing::Test {
|
||||
@@ -154,19 +127,15 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
constexpr bool has_ttl = false;
|
||||
constexpr ExpirationRange expiration_range;
|
||||
constexpr uint64_t blob_file_number = 1;
|
||||
constexpr size_t num_blobs = 3;
|
||||
const std::vector<std::string> key_strs = {"key1", "key2", "key3"};
|
||||
const std::vector<std::string> blob_strs = {"blob1", "blob2", "blob3"};
|
||||
constexpr char key[] = "key";
|
||||
constexpr char blob[] = "blob";
|
||||
|
||||
const std::vector<Slice> keys = {key_strs[0], key_strs[1], key_strs[2]};
|
||||
const std::vector<Slice> blobs = {blob_strs[0], blob_strs[1], blob_strs[2]};
|
||||
|
||||
std::vector<uint64_t> blob_offsets(keys.size());
|
||||
std::vector<uint64_t> blob_sizes(keys.size());
|
||||
uint64_t blob_offset = 0;
|
||||
uint64_t blob_size = 0;
|
||||
|
||||
WriteBlobFile(immutable_options, column_family_id, has_ttl, expiration_range,
|
||||
expiration_range, blob_file_number, keys, blobs, kNoCompression,
|
||||
blob_offsets, blob_sizes);
|
||||
expiration_range, blob_file_number, key, blob, kNoCompression,
|
||||
&blob_offset, &blob_size);
|
||||
|
||||
constexpr HistogramImpl* blob_file_read_hist = nullptr;
|
||||
|
||||
@@ -184,36 +153,10 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
PinnableSlice value;
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_OK(reader->GetBlob(read_options, keys[0], blob_offsets[0],
|
||||
blob_sizes[0], kNoCompression, &value,
|
||||
&bytes_read));
|
||||
ASSERT_EQ(value, blobs[0]);
|
||||
ASSERT_EQ(bytes_read, blob_sizes[0]);
|
||||
|
||||
// MultiGetBlob
|
||||
bytes_read = 0;
|
||||
size_t total_size = 0;
|
||||
autovector<std::reference_wrapper<const Slice>> key_refs;
|
||||
for (const auto& key_ref : keys) {
|
||||
key_refs.emplace_back(std::cref(key_ref));
|
||||
}
|
||||
autovector<uint64_t> offsets{blob_offsets[0], blob_offsets[1],
|
||||
blob_offsets[2]};
|
||||
autovector<uint64_t> sizes{blob_sizes[0], blob_sizes[1], blob_sizes[2]};
|
||||
std::array<Status, num_blobs> statuses_buf;
|
||||
autovector<Status*> statuses{&statuses_buf[0], &statuses_buf[1],
|
||||
&statuses_buf[2]};
|
||||
std::array<PinnableSlice, num_blobs> value_buf;
|
||||
autovector<PinnableSlice*> values{&value_buf[0], &value_buf[1],
|
||||
&value_buf[2]};
|
||||
reader->MultiGetBlob(read_options, key_refs, offsets, sizes, statuses,
|
||||
values, &bytes_read);
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
ASSERT_OK(statuses_buf[i]);
|
||||
ASSERT_EQ(value_buf[i], blobs[i]);
|
||||
total_size += blob_sizes[i];
|
||||
}
|
||||
ASSERT_EQ(bytes_read, total_size);
|
||||
ASSERT_OK(reader->GetBlob(read_options, key, blob_offset, blob_size,
|
||||
kNoCompression, &value, &bytes_read));
|
||||
ASSERT_EQ(value, blob);
|
||||
ASSERT_EQ(bytes_read, blob_size);
|
||||
}
|
||||
|
||||
read_options.verify_checksums = true;
|
||||
@@ -222,15 +165,14 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
PinnableSlice value;
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_OK(reader->GetBlob(read_options, keys[1], blob_offsets[1],
|
||||
blob_sizes[1], kNoCompression, &value,
|
||||
&bytes_read));
|
||||
ASSERT_EQ(value, blobs[1]);
|
||||
ASSERT_OK(reader->GetBlob(read_options, key, blob_offset, blob_size,
|
||||
kNoCompression, &value, &bytes_read));
|
||||
ASSERT_EQ(value, blob);
|
||||
|
||||
const uint64_t key_size = keys[1].size();
|
||||
constexpr uint64_t key_size = sizeof(key) - 1;
|
||||
ASSERT_EQ(bytes_read,
|
||||
BlobLogRecord::CalculateAdjustmentForRecordHeader(key_size) +
|
||||
blob_sizes[1]);
|
||||
blob_size);
|
||||
}
|
||||
|
||||
// Invalid offset (too close to start of file)
|
||||
@@ -239,9 +181,8 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_TRUE(reader
|
||||
->GetBlob(read_options, keys[0], blob_offsets[0] - 1,
|
||||
blob_sizes[0], kNoCompression, &value,
|
||||
&bytes_read)
|
||||
->GetBlob(read_options, key, blob_offset - 1, blob_size,
|
||||
kNoCompression, &value, &bytes_read)
|
||||
.IsCorruption());
|
||||
ASSERT_EQ(bytes_read, 0);
|
||||
}
|
||||
@@ -252,9 +193,8 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_TRUE(reader
|
||||
->GetBlob(read_options, keys[2], blob_offsets[2] + 1,
|
||||
blob_sizes[2], kNoCompression, &value,
|
||||
&bytes_read)
|
||||
->GetBlob(read_options, key, blob_offset + 1, blob_size,
|
||||
kNoCompression, &value, &bytes_read)
|
||||
.IsCorruption());
|
||||
ASSERT_EQ(bytes_read, 0);
|
||||
}
|
||||
@@ -265,8 +205,8 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_TRUE(reader
|
||||
->GetBlob(read_options, keys[0], blob_offsets[0],
|
||||
blob_sizes[0], kZSTD, &value, &bytes_read)
|
||||
->GetBlob(read_options, key, blob_offset, blob_size, kZSTD,
|
||||
&value, &bytes_read)
|
||||
.IsCorruption());
|
||||
ASSERT_EQ(bytes_read, 0);
|
||||
}
|
||||
@@ -279,82 +219,23 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
|
||||
ASSERT_TRUE(reader
|
||||
->GetBlob(read_options, shorter_key,
|
||||
blob_offsets[0] -
|
||||
(keys[0].size() - sizeof(shorter_key) + 1),
|
||||
blob_sizes[0], kNoCompression, &value,
|
||||
&bytes_read)
|
||||
blob_offset - (sizeof(key) - sizeof(shorter_key)),
|
||||
blob_size, kNoCompression, &value, &bytes_read)
|
||||
.IsCorruption());
|
||||
ASSERT_EQ(bytes_read, 0);
|
||||
|
||||
// MultiGetBlob
|
||||
autovector<std::reference_wrapper<const Slice>> key_refs;
|
||||
for (const auto& key_ref : keys) {
|
||||
key_refs.emplace_back(std::cref(key_ref));
|
||||
}
|
||||
Slice shorter_key_slice(shorter_key, sizeof(shorter_key) - 1);
|
||||
key_refs[1] = std::cref(shorter_key_slice);
|
||||
|
||||
autovector<uint64_t> offsets{
|
||||
blob_offsets[0],
|
||||
blob_offsets[1] - (keys[1].size() - key_refs[1].get().size()),
|
||||
blob_offsets[2]};
|
||||
autovector<uint64_t> sizes{blob_sizes[0], blob_sizes[1], blob_sizes[2]};
|
||||
std::array<Status, num_blobs> statuses_buf;
|
||||
autovector<Status*> statuses{&statuses_buf[0], &statuses_buf[1],
|
||||
&statuses_buf[2]};
|
||||
std::array<PinnableSlice, num_blobs> value_buf;
|
||||
autovector<PinnableSlice*> values{&value_buf[0], &value_buf[1],
|
||||
&value_buf[2]};
|
||||
reader->MultiGetBlob(read_options, key_refs, offsets, sizes, statuses,
|
||||
values, &bytes_read);
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
if (i == 1) {
|
||||
ASSERT_TRUE(statuses_buf[i].IsCorruption());
|
||||
} else {
|
||||
ASSERT_OK(statuses_buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Incorrect key
|
||||
{
|
||||
constexpr char incorrect_key[] = "foo1";
|
||||
constexpr char incorrect_key[] = "foo";
|
||||
PinnableSlice value;
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_TRUE(reader
|
||||
->GetBlob(read_options, incorrect_key, blob_offsets[0],
|
||||
blob_sizes[0], kNoCompression, &value,
|
||||
&bytes_read)
|
||||
->GetBlob(read_options, incorrect_key, blob_offset,
|
||||
blob_size, kNoCompression, &value, &bytes_read)
|
||||
.IsCorruption());
|
||||
ASSERT_EQ(bytes_read, 0);
|
||||
|
||||
// MultiGetBlob
|
||||
autovector<std::reference_wrapper<const Slice>> key_refs;
|
||||
for (const auto& key_ref : keys) {
|
||||
key_refs.emplace_back(std::cref(key_ref));
|
||||
}
|
||||
Slice wrong_key_slice(incorrect_key, sizeof(incorrect_key) - 1);
|
||||
key_refs[2] = std::cref(wrong_key_slice);
|
||||
|
||||
autovector<uint64_t> offsets{blob_offsets[0], blob_offsets[1],
|
||||
blob_offsets[2]};
|
||||
autovector<uint64_t> sizes{blob_sizes[0], blob_sizes[1], blob_sizes[2]};
|
||||
std::array<Status, num_blobs> statuses_buf;
|
||||
autovector<Status*> statuses{&statuses_buf[0], &statuses_buf[1],
|
||||
&statuses_buf[2]};
|
||||
std::array<PinnableSlice, num_blobs> value_buf;
|
||||
autovector<PinnableSlice*> values{&value_buf[0], &value_buf[1],
|
||||
&value_buf[2]};
|
||||
reader->MultiGetBlob(read_options, key_refs, offsets, sizes, statuses,
|
||||
values, &bytes_read);
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
if (i == num_blobs - 1) {
|
||||
ASSERT_TRUE(statuses_buf[i].IsCorruption());
|
||||
} else {
|
||||
ASSERT_OK(statuses_buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Incorrect value size
|
||||
@@ -363,35 +244,10 @@ TEST_F(BlobFileReaderTest, CreateReaderAndGetBlob) {
|
||||
uint64_t bytes_read = 0;
|
||||
|
||||
ASSERT_TRUE(reader
|
||||
->GetBlob(read_options, keys[1], blob_offsets[1],
|
||||
blob_sizes[1] + 1, kNoCompression, &value,
|
||||
&bytes_read)
|
||||
->GetBlob(read_options, key, blob_offset, blob_size + 1,
|
||||
kNoCompression, &value, &bytes_read)
|
||||
.IsCorruption());
|
||||
ASSERT_EQ(bytes_read, 0);
|
||||
|
||||
// MultiGetBlob
|
||||
autovector<std::reference_wrapper<const Slice>> key_refs;
|
||||
for (const auto& key_ref : keys) {
|
||||
key_refs.emplace_back(std::cref(key_ref));
|
||||
}
|
||||
autovector<uint64_t> offsets{blob_offsets[0], blob_offsets[1],
|
||||
blob_offsets[2]};
|
||||
autovector<uint64_t> sizes{blob_sizes[0], blob_sizes[1] + 1, blob_sizes[2]};
|
||||
std::array<Status, num_blobs> statuses_buf;
|
||||
autovector<Status*> statuses{&statuses_buf[0], &statuses_buf[1],
|
||||
&statuses_buf[2]};
|
||||
std::array<PinnableSlice, num_blobs> value_buf;
|
||||
autovector<PinnableSlice*> values{&value_buf[0], &value_buf[1],
|
||||
&value_buf[2]};
|
||||
reader->MultiGetBlob(read_options, key_refs, offsets, sizes, statuses,
|
||||
values, &bytes_read);
|
||||
for (size_t i = 0; i < num_blobs; ++i) {
|
||||
if (i != 1) {
|
||||
ASSERT_OK(statuses_buf[i]);
|
||||
} else {
|
||||
ASSERT_TRUE(statuses_buf[i].IsCorruption());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,6 @@ class BlobIndex {
|
||||
|
||||
BlobIndex() : type_(Type::kUnknown) {}
|
||||
|
||||
BlobIndex(const BlobIndex&) = default;
|
||||
BlobIndex& operator=(const BlobIndex&) = default;
|
||||
|
||||
bool IsInlined() const { return type_ == Type::kInlinedTTL; }
|
||||
|
||||
bool HasTTL() const {
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
#include "db/blob/blob_index.h"
|
||||
#include "db/blob/blob_log_format.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/sync_point.h"
|
||||
@@ -127,237 +125,6 @@ TEST_F(DBBlobBasicTest, MultiGetBlobs) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBBlobBasicTest, MultiGetWithDirectIO) {
|
||||
Options options = GetDefaultOptions();
|
||||
|
||||
// First, create an external SST file ["b"].
|
||||
const std::string file_path = dbname_ + "/test.sst";
|
||||
{
|
||||
SstFileWriter sst_file_writer(EnvOptions(), GetDefaultOptions());
|
||||
Status s = sst_file_writer.Open(file_path);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_OK(sst_file_writer.Put("b", "b_value"));
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
}
|
||||
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 1000;
|
||||
options.use_direct_reads = true;
|
||||
options.allow_ingest_behind = true;
|
||||
|
||||
// Open DB with fixed-prefix sst-partitioner so that compaction will cut
|
||||
// new table file when encountering a new key whose 1-byte prefix changes.
|
||||
constexpr size_t key_len = 1;
|
||||
options.sst_partitioner_factory =
|
||||
NewSstPartitionerFixedPrefixFactory(key_len);
|
||||
|
||||
Status s = TryReopen(options);
|
||||
if (s.IsInvalidArgument()) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires direct IO support");
|
||||
return;
|
||||
}
|
||||
ASSERT_OK(s);
|
||||
|
||||
constexpr size_t num_keys = 3;
|
||||
constexpr size_t blob_size = 3000;
|
||||
|
||||
constexpr char first_key[] = "a";
|
||||
const std::string first_blob(blob_size, 'a');
|
||||
ASSERT_OK(Put(first_key, first_blob));
|
||||
|
||||
constexpr char second_key[] = "b";
|
||||
const std::string second_blob(2 * blob_size, 'b');
|
||||
ASSERT_OK(Put(second_key, second_blob));
|
||||
|
||||
constexpr char third_key[] = "d";
|
||||
const std::string third_blob(blob_size, 'd');
|
||||
ASSERT_OK(Put(third_key, third_blob));
|
||||
|
||||
// first_blob, second_blob and third_blob in the same blob file.
|
||||
// SST Blob file
|
||||
// L0 ["a", "b", "d"] |'aaaa', 'bbbb', 'dddd'|
|
||||
// | | | ^ ^ ^
|
||||
// | | | | | |
|
||||
// | | +---------|-------|--------+
|
||||
// | +-----------------|-------+
|
||||
// +-------------------------+
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr char fourth_key[] = "c";
|
||||
const std::string fourth_blob(blob_size, 'c');
|
||||
ASSERT_OK(Put(fourth_key, fourth_blob));
|
||||
// fourth_blob in another blob file.
|
||||
// SST Blob file SST Blob file
|
||||
// L0 ["a", "b", "d"] |'aaaa', 'bbbb', 'dddd'| ["c"] |'cccc'|
|
||||
// | | | ^ ^ ^ | ^
|
||||
// | | | | | | | |
|
||||
// | | +---------|-------|--------+ +-------+
|
||||
// | +-----------------|-------+
|
||||
// +-------------------------+
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), /*begin=*/nullptr,
|
||||
/*end=*/nullptr));
|
||||
|
||||
// Due to the above sst partitioner, we get 4 L1 files. The blob files are
|
||||
// unchanged.
|
||||
// |'aaaa', 'bbbb', 'dddd'| |'cccc'|
|
||||
// ^ ^ ^ ^
|
||||
// | | | |
|
||||
// L0 | | | |
|
||||
// L1 ["a"] ["b"] ["c"] | | ["d"] |
|
||||
// | | | | | |
|
||||
// | | +---------|-------|---------------+
|
||||
// | +-----------------|-------+
|
||||
// +-------------------------+
|
||||
ASSERT_EQ(4, NumTableFilesAtLevel(/*level=*/1));
|
||||
|
||||
{
|
||||
// Ingest the external SST file into bottommost level.
|
||||
std::vector<std::string> ext_files{file_path};
|
||||
IngestExternalFileOptions opts;
|
||||
opts.ingest_behind = true;
|
||||
ASSERT_OK(
|
||||
db_->IngestExternalFile(db_->DefaultColumnFamily(), ext_files, opts));
|
||||
}
|
||||
|
||||
// Now the database becomes as follows.
|
||||
// |'aaaa', 'bbbb', 'dddd'| |'cccc'|
|
||||
// ^ ^ ^ ^
|
||||
// | | | |
|
||||
// L0 | | | |
|
||||
// L1 ["a"] ["b"] ["c"] | | ["d"] |
|
||||
// | | | | | |
|
||||
// | | +---------|-------|---------------+
|
||||
// | +-----------------|-------+
|
||||
// +-------------------------+
|
||||
//
|
||||
// L6 ["b"]
|
||||
|
||||
{
|
||||
// Compact ["b"] to bottommost level.
|
||||
Slice begin = Slice(second_key);
|
||||
Slice end = Slice(second_key);
|
||||
CompactRangeOptions cro;
|
||||
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
|
||||
ASSERT_OK(db_->CompactRange(cro, &begin, &end));
|
||||
}
|
||||
|
||||
// |'aaaa', 'bbbb', 'dddd'| |'cccc'|
|
||||
// ^ ^ ^ ^
|
||||
// | | | |
|
||||
// L0 | | | |
|
||||
// L1 ["a"] ["c"] | | ["d"] |
|
||||
// | | | | |
|
||||
// | +---------|-------|---------------+
|
||||
// | +-----------------|-------+
|
||||
// +-------|-----------------+
|
||||
// |
|
||||
// L6 ["b"]
|
||||
ASSERT_EQ(3, NumTableFilesAtLevel(/*level=*/1));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(/*level=*/6));
|
||||
|
||||
bool called = false;
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"RandomAccessFileReader::MultiRead:AlignedReqs", [&](void* arg) {
|
||||
auto* aligned_reqs = static_cast<std::vector<FSReadRequest>*>(arg);
|
||||
assert(aligned_reqs);
|
||||
ASSERT_EQ(1, aligned_reqs->size());
|
||||
called = true;
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::array<Slice, num_keys> keys{{first_key, third_key, second_key}};
|
||||
|
||||
{
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
// The MultiGet(), when constructing the KeyContexts, will process the keys
|
||||
// in such order: a, d, b. The reason is that ["a"] and ["d"] are in L1,
|
||||
// while ["b"] resides in L6.
|
||||
// Consequently, the original FSReadRequest list prepared by
|
||||
// Version::MultiGetblob() will be for "a", "d" and "b". It is unsorted as
|
||||
// follows:
|
||||
//
|
||||
// ["a", offset=30, len=3033],
|
||||
// ["d", offset=9096, len=3033],
|
||||
// ["b", offset=3063, len=6033]
|
||||
//
|
||||
// If we do not sort them before calling MultiRead() in DirectIO, then the
|
||||
// underlying IO merging logic will yield two requests.
|
||||
//
|
||||
// [offset=0, len=4096] (for "a")
|
||||
// [offset=0, len=12288] (result of merging the request for "d" and "b")
|
||||
//
|
||||
// We need to sort them in Version::MultiGetBlob() so that the underlying
|
||||
// IO merging logic in DirectIO mode works as expected. The correct
|
||||
// behavior will be one aligned request:
|
||||
//
|
||||
// [offset=0, len=12288]
|
||||
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
ASSERT_TRUE(called);
|
||||
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(values[0], first_blob);
|
||||
|
||||
ASSERT_OK(statuses[1]);
|
||||
ASSERT_EQ(values[1], third_blob);
|
||||
|
||||
ASSERT_OK(statuses[2]);
|
||||
ASSERT_EQ(values[2], second_blob);
|
||||
}
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
TEST_F(DBBlobBasicTest, MultiGetBlobsFromMultipleFiles) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
constexpr size_t kNumBlobFiles = 3;
|
||||
constexpr size_t kNumBlobsPerFile = 3;
|
||||
constexpr size_t kNumKeys = kNumBlobsPerFile * kNumBlobFiles;
|
||||
|
||||
std::vector<std::string> key_strs;
|
||||
std::vector<std::string> value_strs;
|
||||
for (size_t i = 0; i < kNumBlobFiles; ++i) {
|
||||
for (size_t j = 0; j < kNumBlobsPerFile; ++j) {
|
||||
std::string key = "key" + std::to_string(i) + "_" + std::to_string(j);
|
||||
std::string value =
|
||||
"value_as_blob" + std::to_string(i) + "_" + std::to_string(j);
|
||||
ASSERT_OK(Put(key, value));
|
||||
key_strs.push_back(key);
|
||||
value_strs.push_back(value);
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
assert(key_strs.size() == kNumKeys);
|
||||
std::array<Slice, kNumKeys> keys;
|
||||
for (size_t i = 0; i < keys.size(); ++i) {
|
||||
keys[i] = key_strs[i];
|
||||
}
|
||||
std::array<PinnableSlice, kNumKeys> values;
|
||||
std::array<Status, kNumKeys> statuses;
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), kNumKeys, &keys[0],
|
||||
&values[0], &statuses[0]);
|
||||
|
||||
for (size_t i = 0; i < kNumKeys; ++i) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
ASSERT_EQ(value_strs[i], values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, GetBlob_CorruptIndex) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
@@ -381,83 +148,6 @@ TEST_F(DBBlobBasicTest, GetBlob_CorruptIndex) {
|
||||
.IsCorruption());
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, MultiGetBlob_CorruptIndex) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
options.create_if_missing = true;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
constexpr size_t kNumOfKeys = 3;
|
||||
std::array<std::string, kNumOfKeys> key_strs;
|
||||
std::array<std::string, kNumOfKeys> value_strs;
|
||||
std::array<Slice, kNumOfKeys + 1> keys;
|
||||
for (size_t i = 0; i < kNumOfKeys; ++i) {
|
||||
key_strs[i] = "foo" + std::to_string(i);
|
||||
value_strs[i] = "blob_value" + std::to_string(i);
|
||||
ASSERT_OK(Put(key_strs[i], value_strs[i]));
|
||||
keys[i] = key_strs[i];
|
||||
}
|
||||
|
||||
constexpr char key[] = "key";
|
||||
{
|
||||
// Fake a corrupt blob index.
|
||||
const std::string blob_index("foobar");
|
||||
WriteBatch batch;
|
||||
ASSERT_OK(WriteBatchInternal::PutBlobIndex(&batch, 0, key, blob_index));
|
||||
ASSERT_OK(db_->Write(WriteOptions(), &batch));
|
||||
keys[kNumOfKeys] = Slice(static_cast<const char*>(key), sizeof(key) - 1);
|
||||
}
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::array<PinnableSlice, kNumOfKeys + 1> values;
|
||||
std::array<Status, kNumOfKeys + 1> statuses;
|
||||
db_->MultiGet(ReadOptions(), dbfull()->DefaultColumnFamily(), kNumOfKeys + 1,
|
||||
keys.data(), values.data(), statuses.data(),
|
||||
/*sorted_input=*/false);
|
||||
for (size_t i = 0; i < kNumOfKeys + 1; ++i) {
|
||||
if (i != kNumOfKeys) {
|
||||
ASSERT_OK(statuses[i]);
|
||||
ASSERT_EQ("blob_value" + std::to_string(i), values[i]);
|
||||
} else {
|
||||
ASSERT_TRUE(statuses[i].IsCorruption());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, MultiGetBlob_ExceedSoftLimit) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
constexpr size_t kNumOfKeys = 3;
|
||||
std::array<std::string, kNumOfKeys> key_bufs;
|
||||
std::array<std::string, kNumOfKeys> value_bufs;
|
||||
std::array<Slice, kNumOfKeys> keys;
|
||||
for (size_t i = 0; i < kNumOfKeys; ++i) {
|
||||
key_bufs[i] = "foo" + std::to_string(i);
|
||||
value_bufs[i] = "blob_value" + std::to_string(i);
|
||||
ASSERT_OK(Put(key_bufs[i], value_bufs[i]));
|
||||
keys[i] = key_bufs[i];
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::array<PinnableSlice, kNumOfKeys> values;
|
||||
std::array<Status, kNumOfKeys> statuses;
|
||||
ReadOptions read_opts;
|
||||
read_opts.value_size_soft_limit = 1;
|
||||
db_->MultiGet(read_opts, dbfull()->DefaultColumnFamily(), kNumOfKeys,
|
||||
keys.data(), values.data(), statuses.data(),
|
||||
/*sorted_input=*/true);
|
||||
for (const auto& s : statuses) {
|
||||
ASSERT_TRUE(s.IsAborted());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, GetBlob_InlinedTTLIndex) {
|
||||
constexpr uint64_t min_blob_size = 10;
|
||||
|
||||
@@ -677,147 +367,6 @@ TEST_F(DBBlobBasicTest, MultiGetMergeBlobWithPut) {
|
||||
ASSERT_EQ(values[2], "v2_0");
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBBlobBasicTest, Properties) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
constexpr char key1[] = "key1";
|
||||
constexpr size_t key1_size = sizeof(key1) - 1;
|
||||
|
||||
constexpr char key2[] = "key2";
|
||||
constexpr size_t key2_size = sizeof(key2) - 1;
|
||||
|
||||
constexpr char key3[] = "key3";
|
||||
constexpr size_t key3_size = sizeof(key3) - 1;
|
||||
|
||||
constexpr char blob[] = "0000000000";
|
||||
constexpr size_t blob_size = sizeof(blob) - 1;
|
||||
|
||||
ASSERT_OK(Put(key1, blob));
|
||||
ASSERT_OK(Put(key2, blob));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr size_t first_blob_file_expected_size =
|
||||
BlobLogHeader::kSize +
|
||||
BlobLogRecord::CalculateAdjustmentForRecordHeader(key1_size) + blob_size +
|
||||
BlobLogRecord::CalculateAdjustmentForRecordHeader(key2_size) + blob_size +
|
||||
BlobLogFooter::kSize;
|
||||
|
||||
ASSERT_OK(Put(key3, blob));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr size_t second_blob_file_expected_size =
|
||||
BlobLogHeader::kSize +
|
||||
BlobLogRecord::CalculateAdjustmentForRecordHeader(key3_size) + blob_size +
|
||||
BlobLogFooter::kSize;
|
||||
|
||||
constexpr size_t total_expected_size =
|
||||
first_blob_file_expected_size + second_blob_file_expected_size;
|
||||
|
||||
// Number of blob files
|
||||
uint64_t num_blob_files = 0;
|
||||
ASSERT_TRUE(
|
||||
db_->GetIntProperty(DB::Properties::kNumBlobFiles, &num_blob_files));
|
||||
ASSERT_EQ(num_blob_files, 2);
|
||||
|
||||
// Total size of live blob files
|
||||
uint64_t live_blob_file_size = 0;
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kLiveBlobFileSize,
|
||||
&live_blob_file_size));
|
||||
ASSERT_EQ(live_blob_file_size, total_expected_size);
|
||||
|
||||
// Total size of all blob files across all versions
|
||||
// Note: this should be the same as above since we only have one
|
||||
// version at this point.
|
||||
uint64_t total_blob_file_size = 0;
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kTotalBlobFileSize,
|
||||
&total_blob_file_size));
|
||||
ASSERT_EQ(total_blob_file_size, total_expected_size);
|
||||
|
||||
// Delete key2 to create some garbage
|
||||
ASSERT_OK(Delete(key2));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr Slice* begin = nullptr;
|
||||
constexpr Slice* end = nullptr;
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), begin, end));
|
||||
|
||||
constexpr size_t expected_garbage_size =
|
||||
BlobLogRecord::CalculateAdjustmentForRecordHeader(key2_size) + blob_size;
|
||||
|
||||
// Blob file stats
|
||||
std::string blob_stats;
|
||||
ASSERT_TRUE(db_->GetProperty(DB::Properties::kBlobStats, &blob_stats));
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "Number of blob files: 2\nTotal size of blob files: "
|
||||
<< total_expected_size
|
||||
<< "\nTotal size of garbage in blob files: " << expected_garbage_size
|
||||
<< '\n';
|
||||
|
||||
ASSERT_EQ(blob_stats, oss.str());
|
||||
}
|
||||
|
||||
TEST_F(DBBlobBasicTest, PropertiesMultiVersion) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
constexpr char key1[] = "key1";
|
||||
constexpr char key2[] = "key2";
|
||||
constexpr char key3[] = "key3";
|
||||
|
||||
constexpr size_t key_size = sizeof(key1) - 1;
|
||||
static_assert(sizeof(key2) - 1 == key_size, "unexpected size: key2");
|
||||
static_assert(sizeof(key3) - 1 == key_size, "unexpected size: key3");
|
||||
|
||||
constexpr char blob[] = "0000000000";
|
||||
constexpr size_t blob_size = sizeof(blob) - 1;
|
||||
|
||||
ASSERT_OK(Put(key1, blob));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put(key2, blob));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// Create an iterator to keep the current version alive
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
// Note: the Delete and subsequent compaction results in the first blob file
|
||||
// not making it to the final version. (It is still part of the previous
|
||||
// version kept alive by the iterator though.) On the other hand, the Put
|
||||
// results in a third blob file.
|
||||
ASSERT_OK(Delete(key1));
|
||||
ASSERT_OK(Put(key3, blob));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr Slice* begin = nullptr;
|
||||
constexpr Slice* end = nullptr;
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), begin, end));
|
||||
|
||||
// Total size of all blob files across all versions: between the two versions,
|
||||
// we should have three blob files of the same size with one blob each.
|
||||
// The version kept alive by the iterator contains the first and the second
|
||||
// blob file, while the final version contains the second and the third blob
|
||||
// file. (The second blob file is thus shared by the two versions but should
|
||||
// be counted only once.)
|
||||
uint64_t total_blob_file_size = 0;
|
||||
ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kTotalBlobFileSize,
|
||||
&total_blob_file_size));
|
||||
ASSERT_EQ(total_blob_file_size,
|
||||
3 * (BlobLogHeader::kSize +
|
||||
BlobLogRecord::CalculateAdjustmentForRecordHeader(key_size) +
|
||||
blob_size + BlobLogFooter::kSize));
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
class DBBlobBasicIOErrorTest : public DBBlobBasicTest,
|
||||
public testing::WithParamInterface<std::string> {
|
||||
protected:
|
||||
@@ -830,21 +379,11 @@ class DBBlobBasicIOErrorTest : public DBBlobBasicTest,
|
||||
std::string sync_point_;
|
||||
};
|
||||
|
||||
class DBBlobBasicIOErrorMultiGetTest : public DBBlobBasicIOErrorTest {
|
||||
public:
|
||||
DBBlobBasicIOErrorMultiGetTest() : DBBlobBasicIOErrorTest() {}
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBBlobBasicTest, DBBlobBasicIOErrorTest,
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"BlobFileReader::OpenFile:NewRandomAccessFile",
|
||||
"BlobFileReader::GetBlob:ReadFromFile"}));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBBlobBasicTest, DBBlobBasicIOErrorMultiGetTest,
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"BlobFileReader::OpenFile:NewRandomAccessFile",
|
||||
"BlobFileReader::MultiGetBlob:ReadFromFile"}));
|
||||
|
||||
TEST_P(DBBlobBasicIOErrorTest, GetBlob_IOError) {
|
||||
Options options;
|
||||
options.env = fault_injection_env_.get();
|
||||
@@ -874,7 +413,7 @@ TEST_P(DBBlobBasicIOErrorTest, GetBlob_IOError) {
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
TEST_P(DBBlobBasicIOErrorMultiGetTest, MultiGetBlobs_IOError) {
|
||||
TEST_P(DBBlobBasicIOErrorTest, MultiGetBlobs_IOError) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_injection_env_.get();
|
||||
options.enable_blob_files = true;
|
||||
@@ -916,53 +455,6 @@ TEST_P(DBBlobBasicIOErrorMultiGetTest, MultiGetBlobs_IOError) {
|
||||
ASSERT_TRUE(statuses[1].IsIOError());
|
||||
}
|
||||
|
||||
TEST_P(DBBlobBasicIOErrorMultiGetTest, MultipleBlobFiles) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_injection_env_.get();
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
constexpr size_t num_keys = 2;
|
||||
|
||||
constexpr char key1[] = "key1";
|
||||
constexpr char value1[] = "blob1";
|
||||
|
||||
ASSERT_OK(Put(key1, value1));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr char key2[] = "key2";
|
||||
constexpr char value2[] = "blob2";
|
||||
|
||||
ASSERT_OK(Put(key2, value2));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::array<Slice, num_keys> keys{{key1, key2}};
|
||||
std::array<PinnableSlice, num_keys> values;
|
||||
std::array<Status, num_keys> statuses;
|
||||
|
||||
bool first_blob_file = true;
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
sync_point_, [&first_blob_file, this](void* /* arg */) {
|
||||
if (first_blob_file) {
|
||||
first_blob_file = false;
|
||||
return;
|
||||
}
|
||||
fault_injection_env_->SetFilesystemActive(false,
|
||||
Status::IOError(sync_point_));
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
db_->MultiGet(ReadOptions(), db_->DefaultColumnFamily(), num_keys,
|
||||
keys.data(), values.data(), statuses.data());
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_EQ(value1, values[0]);
|
||||
ASSERT_TRUE(statuses[1].IsIOError());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ReadBlobCompactionFilter : public CompactionFilter {
|
||||
@@ -1018,17 +510,8 @@ TEST_P(DBBlobBasicIOErrorTest, CompactionFilterReadBlob_IOError) {
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
void RegisterCustomObjects(int argc, char** argv);
|
||||
}
|
||||
#else
|
||||
void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -592,17 +593,8 @@ TEST_F(DBBlobCompactionTest, MergeBlobWithBase) {
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
void RegisterCustomObjects(int argc, char** argv);
|
||||
}
|
||||
#else
|
||||
void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -74,17 +74,8 @@ TEST_F(DBBlobCorruptionTest, VerifyWholeBlobFileChecksum) {
|
||||
#endif // !ROCKSDB_LITE
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
void RegisterCustomObjects(int argc, char** argv);
|
||||
}
|
||||
#else
|
||||
void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -564,17 +564,8 @@ TEST_F(DBBlobIndexTest, IntegratedBlobIterate) {
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
void RegisterCustomObjects(int argc, char** argv);
|
||||
}
|
||||
#else
|
||||
void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // !ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+8
-9
@@ -65,8 +65,7 @@ Status BuildTable(
|
||||
SequenceNumber earliest_write_conflict_snapshot,
|
||||
SnapshotChecker* snapshot_checker, bool paranoid_file_checks,
|
||||
InternalStats* internal_stats, IOStatus* io_status,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCreationReason blob_creation_reason, EventLogger* event_logger,
|
||||
const std::shared_ptr<IOTracer>& io_tracer, EventLogger* event_logger,
|
||||
int job_id, const Env::IOPriority io_priority,
|
||||
TableProperties* table_properties, Env::WriteLifeTimeHint write_hint,
|
||||
const std::string* full_history_ts_low,
|
||||
@@ -179,12 +178,12 @@ Status BuildTable(
|
||||
|
||||
std::unique_ptr<BlobFileBuilder> blob_file_builder(
|
||||
(mutable_cf_options.enable_blob_files && blob_file_additions)
|
||||
? new BlobFileBuilder(
|
||||
versions, fs, &ioptions, &mutable_cf_options, &file_options,
|
||||
job_id, tboptions.column_family_id,
|
||||
tboptions.column_family_name, io_priority, write_hint,
|
||||
io_tracer, blob_callback, blob_creation_reason,
|
||||
&blob_file_paths, blob_file_additions)
|
||||
? new BlobFileBuilder(versions, fs, &ioptions, &mutable_cf_options,
|
||||
&file_options, job_id,
|
||||
tboptions.column_family_id,
|
||||
tboptions.column_family_name, io_priority,
|
||||
write_hint, io_tracer, blob_callback,
|
||||
&blob_file_paths, blob_file_additions)
|
||||
: nullptr);
|
||||
|
||||
CompactionIterator c_iter(
|
||||
@@ -312,7 +311,7 @@ Status BuildTable(
|
||||
if (s.ok()) {
|
||||
s = blob_file_builder->Finish();
|
||||
} else {
|
||||
blob_file_builder->Abandon(s);
|
||||
blob_file_builder->Abandon();
|
||||
}
|
||||
blob_file_builder.reset();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ extern Status BuildTable(
|
||||
SnapshotChecker* snapshot_checker, bool paranoid_file_checks,
|
||||
InternalStats* internal_stats, IOStatus* io_status,
|
||||
const std::shared_ptr<IOTracer>& io_tracer,
|
||||
BlobFileCreationReason blob_creation_reason,
|
||||
EventLogger* event_logger = nullptr, int job_id = 0,
|
||||
const Env::IOPriority io_priority = Env::IO_HIGH,
|
||||
TableProperties* table_properties = nullptr,
|
||||
|
||||
+2
-5
@@ -29,6 +29,7 @@
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_controller.h"
|
||||
#include "file/sst_file_manager_impl.h"
|
||||
#include "memtable/hash_skiplist_rep.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/port.h"
|
||||
@@ -202,7 +203,7 @@ Status CheckCFPathsSupported(const DBOptions& db_options,
|
||||
namespace {
|
||||
const uint64_t kDefaultTtl = 0xfffffffffffffffe;
|
||||
const uint64_t kDefaultPeriodicCompSecs = 0xfffffffffffffffe;
|
||||
} // namespace
|
||||
}; // namespace
|
||||
|
||||
ColumnFamilyOptions SanitizeOptions(const ImmutableDBOptions& db_options,
|
||||
const ColumnFamilyOptions& src) {
|
||||
@@ -1048,10 +1049,6 @@ uint64_t ColumnFamilyData::GetTotalSstFilesSize() const {
|
||||
return VersionSet::GetTotalSstFilesSize(dummy_versions_);
|
||||
}
|
||||
|
||||
uint64_t ColumnFamilyData::GetTotalBlobFileSize() const {
|
||||
return VersionSet::GetTotalBlobFileSize(dummy_versions_);
|
||||
}
|
||||
|
||||
uint64_t ColumnFamilyData::GetLiveSstFilesSize() const {
|
||||
return current_->GetSstFilesSize();
|
||||
}
|
||||
|
||||
@@ -357,7 +357,6 @@ class ColumnFamilyData {
|
||||
uint64_t GetNumLiveVersions() const; // REQUIRE: DB mutex held
|
||||
uint64_t GetTotalSstFilesSize() const; // REQUIRE: DB mutex held
|
||||
uint64_t GetLiveSstFilesSize() const; // REQUIRE: DB mutex held
|
||||
uint64_t GetTotalBlobFileSize() const; // REQUIRE: DB mutex held
|
||||
void SetMemtable(MemTable* new_mem) {
|
||||
uint64_t memtable_id = last_memtable_id_.fetch_add(1) + 1;
|
||||
new_mem->SetID(memtable_id);
|
||||
|
||||
@@ -2975,8 +2975,7 @@ TEST_P(ColumnFamilyTest, FlushCloseWALFiles) {
|
||||
SpecialEnv env(Env::Default());
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2));
|
||||
column_family_options_.memtable_factory.reset(new SpecialSkipListFactory(2));
|
||||
Open();
|
||||
CreateColumnFamilies({"one"});
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
@@ -3021,8 +3020,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile1) {
|
||||
SpecialEnv env(Env::Default());
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2));
|
||||
column_family_options_.memtable_factory.reset(new SpecialSkipListFactory(2));
|
||||
Open();
|
||||
CreateColumnFamilies({"one"});
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
@@ -3073,8 +3071,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
|
||||
env.SetBackgroundThreads(2, Env::HIGH);
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2));
|
||||
column_family_options_.memtable_factory.reset(new SpecialSkipListFactory(2));
|
||||
Open();
|
||||
CreateColumnFamilies({"one"});
|
||||
ASSERT_OK(Put(1, "fodor", "mirko"));
|
||||
@@ -3132,8 +3129,7 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
|
||||
env.SetBackgroundThreads(2, Env::HIGH);
|
||||
db_options_.env = &env;
|
||||
db_options_.max_background_flushes = 1;
|
||||
column_family_options_.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(3));
|
||||
column_family_options_.memtable_factory.reset(new SpecialSkipListFactory(3));
|
||||
column_family_options_.level0_file_num_compaction_trigger = 2;
|
||||
Open();
|
||||
CreateColumnFamilies({"one"});
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
struct CompactionIterationStats {
|
||||
|
||||
@@ -932,8 +932,7 @@ Status CompactionJob::Install(const MutableCFOptions& mutable_cf_options) {
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
CompactionServiceJobStatus
|
||||
CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
void CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
SubcompactionState* sub_compact) {
|
||||
assert(sub_compact);
|
||||
assert(sub_compact->compaction);
|
||||
@@ -970,7 +969,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
Status s = compaction_input.Write(&compaction_input_binary);
|
||||
if (!s.ok()) {
|
||||
sub_compact->status = s;
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream input_files_oss;
|
||||
@@ -985,77 +984,39 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
"[%s] [JOB %d] Starting remote compaction (output level: %d): %s",
|
||||
compaction_input.column_family.name.c_str(), job_id_,
|
||||
compaction_input.output_level, input_files_oss.str().c_str());
|
||||
CompactionServiceJobInfo info(dbname_, db_id_, db_session_id_,
|
||||
GetCompactionId(sub_compact), thread_pri_);
|
||||
CompactionServiceJobStatus compaction_status =
|
||||
db_options_.compaction_service->StartV2(info, compaction_input_binary);
|
||||
switch (compaction_status) {
|
||||
case CompactionServiceJobStatus::kSuccess:
|
||||
break;
|
||||
case CompactionServiceJobStatus::kFailure:
|
||||
sub_compact->status = Status::Incomplete(
|
||||
"CompactionService failed to start compaction job.");
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
"[%s] [JOB %d] Remote compaction failed to start.",
|
||||
compaction_input.column_family.name.c_str(), job_id_);
|
||||
return compaction_status;
|
||||
case CompactionServiceJobStatus::kUseLocal:
|
||||
ROCKS_LOG_INFO(
|
||||
db_options_.info_log,
|
||||
"[%s] [JOB %d] Remote compaction fallback to local by API Start.",
|
||||
compaction_input.column_family.name.c_str(), job_id_);
|
||||
return compaction_status;
|
||||
default:
|
||||
assert(false); // unknown status
|
||||
break;
|
||||
db_options_.compaction_service->Start(compaction_input_binary,
|
||||
GetCompactionId(sub_compact));
|
||||
if (compaction_status != CompactionServiceJobStatus::kSuccess) {
|
||||
sub_compact->status =
|
||||
Status::Incomplete("CompactionService failed to start compaction job.");
|
||||
return;
|
||||
}
|
||||
|
||||
ROCKS_LOG_INFO(db_options_.info_log,
|
||||
"[%s] [JOB %d] Waiting for remote compaction...",
|
||||
compaction_input.column_family.name.c_str(), job_id_);
|
||||
std::string compaction_result_binary;
|
||||
compaction_status = db_options_.compaction_service->WaitForCompleteV2(
|
||||
info, &compaction_result_binary);
|
||||
|
||||
if (compaction_status == CompactionServiceJobStatus::kUseLocal) {
|
||||
ROCKS_LOG_INFO(db_options_.info_log,
|
||||
"[%s] [JOB %d] Remote compaction fallback to local by API "
|
||||
"WaitForComplete.",
|
||||
compaction_input.column_family.name.c_str(), job_id_);
|
||||
return compaction_status;
|
||||
}
|
||||
compaction_status = db_options_.compaction_service->WaitForComplete(
|
||||
GetCompactionId(sub_compact), &compaction_result_binary);
|
||||
|
||||
CompactionServiceResult compaction_result;
|
||||
s = CompactionServiceResult::Read(compaction_result_binary,
|
||||
&compaction_result);
|
||||
|
||||
if (compaction_status == CompactionServiceJobStatus::kFailure) {
|
||||
if (s.ok()) {
|
||||
if (compaction_result.status.ok()) {
|
||||
sub_compact->status = Status::Incomplete(
|
||||
"CompactionService failed to run the compaction job (even though "
|
||||
"the internal status is okay).");
|
||||
} else {
|
||||
// set the current sub compaction status with the status returned from
|
||||
// remote
|
||||
sub_compact->status = compaction_result.status;
|
||||
}
|
||||
} else {
|
||||
sub_compact->status = Status::Incomplete(
|
||||
"CompactionService failed to run the compaction job (and no valid "
|
||||
"result is returned).");
|
||||
compaction_result.status.PermitUncheckedError();
|
||||
}
|
||||
if (compaction_status != CompactionServiceJobStatus::kSuccess) {
|
||||
sub_compact->status =
|
||||
s.ok() ? compaction_result.status
|
||||
: Status::Incomplete(
|
||||
"CompactionService failed to run compaction job.");
|
||||
compaction_result.status.PermitUncheckedError();
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
"[%s] [JOB %d] Remote compaction failed.",
|
||||
compaction_input.column_family.name.c_str(), job_id_);
|
||||
return compaction_status;
|
||||
"[%s] [JOB %d] Remote compaction failed, status: %s",
|
||||
compaction_input.column_family.name.c_str(), job_id_,
|
||||
s.ToString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s.ok()) {
|
||||
sub_compact->status = s;
|
||||
compaction_result.status.PermitUncheckedError();
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
return;
|
||||
}
|
||||
sub_compact->status = compaction_result.status;
|
||||
|
||||
@@ -1075,7 +1036,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
|
||||
if (!s.ok()) {
|
||||
sub_compact->status = s;
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& file : compaction_result.output_files) {
|
||||
@@ -1086,7 +1047,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
s = fs_->RenameFile(src_file, tgt_file, IOOptions(), nullptr);
|
||||
if (!s.ok()) {
|
||||
sub_compact->status = s;
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
return;
|
||||
}
|
||||
|
||||
FileMetaData meta;
|
||||
@@ -1094,7 +1055,7 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
s = fs_->GetFileSize(tgt_file, IOOptions(), &file_size, nullptr);
|
||||
if (!s.ok()) {
|
||||
sub_compact->status = s;
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
return;
|
||||
}
|
||||
meta.fd = FileDescriptor(file_num, compaction->output_path_id(), file_size,
|
||||
file.smallest_seqno, file.largest_seqno);
|
||||
@@ -1115,7 +1076,6 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
sub_compact->total_bytes = compaction_result.total_bytes;
|
||||
IOSTATS_ADD(bytes_written, compaction_result.bytes_written);
|
||||
IOSTATS_ADD(bytes_read, compaction_result.bytes_read);
|
||||
return CompactionServiceJobStatus::kSuccess;
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -1125,14 +1085,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (db_options_.compaction_service) {
|
||||
CompactionServiceJobStatus comp_status =
|
||||
ProcessKeyValueCompactionWithCompactionService(sub_compact);
|
||||
if (comp_status == CompactionServiceJobStatus::kSuccess ||
|
||||
comp_status == CompactionServiceJobStatus::kFailure) {
|
||||
return;
|
||||
}
|
||||
// fallback to local compaction
|
||||
assert(comp_status == CompactionServiceJobStatus::kUseLocal);
|
||||
return ProcessKeyValueCompactionWithCompactionService(sub_compact);
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -1256,13 +1209,13 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
|
||||
std::unique_ptr<BlobFileBuilder> blob_file_builder(
|
||||
mutable_cf_options->enable_blob_files
|
||||
? new BlobFileBuilder(
|
||||
versions_, fs_.get(),
|
||||
sub_compact->compaction->immutable_options(),
|
||||
mutable_cf_options, &file_options_, job_id_, cfd->GetID(),
|
||||
cfd->GetName(), Env::IOPriority::IO_LOW, write_hint_,
|
||||
io_tracer_, blob_callback_, BlobFileCreationReason::kCompaction,
|
||||
&blob_file_paths, &sub_compact->blob_file_additions)
|
||||
? new BlobFileBuilder(versions_, fs_.get(),
|
||||
sub_compact->compaction->immutable_options(),
|
||||
mutable_cf_options, &file_options_, job_id_,
|
||||
cfd->GetID(), cfd->GetName(),
|
||||
Env::IOPriority::IO_LOW, write_hint_,
|
||||
io_tracer_, blob_callback_, &blob_file_paths,
|
||||
&sub_compact->blob_file_additions)
|
||||
: nullptr);
|
||||
|
||||
TEST_SYNC_POINT("CompactionJob::Run():Inprogress");
|
||||
@@ -1473,7 +1426,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
if (status.ok()) {
|
||||
status = blob_file_builder->Finish();
|
||||
} else {
|
||||
blob_file_builder->Abandon(status);
|
||||
blob_file_builder->Abandon();
|
||||
}
|
||||
blob_file_builder.reset();
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ class CompactionJob {
|
||||
// consecutive groups such that each group has a similar size.
|
||||
void GenSubcompactionBoundaries();
|
||||
|
||||
CompactionServiceJobStatus ProcessKeyValueCompactionWithCompactionService(
|
||||
void ProcessKeyValueCompactionWithCompactionService(
|
||||
SubcompactionState* sub_compact);
|
||||
|
||||
// update the thread status for starting a compaction.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "env/mock_env.h"
|
||||
#include "file/filename.h"
|
||||
#include "memtable/hash_linklist_rep.h"
|
||||
#include "monitoring/statistics.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
@@ -268,10 +269,10 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
if (cf == 0) {
|
||||
// default cfd
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.num-files-at-level" + ToString(level), &property));
|
||||
"rocksdb.num-files-at-level" + NumberToString(level), &property));
|
||||
} else {
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
handles_[cf], "rocksdb.num-files-at-level" + ToString(level),
|
||||
handles_[cf], "rocksdb.num-files-at-level" + NumberToString(level),
|
||||
&property));
|
||||
}
|
||||
return atoi(property.c_str());
|
||||
|
||||
@@ -1120,9 +1120,7 @@ TEST_F(CompactionJobTest, InputSerialization) {
|
||||
input.snapshots.emplace_back(rnd64.Uniform(UINT64_MAX));
|
||||
}
|
||||
while (!rnd.OneIn(10)) {
|
||||
input.input_files.emplace_back(rnd.RandomString(
|
||||
rnd.Uniform(kStrMaxLen - 1) +
|
||||
1)); // input file name should have at least one character
|
||||
input.input_files.emplace_back(rnd.RandomString(rnd.Uniform(kStrMaxLen)));
|
||||
}
|
||||
input.output_level = 4;
|
||||
input.has_begin = rnd.OneIn(2);
|
||||
|
||||
@@ -385,7 +385,7 @@ uint32_t LevelCompactionBuilder::GetPathId(
|
||||
if (ioptions.level_compaction_dynamic_level_bytes) {
|
||||
// Currently, level_compaction_dynamic_level_bytes is ignored when
|
||||
// multiple db paths are specified. https://github.com/facebook/
|
||||
// rocksdb/blob/main/db/column_family.cc.
|
||||
// rocksdb/blob/master/db/column_family.cc.
|
||||
// Still, adding this check to avoid accidentally using
|
||||
// max_bytes_for_level_multiplier_additional
|
||||
level_size = static_cast<uint64_t>(
|
||||
|
||||
@@ -157,9 +157,9 @@ struct SmallestKeyHeapComparator {
|
||||
const Comparator* ucmp_;
|
||||
};
|
||||
|
||||
using SmallestKeyHeap =
|
||||
std::priority_queue<InputFileInfo, std::vector<InputFileInfo>,
|
||||
SmallestKeyHeapComparator>;
|
||||
typedef std::priority_queue<InputFileInfo, std::vector<InputFileInfo>,
|
||||
SmallestKeyHeapComparator>
|
||||
SmallestKeyHeap;
|
||||
|
||||
// This function creates the heap that is used to find if the files are
|
||||
// overlapping during universal compaction when the allow_trivial_move
|
||||
|
||||
@@ -10,54 +10,13 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class TestCompactionServiceBase {
|
||||
class MyTestCompactionService : public CompactionService {
|
||||
public:
|
||||
virtual int GetCompactionNum() = 0;
|
||||
MyTestCompactionService(const std::string& db_path, Options& options,
|
||||
std::shared_ptr<Statistics> statistics = nullptr)
|
||||
: db_path_(db_path), options_(options), statistics_(statistics) {}
|
||||
|
||||
void OverrideStartStatus(CompactionServiceJobStatus s) {
|
||||
is_override_start_status = true;
|
||||
override_start_status = s;
|
||||
}
|
||||
|
||||
void OverrideWaitStatus(CompactionServiceJobStatus s) {
|
||||
is_override_wait_status = true;
|
||||
override_wait_status = s;
|
||||
}
|
||||
|
||||
void OverrideWaitResult(std::string str) {
|
||||
is_override_wait_result = true;
|
||||
override_wait_result = std::move(str);
|
||||
}
|
||||
|
||||
void ResetOverride() {
|
||||
is_override_wait_result = false;
|
||||
is_override_start_status = false;
|
||||
is_override_wait_status = false;
|
||||
}
|
||||
|
||||
virtual ~TestCompactionServiceBase() = default;
|
||||
|
||||
protected:
|
||||
bool is_override_start_status = false;
|
||||
CompactionServiceJobStatus override_start_status =
|
||||
CompactionServiceJobStatus::kFailure;
|
||||
bool is_override_wait_status = false;
|
||||
CompactionServiceJobStatus override_wait_status =
|
||||
CompactionServiceJobStatus::kFailure;
|
||||
bool is_override_wait_result = false;
|
||||
std::string override_wait_result;
|
||||
};
|
||||
|
||||
class MyTestCompactionServiceLegacy : public CompactionService,
|
||||
public TestCompactionServiceBase {
|
||||
public:
|
||||
MyTestCompactionServiceLegacy(std::string db_path, Options& options,
|
||||
std::shared_ptr<Statistics>& statistics)
|
||||
: db_path_(std::move(db_path)),
|
||||
options_(options),
|
||||
statistics_(statistics) {}
|
||||
|
||||
static const char* kClassName() { return "MyTestCompactionServiceLegacy"; }
|
||||
static const char* kClassName() { return "MyTestCompactionService"; }
|
||||
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
@@ -66,9 +25,7 @@ class MyTestCompactionServiceLegacy : public CompactionService,
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
jobs_.emplace(job_id, compaction_service_input);
|
||||
CompactionServiceJobStatus s = CompactionServiceJobStatus::kSuccess;
|
||||
if (is_override_start_status) {
|
||||
return override_start_status;
|
||||
}
|
||||
TEST_SYNC_POINT_CALLBACK("MyTestCompactionService::Start::End", &s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -85,10 +42,6 @@ class MyTestCompactionServiceLegacy : public CompactionService,
|
||||
jobs_.erase(i);
|
||||
}
|
||||
|
||||
if (is_override_wait_status) {
|
||||
return override_wait_status;
|
||||
}
|
||||
|
||||
CompactionServiceOptionsOverride options_override;
|
||||
options_override.env = options_.env;
|
||||
options_override.file_checksum_gen_factory =
|
||||
@@ -106,9 +59,8 @@ class MyTestCompactionServiceLegacy : public CompactionService,
|
||||
Status s = DB::OpenAndCompact(
|
||||
db_path_, db_path_ + "/" + ROCKSDB_NAMESPACE::ToString(job_id),
|
||||
compaction_input, compaction_service_result, options_override);
|
||||
if (is_override_wait_result) {
|
||||
*compaction_service_result = override_wait_result;
|
||||
}
|
||||
TEST_SYNC_POINT_CALLBACK("MyTestCompactionService::WaitForComplete::End",
|
||||
compaction_service_result);
|
||||
compaction_num_.fetch_add(1);
|
||||
if (s.ok()) {
|
||||
return CompactionServiceJobStatus::kSuccess;
|
||||
@@ -117,7 +69,7 @@ class MyTestCompactionServiceLegacy : public CompactionService,
|
||||
}
|
||||
}
|
||||
|
||||
int GetCompactionNum() override { return compaction_num_.load(); }
|
||||
int GetCompactionNum() { return compaction_num_.load(); }
|
||||
|
||||
private:
|
||||
InstrumentedMutex mutex_;
|
||||
@@ -128,144 +80,12 @@ class MyTestCompactionServiceLegacy : public CompactionService,
|
||||
std::shared_ptr<Statistics> statistics_;
|
||||
};
|
||||
|
||||
class MyTestCompactionService : public CompactionService,
|
||||
public TestCompactionServiceBase {
|
||||
public:
|
||||
MyTestCompactionService(std::string db_path, Options& options,
|
||||
std::shared_ptr<Statistics>& statistics)
|
||||
: db_path_(std::move(db_path)),
|
||||
options_(options),
|
||||
statistics_(statistics),
|
||||
start_info_("na", "na", "na", 0, Env::TOTAL),
|
||||
wait_info_("na", "na", "na", 0, Env::TOTAL) {}
|
||||
|
||||
static const char* kClassName() { return "MyTestCompactionService"; }
|
||||
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
CompactionServiceJobStatus StartV2(
|
||||
const CompactionServiceJobInfo& info,
|
||||
const std::string& compaction_service_input) override {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
start_info_ = info;
|
||||
assert(info.db_name == db_path_);
|
||||
jobs_.emplace(info.job_id, compaction_service_input);
|
||||
CompactionServiceJobStatus s = CompactionServiceJobStatus::kSuccess;
|
||||
if (is_override_start_status) {
|
||||
return override_start_status;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
CompactionServiceJobStatus WaitForCompleteV2(
|
||||
const CompactionServiceJobInfo& info,
|
||||
std::string* compaction_service_result) override {
|
||||
std::string compaction_input;
|
||||
assert(info.db_name == db_path_);
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
wait_info_ = info;
|
||||
auto i = jobs_.find(info.job_id);
|
||||
if (i == jobs_.end()) {
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
}
|
||||
compaction_input = std::move(i->second);
|
||||
jobs_.erase(i);
|
||||
}
|
||||
|
||||
if (is_override_wait_status) {
|
||||
return override_wait_status;
|
||||
}
|
||||
|
||||
CompactionServiceOptionsOverride options_override;
|
||||
options_override.env = options_.env;
|
||||
options_override.file_checksum_gen_factory =
|
||||
options_.file_checksum_gen_factory;
|
||||
options_override.comparator = options_.comparator;
|
||||
options_override.merge_operator = options_.merge_operator;
|
||||
options_override.compaction_filter = options_.compaction_filter;
|
||||
options_override.compaction_filter_factory =
|
||||
options_.compaction_filter_factory;
|
||||
options_override.prefix_extractor = options_.prefix_extractor;
|
||||
options_override.table_factory = options_.table_factory;
|
||||
options_override.sst_partitioner_factory = options_.sst_partitioner_factory;
|
||||
options_override.statistics = statistics_;
|
||||
|
||||
Status s = DB::OpenAndCompact(
|
||||
db_path_, db_path_ + "/" + ROCKSDB_NAMESPACE::ToString(info.job_id),
|
||||
compaction_input, compaction_service_result, options_override);
|
||||
if (is_override_wait_result) {
|
||||
*compaction_service_result = override_wait_result;
|
||||
}
|
||||
compaction_num_.fetch_add(1);
|
||||
if (s.ok()) {
|
||||
return CompactionServiceJobStatus::kSuccess;
|
||||
} else {
|
||||
return CompactionServiceJobStatus::kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
int GetCompactionNum() override { return compaction_num_.load(); }
|
||||
|
||||
CompactionServiceJobInfo GetCompactionInfoForStart() { return start_info_; }
|
||||
CompactionServiceJobInfo GetCompactionInfoForWait() { return wait_info_; }
|
||||
|
||||
private:
|
||||
InstrumentedMutex mutex_;
|
||||
std::atomic_int compaction_num_{0};
|
||||
std::map<uint64_t, std::string> jobs_;
|
||||
const std::string db_path_;
|
||||
Options options_;
|
||||
std::shared_ptr<Statistics> statistics_;
|
||||
CompactionServiceJobInfo start_info_;
|
||||
CompactionServiceJobInfo wait_info_;
|
||||
};
|
||||
|
||||
// This is only for listing test classes
|
||||
enum TestCompactionServiceType {
|
||||
MyTestCompactionServiceType,
|
||||
MyTestCompactionServiceLegacyType,
|
||||
};
|
||||
|
||||
class CompactionServiceTest
|
||||
: public DBTestBase,
|
||||
public testing::WithParamInterface<TestCompactionServiceType> {
|
||||
class CompactionServiceTest : public DBTestBase {
|
||||
public:
|
||||
explicit CompactionServiceTest()
|
||||
: DBTestBase("compaction_service_test", true) {}
|
||||
|
||||
protected:
|
||||
void ReopenWithCompactionService(Options* options) {
|
||||
options->env = env_;
|
||||
primary_statistics_ = CreateDBStatistics();
|
||||
options->statistics = primary_statistics_;
|
||||
compactor_statistics_ = CreateDBStatistics();
|
||||
TestCompactionServiceType cs_type = GetParam();
|
||||
switch (cs_type) {
|
||||
case MyTestCompactionServiceType:
|
||||
compaction_service_ = std::make_shared<MyTestCompactionService>(
|
||||
dbname_, *options, compactor_statistics_);
|
||||
break;
|
||||
case MyTestCompactionServiceLegacyType:
|
||||
compaction_service_ = std::make_shared<MyTestCompactionServiceLegacy>(
|
||||
dbname_, *options, compactor_statistics_);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
options->compaction_service = compaction_service_;
|
||||
DestroyAndReopen(*options);
|
||||
}
|
||||
|
||||
Statistics* GetCompactorStatistics() { return compactor_statistics_.get(); }
|
||||
|
||||
Statistics* GetPrimaryStatistics() { return primary_statistics_.get(); }
|
||||
|
||||
TestCompactionServiceBase* GetCompactionService() {
|
||||
CompactionService* cs = compaction_service_.get();
|
||||
return dynamic_cast<TestCompactionServiceBase*>(cs);
|
||||
}
|
||||
|
||||
void GenerateTestData() {
|
||||
// Generate 20 files @ L2
|
||||
for (int i = 0; i < 20; i++) {
|
||||
@@ -299,16 +119,17 @@ class CompactionServiceTest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Statistics> compactor_statistics_;
|
||||
std::shared_ptr<Statistics> primary_statistics_;
|
||||
std::shared_ptr<CompactionService> compaction_service_;
|
||||
};
|
||||
|
||||
TEST_P(CompactionServiceTest, BasicCompactions) {
|
||||
TEST_F(CompactionServiceTest, BasicCompactions) {
|
||||
Options options = CurrentOptions();
|
||||
ReopenWithCompactionService(&options);
|
||||
options.env = env_;
|
||||
options.statistics = CreateDBStatistics();
|
||||
std::shared_ptr<Statistics> compactor_statistics = CreateDBStatistics();
|
||||
options.compaction_service = std::make_shared<MyTestCompactionService>(
|
||||
dbname_, options, compactor_statistics);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
@@ -336,22 +157,21 @@ TEST_P(CompactionServiceTest, BasicCompactions) {
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
auto my_cs = GetCompactionService();
|
||||
Statistics* compactor_statistics = GetCompactorStatistics();
|
||||
auto my_cs =
|
||||
dynamic_cast<MyTestCompactionService*>(options.compaction_service.get());
|
||||
ASSERT_GE(my_cs->GetCompactionNum(), 1);
|
||||
|
||||
// make sure the compaction statistics is only recorded on the remote side
|
||||
// make sure the compaction statistics is only recorded on remote side
|
||||
ASSERT_GE(
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY), 1);
|
||||
Statistics* primary_statistics = GetPrimaryStatistics();
|
||||
ASSERT_EQ(primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
ASSERT_EQ(options.statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
0);
|
||||
|
||||
// Test failed compaction
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImplSecondary::CompactWithoutInstallation::End", [&](void* status) {
|
||||
// override job status
|
||||
auto s = static_cast<Status*>(status);
|
||||
Status* s = static_cast<Status*>(status);
|
||||
*s = Status::Aborted("MyTestCompactionService failed to compact!");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
@@ -380,13 +200,17 @@ TEST_P(CompactionServiceTest, BasicCompactions) {
|
||||
ASSERT_TRUE(s.IsAborted());
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, ManualCompaction) {
|
||||
TEST_F(CompactionServiceTest, ManualCompaction) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.disable_auto_compactions = true;
|
||||
ReopenWithCompactionService(&options);
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
DestroyAndReopen(options);
|
||||
GenerateTestData();
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
auto my_cs =
|
||||
dynamic_cast<MyTestCompactionService*>(options.compaction_service.get());
|
||||
|
||||
std::string start_str = Key(15);
|
||||
std::string end_str = Key(45);
|
||||
@@ -417,15 +241,22 @@ TEST_P(CompactionServiceTest, ManualCompaction) {
|
||||
VerifyTestData();
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, FailedToStart) {
|
||||
TEST_F(CompactionServiceTest, FailedToStart) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.disable_auto_compactions = true;
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
DestroyAndReopen(options);
|
||||
GenerateTestData();
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
my_cs->OverrideStartStatus(CompactionServiceJobStatus::kFailure);
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"MyTestCompactionService::Start::End", [&](void* status) {
|
||||
// override job status
|
||||
auto s = static_cast<CompactionServiceJobStatus*>(status);
|
||||
*s = CompactionServiceJobStatus::kFailure;
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::string start_str = Key(15);
|
||||
std::string end_str = Key(45);
|
||||
@@ -435,15 +266,22 @@ TEST_P(CompactionServiceTest, FailedToStart) {
|
||||
ASSERT_TRUE(s.IsIncomplete());
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, InvalidResult) {
|
||||
TEST_F(CompactionServiceTest, InvalidResult) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.disable_auto_compactions = true;
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
DestroyAndReopen(options);
|
||||
GenerateTestData();
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
my_cs->OverrideWaitResult("Invalid Str");
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"MyTestCompactionService::WaitForComplete::End", [&](void* result) {
|
||||
// override job status
|
||||
auto result_str = static_cast<std::string*>(result);
|
||||
*result_str = "Invalid Str";
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
std::string start_str = Key(15);
|
||||
std::string end_str = Key(45);
|
||||
@@ -453,17 +291,21 @@ TEST_P(CompactionServiceTest, InvalidResult) {
|
||||
ASSERT_FALSE(s.ok());
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, SubCompaction) {
|
||||
TEST_F(CompactionServiceTest, SubCompaction) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.max_subcompactions = 10;
|
||||
options.target_file_size_base = 1 << 10; // 1KB
|
||||
options.disable_auto_compactions = true;
|
||||
ReopenWithCompactionService(&options);
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
GenerateTestData();
|
||||
VerifyTestData();
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
auto my_cs =
|
||||
dynamic_cast<MyTestCompactionService*>(options.compaction_service.get());
|
||||
int compaction_num_before = my_cs->GetCompactionNum();
|
||||
|
||||
auto cro = CompactRangeOptions();
|
||||
@@ -492,12 +334,16 @@ class PartialDeleteCompactionFilter : public CompactionFilter {
|
||||
const char* Name() const override { return "PartialDeleteCompactionFilter"; }
|
||||
};
|
||||
|
||||
TEST_P(CompactionServiceTest, CompactionFilter) {
|
||||
TEST_F(CompactionServiceTest, CompactionFilter) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
std::unique_ptr<CompactionFilter> delete_comp_filter(
|
||||
new PartialDeleteCompactionFilter());
|
||||
options.compaction_filter = delete_comp_filter.get();
|
||||
ReopenWithCompactionService(&options);
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
@@ -529,13 +375,18 @@ TEST_P(CompactionServiceTest, CompactionFilter) {
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
auto my_cs = GetCompactionService();
|
||||
auto my_cs =
|
||||
dynamic_cast<MyTestCompactionService*>(options.compaction_service.get());
|
||||
ASSERT_GE(my_cs->GetCompactionNum(), 1);
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, Snapshot) {
|
||||
TEST_F(CompactionServiceTest, Snapshot) {
|
||||
Options options = CurrentOptions();
|
||||
ReopenWithCompactionService(&options);
|
||||
options.env = env_;
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put(Key(1), "value1"));
|
||||
ASSERT_OK(Put(Key(2), "value1"));
|
||||
@@ -547,18 +398,23 @@ TEST_P(CompactionServiceTest, Snapshot) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
auto my_cs = GetCompactionService();
|
||||
auto my_cs =
|
||||
dynamic_cast<MyTestCompactionService*>(options.compaction_service.get());
|
||||
ASSERT_GE(my_cs->GetCompactionNum(), 1);
|
||||
ASSERT_EQ("value1", Get(Key(1), s1));
|
||||
ASSERT_EQ("value2", Get(Key(1)));
|
||||
db_->ReleaseSnapshot(s1);
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, ConcurrentCompaction) {
|
||||
TEST_F(CompactionServiceTest, ConcurrentCompaction) {
|
||||
Options options = CurrentOptions();
|
||||
options.level0_file_num_compaction_trigger = 100;
|
||||
options.env = env_;
|
||||
options.compaction_service =
|
||||
std::make_shared<MyTestCompactionService>(dbname_, options);
|
||||
options.max_background_jobs = 20;
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
GenerateTestData();
|
||||
|
||||
ColumnFamilyMetaData meta;
|
||||
@@ -586,209 +442,12 @@ TEST_P(CompactionServiceTest, ConcurrentCompaction) {
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
auto my_cs = GetCompactionService();
|
||||
auto my_cs =
|
||||
dynamic_cast<MyTestCompactionService*>(options.compaction_service.get());
|
||||
ASSERT_EQ(my_cs->GetCompactionNum(), 10);
|
||||
ASSERT_EQ(FilesPerLevel(), "0,0,10");
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, CompactionInfo) {
|
||||
// only test compaction info for new compaction service interface
|
||||
if (GetParam() != MyTestCompactionServiceType) {
|
||||
return;
|
||||
}
|
||||
|
||||
Options options = CurrentOptions();
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 10 + j;
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 20 + j * 2;
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
auto my_cs =
|
||||
static_cast_with_check<MyTestCompactionService>(GetCompactionService());
|
||||
uint64_t comp_num = my_cs->GetCompactionNum();
|
||||
ASSERT_GE(comp_num, 1);
|
||||
|
||||
CompactionServiceJobInfo info = my_cs->GetCompactionInfoForStart();
|
||||
ASSERT_EQ(dbname_, info.db_name);
|
||||
std::string db_id, db_session_id;
|
||||
ASSERT_OK(db_->GetDbIdentity(db_id));
|
||||
ASSERT_EQ(db_id, info.db_id);
|
||||
ASSERT_OK(db_->GetDbSessionId(db_session_id));
|
||||
ASSERT_EQ(db_session_id, info.db_session_id);
|
||||
ASSERT_EQ(Env::LOW, info.priority);
|
||||
info = my_cs->GetCompactionInfoForWait();
|
||||
ASSERT_EQ(dbname_, info.db_name);
|
||||
ASSERT_EQ(db_id, info.db_id);
|
||||
ASSERT_EQ(db_session_id, info.db_session_id);
|
||||
ASSERT_EQ(Env::LOW, info.priority);
|
||||
|
||||
// Test priority USER
|
||||
ColumnFamilyMetaData meta;
|
||||
db_->GetColumnFamilyMetaData(&meta);
|
||||
SstFileMetaData file = meta.levels[1].files[0];
|
||||
ASSERT_OK(db_->CompactFiles(CompactionOptions(),
|
||||
{file.db_path + "/" + file.name}, 2));
|
||||
info = my_cs->GetCompactionInfoForStart();
|
||||
ASSERT_EQ(Env::USER, info.priority);
|
||||
info = my_cs->GetCompactionInfoForWait();
|
||||
ASSERT_EQ(Env::USER, info.priority);
|
||||
|
||||
// Test priority BOTTOM
|
||||
env_->SetBackgroundThreads(1, Env::BOTTOM);
|
||||
options.num_levels = 2;
|
||||
ReopenWithCompactionService(&options);
|
||||
my_cs =
|
||||
static_cast_with_check<MyTestCompactionService>(GetCompactionService());
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 10 + j;
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 20 + j * 2;
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
info = my_cs->GetCompactionInfoForStart();
|
||||
ASSERT_EQ(Env::BOTTOM, info.priority);
|
||||
info = my_cs->GetCompactionInfoForWait();
|
||||
ASSERT_EQ(Env::BOTTOM, info.priority);
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, FallbackLocalAuto) {
|
||||
Options options = CurrentOptions();
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
Statistics* compactor_statistics = GetCompactorStatistics();
|
||||
Statistics* primary_statistics = GetPrimaryStatistics();
|
||||
uint64_t compactor_new_key =
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY);
|
||||
uint64_t primary_new_key =
|
||||
primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY);
|
||||
|
||||
my_cs->OverrideStartStatus(CompactionServiceJobStatus::kUseLocal);
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 10 + j;
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 20 + j * 2;
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
// verify result
|
||||
for (int i = 0; i < 200; i++) {
|
||||
auto result = Get(Key(i));
|
||||
if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQ(my_cs->GetCompactionNum(), 0);
|
||||
|
||||
// make sure the compaction statistics is only recorded on the local side
|
||||
ASSERT_EQ(
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
compactor_new_key);
|
||||
ASSERT_GT(primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
primary_new_key);
|
||||
}
|
||||
|
||||
TEST_P(CompactionServiceTest, FallbackLocalManual) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
GenerateTestData();
|
||||
VerifyTestData();
|
||||
|
||||
auto my_cs = GetCompactionService();
|
||||
Statistics* compactor_statistics = GetCompactorStatistics();
|
||||
Statistics* primary_statistics = GetPrimaryStatistics();
|
||||
uint64_t compactor_new_key =
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY);
|
||||
uint64_t primary_new_key =
|
||||
primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY);
|
||||
|
||||
// re-enable remote compaction
|
||||
my_cs->ResetOverride();
|
||||
std::string start_str = Key(15);
|
||||
std::string end_str = Key(45);
|
||||
Slice start(start_str);
|
||||
Slice end(end_str);
|
||||
uint64_t comp_num = my_cs->GetCompactionNum();
|
||||
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), &start, &end));
|
||||
ASSERT_GE(my_cs->GetCompactionNum(), comp_num + 1);
|
||||
// make sure the compaction statistics is only recorded on the remote side
|
||||
ASSERT_GT(
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
compactor_new_key);
|
||||
ASSERT_EQ(primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
primary_new_key);
|
||||
|
||||
// return run local again with API WaitForComplete
|
||||
my_cs->OverrideWaitStatus(CompactionServiceJobStatus::kUseLocal);
|
||||
start_str = Key(120);
|
||||
start = start_str;
|
||||
comp_num = my_cs->GetCompactionNum();
|
||||
compactor_new_key =
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY);
|
||||
primary_new_key =
|
||||
primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY);
|
||||
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), &start, nullptr));
|
||||
ASSERT_EQ(my_cs->GetCompactionNum(),
|
||||
comp_num); // no remote compaction is run
|
||||
// make sure the compaction statistics is only recorded on the local side
|
||||
ASSERT_EQ(
|
||||
compactor_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
compactor_new_key);
|
||||
ASSERT_GT(primary_statistics->getTickerCount(COMPACTION_KEY_DROP_NEWER_ENTRY),
|
||||
primary_new_key);
|
||||
|
||||
// verify result after 2 manual compactions
|
||||
VerifyTestData();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
CompactionServiceTest, CompactionServiceTest,
|
||||
::testing::Values(
|
||||
TestCompactionServiceType::MyTestCompactionServiceType,
|
||||
TestCompactionServiceType::MyTestCompactionServiceLegacyType));
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
@@ -94,8 +94,8 @@ class CuckooTableDBTest : public testing::Test {
|
||||
|
||||
int NumTableFilesAtLevel(int level) {
|
||||
std::string property;
|
||||
EXPECT_TRUE(db_->GetProperty("rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(level), &property));
|
||||
return atoi(property.c_str());
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -8,6 +8,7 @@
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include <cstring>
|
||||
#include <regex>
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
@@ -68,10 +69,11 @@ TEST_F(DBBasicTest, UniqueSession) {
|
||||
ASSERT_EQ(sid2, sid4);
|
||||
|
||||
// Expected compact format for session ids (see notes in implementation)
|
||||
TestRegex expected("[0-9A-Z]{20}");
|
||||
EXPECT_MATCHES_REGEX(sid1, expected);
|
||||
EXPECT_MATCHES_REGEX(sid2, expected);
|
||||
EXPECT_MATCHES_REGEX(sid3, expected);
|
||||
std::regex expected("[0-9A-Z]{20}");
|
||||
const std::string match("match");
|
||||
EXPECT_EQ(match, std::regex_replace(sid1, expected, match));
|
||||
EXPECT_EQ(match, std::regex_replace(sid2, expected, match));
|
||||
EXPECT_EQ(match, std::regex_replace(sid3, expected, match));
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
Close();
|
||||
@@ -3235,11 +3237,13 @@ INSTANTIATE_TEST_CASE_P(ParallelIO, DBBasicTestWithParallelIO,
|
||||
// Forward declaration
|
||||
class DeadlineFS;
|
||||
|
||||
class DeadlineRandomAccessFile : public FSRandomAccessFileOwnerWrapper {
|
||||
class DeadlineRandomAccessFile : public FSRandomAccessFileWrapper {
|
||||
public:
|
||||
DeadlineRandomAccessFile(DeadlineFS& fs,
|
||||
std::unique_ptr<FSRandomAccessFile>& file)
|
||||
: FSRandomAccessFileOwnerWrapper(std::move(file)), fs_(fs) {}
|
||||
: FSRandomAccessFileWrapper(file.get()),
|
||||
fs_(fs),
|
||||
file_(std::move(file)) {}
|
||||
|
||||
IOStatus Read(uint64_t offset, size_t len, const IOOptions& opts,
|
||||
Slice* result, char* scratch,
|
||||
|
||||
@@ -505,11 +505,6 @@ TEST_F(DBBlockCacheTest, WarmCacheWithDataBlocksDuringFlush) {
|
||||
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_DATA_MISS));
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_DATA_HIT));
|
||||
}
|
||||
// Verify compaction not counted
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), /*begin=*/nullptr,
|
||||
/*end=*/nullptr));
|
||||
EXPECT_EQ(kNumBlocks,
|
||||
options.statistics->getTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
}
|
||||
|
||||
// This test cache data, index and filter blocks during flush.
|
||||
@@ -547,18 +542,6 @@ TEST_F(DBBlockCacheTest, WarmCacheWithBlocksDuringFlush) {
|
||||
ASSERT_EQ(i * 2,
|
||||
options.statistics->getTickerCount(BLOCK_CACHE_FILTER_HIT));
|
||||
}
|
||||
// Verify compaction not counted
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), /*begin=*/nullptr,
|
||||
/*end=*/nullptr));
|
||||
EXPECT_EQ(kNumBlocks,
|
||||
options.statistics->getTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
// Index and filter blocks are automatically warmed when the new table file
|
||||
// is automatically opened at the end of compaction. This is not easily
|
||||
// disabled so results in the new index and filter blocks being warmed.
|
||||
EXPECT_EQ(1 + kNumBlocks,
|
||||
options.statistics->getTickerCount(BLOCK_CACHE_INDEX_ADD));
|
||||
EXPECT_EQ(1 + kNumBlocks,
|
||||
options.statistics->getTickerCount(BLOCK_CACHE_FILTER_ADD));
|
||||
}
|
||||
|
||||
TEST_F(DBBlockCacheTest, DynamicallyWarmCacheDuringFlush) {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "table/block_based/filter_policy_internal.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -2172,8 +2171,7 @@ TEST_F(DBBloomFilterTest, SeekForPrevWithPartitionedFilters) {
|
||||
Options options = CurrentOptions();
|
||||
constexpr size_t kNumKeys = 10000;
|
||||
static_assert(kNumKeys <= 10000, "kNumKeys have to be <= 10000");
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeys + 10));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeys + 10));
|
||||
options.create_if_missing = true;
|
||||
constexpr size_t kPrefixLength = 4;
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(kPrefixLength));
|
||||
|
||||
+10
-58
@@ -19,7 +19,6 @@
|
||||
#include "rocksdb/sst_file_writer.h"
|
||||
#include "rocksdb/utilities/convenience.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/concurrent_task_limiter_impl.h"
|
||||
#include "util/random.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
@@ -806,8 +805,7 @@ TEST_P(DBCompactionTestWithParam, CompactionTrigger) {
|
||||
options.num_levels = 3;
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
options.max_subcompactions = max_subcompactions_;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
Random rnd(301);
|
||||
@@ -854,8 +852,7 @@ TEST_F(DBCompactionTest, BGCompactionsAllowed) {
|
||||
options.level0_slowdown_writes_trigger = 20;
|
||||
options.soft_pending_compaction_bytes_limit = 1 << 30; // Infinitely large
|
||||
options.max_background_compactions = 3;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
|
||||
// Block all threads in thread pool.
|
||||
const size_t kTotalTasks = 4;
|
||||
@@ -2097,7 +2094,7 @@ TEST_P(DBCompactionTestWithParam, LevelCompactionThirdPath) {
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 4 * 1024 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -2206,7 +2203,7 @@ TEST_P(DBCompactionTestWithParam, LevelCompactionPathUse) {
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 4 * 1024 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -2316,7 +2313,7 @@ TEST_P(DBCompactionTestWithParam, LevelCompactionCFPathUse) {
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 4 * 1024 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -3015,7 +3012,7 @@ TEST_P(DBCompactionTestWithParam, CompressLevelCompaction) {
|
||||
}
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -4818,8 +4815,7 @@ TEST_F(DBCompactionTest, CompactionLimiter) {
|
||||
options.level0_slowdown_writes_trigger = 64;
|
||||
options.level0_stop_writes_trigger = 64;
|
||||
options.max_background_jobs = kMaxBackgroundThreads; // Enough threads
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.max_write_buffer_number = 10; // Enough memtables
|
||||
DestroyAndReopen(options);
|
||||
|
||||
@@ -5342,8 +5338,7 @@ TEST_P(DBCompactionTestWithParam, FixFileIngestionCompactionDeadlock) {
|
||||
options.level0_file_num_compaction_trigger =
|
||||
options.level0_stop_writes_trigger;
|
||||
options.max_subcompactions = max_subcompactions_;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
Random rnd(301);
|
||||
|
||||
@@ -5869,7 +5864,7 @@ TEST_F(DBCompactionTest, ChangeLevelCompactRangeConflictsWithManual) {
|
||||
// `Status::Incomplete`.
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.num_levels = 3;
|
||||
Reopen(options);
|
||||
@@ -5957,7 +5952,7 @@ TEST_F(DBCompactionTest, ChangeLevelErrorPathTest) {
|
||||
// succeeds
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.num_levels = 3;
|
||||
Reopen(options);
|
||||
@@ -6817,49 +6812,6 @@ TEST_F(DBCompactionTest, FIFOWarm) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest,
|
||||
DisableManualCompactionDoesNotWaitForDrainingAutomaticCompaction) {
|
||||
// When `CompactRangeOptions::exclusive_manual_compaction == true`, we wait
|
||||
// for automatic compactions to drain before starting the manual compaction.
|
||||
// This test verifies `DisableManualCompaction()` can cancel such a compaction
|
||||
// without waiting for the drain to complete.
|
||||
const int kNumL0Files = 4;
|
||||
|
||||
// Enforces manual compaction enters wait loop due to pending automatic
|
||||
// compaction.
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::BGWorkCompaction", "DBImpl::RunManualCompaction:NotScheduled"},
|
||||
{"DBImpl::RunManualCompaction:WaitScheduled",
|
||||
"BackgroundCallCompaction:0"}});
|
||||
// The automatic compaction will cancel the waiting manual compaction.
|
||||
// Completing this implies the cancellation did not wait on automatic
|
||||
// compactions to finish.
|
||||
bool callback_completed = false;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"BackgroundCallCompaction:0", [&](void* /*arg*/) {
|
||||
db_->DisableManualCompaction();
|
||||
callback_completed = true;
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.level0_file_num_compaction_trigger = kNumL0Files;
|
||||
Reopen(options);
|
||||
|
||||
for (int i = 0; i < kNumL0Files; ++i) {
|
||||
ASSERT_OK(Put(Key(1), "value1"));
|
||||
ASSERT_OK(Put(Key(2), "value2"));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
CompactRangeOptions cro;
|
||||
cro.exclusive_manual_compaction = true;
|
||||
ASSERT_TRUE(db_->CompactRange(cro, nullptr, nullptr).IsIncomplete());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(callback_completed);
|
||||
}
|
||||
|
||||
#endif // !defined(ROCKSDB_LITE)
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
+2
-3
@@ -18,7 +18,6 @@
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/cast_util.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
@@ -140,7 +139,7 @@ TEST_F(DBFlushTest, FlushInLowPriThreadPool) {
|
||||
// scheduled in the low-pri (compaction) thread pool.
|
||||
Options options = CurrentOptions();
|
||||
options.level0_file_num_compaction_trigger = 4;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(1));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
Reopen(options);
|
||||
env_->SetBackgroundThreads(0, Env::HIGH);
|
||||
|
||||
@@ -2321,7 +2320,7 @@ TEST_P(DBAtomicFlushTest, TriggerFlushAndClose) {
|
||||
options.create_if_missing = true;
|
||||
options.atomic_flush = atomic_flush;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysTriggerFlush));
|
||||
new SpecialSkipListFactory(kNumKeysTriggerFlush));
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
for (int i = 0; i != kNumKeysTriggerFlush; ++i) {
|
||||
|
||||
+42
-44
@@ -53,7 +53,6 @@
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "db/write_callback.h"
|
||||
#include "env/unique_id.h"
|
||||
#include "file/file_util.h"
|
||||
#include "file/filename.h"
|
||||
#include "file/random_access_file_reader.h"
|
||||
@@ -61,6 +60,8 @@
|
||||
#include "logging/auto_roll_logger.h"
|
||||
#include "logging/log_buffer.h"
|
||||
#include "logging/logging.h"
|
||||
#include "memtable/hash_linklist_rep.h"
|
||||
#include "memtable/hash_skiplist_rep.h"
|
||||
#include "monitoring/in_memory_stats_history.h"
|
||||
#include "monitoring/instrumented_mutex.h"
|
||||
#include "monitoring/iostats_context_imp.h"
|
||||
@@ -237,8 +238,7 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname,
|
||||
closed_(false),
|
||||
atomic_flush_install_cv_(&mutex_),
|
||||
blob_callback_(immutable_db_options_.sst_file_manager.get(), &mutex_,
|
||||
&error_handler_, &event_logger_,
|
||||
immutable_db_options_.listeners, dbname_) {
|
||||
&error_handler_) {
|
||||
// !batch_per_trx_ implies seq_per_batch_ because it is only unset for
|
||||
// WriteUnprepared, which should use seq_per_batch_.
|
||||
assert(batch_per_txn_ || seq_per_batch_);
|
||||
@@ -958,13 +958,8 @@ void DBImpl::DumpStats() {
|
||||
// Release DB mutex for gathering cache entry stats. Pass over all
|
||||
// column families for this first so that other stats are dumped
|
||||
// near-atomically.
|
||||
// Get a ref before unlocking
|
||||
cfd->Ref();
|
||||
{
|
||||
InstrumentedMutexUnlock u(&mutex_);
|
||||
cfd->internal_stats()->CollectCacheEntryStats(/*foreground=*/false);
|
||||
}
|
||||
cfd->UnrefAndTryDelete();
|
||||
InstrumentedMutexUnlock u(&mutex_);
|
||||
cfd->internal_stats()->CollectCacheEntryStats(/*foreground=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2162,7 +2157,7 @@ bool DBImpl::MultiCFSnapshot(
|
||||
// consecutive retries, it means the write rate is very high. In that case
|
||||
// its probably ok to take the mutex on the 3rd try so we can succeed for
|
||||
// sure
|
||||
constexpr int num_retries = 3;
|
||||
static const int num_retries = 3;
|
||||
for (int i = 0; i < num_retries; ++i) {
|
||||
last_try = (i == num_retries - 1);
|
||||
bool retry = false;
|
||||
@@ -2192,9 +2187,8 @@ bool DBImpl::MultiCFSnapshot(
|
||||
*snapshot = versions_->LastPublishedSequence();
|
||||
}
|
||||
} else {
|
||||
*snapshot =
|
||||
static_cast_with_check<const SnapshotImpl>(read_options.snapshot)
|
||||
->number_;
|
||||
*snapshot = reinterpret_cast<const SnapshotImpl*>(read_options.snapshot)
|
||||
->number_;
|
||||
}
|
||||
for (auto cf_iter = cf_list->begin(); cf_iter != cf_list->end();
|
||||
++cf_iter) {
|
||||
@@ -2395,9 +2389,17 @@ void DBImpl::PrepareMultiGetKeys(
|
||||
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* sorted_keys) {
|
||||
if (sorted_input) {
|
||||
#ifndef NDEBUG
|
||||
assert(std::is_sorted(sorted_keys->begin(), sorted_keys->end(),
|
||||
CompareKeyContext()));
|
||||
CompareKeyContext key_context_less;
|
||||
|
||||
for (size_t index = 1; index < sorted_keys->size(); ++index) {
|
||||
const KeyContext* const lhs = (*sorted_keys)[index - 1];
|
||||
const KeyContext* const rhs = (*sorted_keys)[index];
|
||||
|
||||
// lhs should be <= rhs, or in other words, rhs should NOT be < lhs
|
||||
assert(!key_context_less(rhs, lhs));
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3108,7 +3110,7 @@ SnapshotImpl* DBImpl::GetSnapshotImpl(bool is_write_conflict_boundary,
|
||||
}
|
||||
|
||||
namespace {
|
||||
using CfdList = autovector<ColumnFamilyData*, 2>;
|
||||
typedef autovector<ColumnFamilyData*, 2> CfdList;
|
||||
bool CfdListContains(const CfdList& list, ColumnFamilyData* cfd) {
|
||||
for (const ColumnFamilyData* t : list) {
|
||||
if (t == cfd) {
|
||||
@@ -3931,8 +3933,7 @@ Status DBImpl::GetDbIdentityFromIdentityFile(std::string* identity) const {
|
||||
return s;
|
||||
}
|
||||
|
||||
// If last character is '\n' remove it from identity. (Old implementations
|
||||
// of Env::GenerateUniqueId() would include a trailing '\n'.)
|
||||
// If last character is '\n' remove it from identity
|
||||
if (identity->size() > 0 && identity->back() == '\n') {
|
||||
identity->pop_back();
|
||||
}
|
||||
@@ -3944,11 +3945,10 @@ Status DBImpl::GetDbSessionId(std::string& session_id) const {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::string DBImpl::GenerateDbSessionId(Env*) {
|
||||
// GenerateRawUniqueId() generates an identifier that has a negligible
|
||||
// probability of being duplicated. It should have full 128 bits of entropy.
|
||||
uint64_t a, b;
|
||||
GenerateRawUniqueId(&a, &b);
|
||||
std::string DBImpl::GenerateDbSessionId(Env* env) {
|
||||
// GenerateUniqueId() generates an identifier that has a negligible
|
||||
// probability of being duplicated, ~128 bits of entropy
|
||||
std::string uuid = env->GenerateUniqueId();
|
||||
|
||||
// Hash and reformat that down to a more compact format, 20 characters
|
||||
// in base-36 ([0-9A-Z]), which is ~103 bits of entropy, which is enough
|
||||
@@ -3957,10 +3957,18 @@ std::string DBImpl::GenerateDbSessionId(Env*) {
|
||||
// * Save ~ dozen bytes per SST file
|
||||
// * Shorter shared backup file names (some platforms have low limits)
|
||||
// * Visually distinct from DB id format
|
||||
std::string db_session_id(20U, '\0');
|
||||
char* buf = &db_session_id[0];
|
||||
PutBaseChars<36>(&buf, 10, a, /*uppercase*/ true);
|
||||
PutBaseChars<36>(&buf, 10, b, /*uppercase*/ true);
|
||||
uint64_t a = NPHash64(uuid.data(), uuid.size(), 1234U);
|
||||
uint64_t b = NPHash64(uuid.data(), uuid.size(), 5678U);
|
||||
std::string db_session_id;
|
||||
db_session_id.resize(20);
|
||||
static const char* const base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
size_t i = 0;
|
||||
for (; i < 10U; ++i, a /= 36U) {
|
||||
db_session_id[i] = base36[a % 36];
|
||||
}
|
||||
for (; i < 20U; ++i, b /= 36U) {
|
||||
db_session_id[i] = base36[b % 36];
|
||||
}
|
||||
return db_session_id;
|
||||
}
|
||||
|
||||
@@ -4679,11 +4687,14 @@ Status DBImpl::IngestExternalFiles(
|
||||
if (status.ok()) {
|
||||
int consumed_seqno_count =
|
||||
ingestion_jobs[0].ConsumedSequenceNumbersCount();
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 1; i != num_cfs; ++i) {
|
||||
consumed_seqno_count =
|
||||
std::max(consumed_seqno_count,
|
||||
ingestion_jobs[i].ConsumedSequenceNumbersCount());
|
||||
assert(!!consumed_seqno_count ==
|
||||
!!ingestion_jobs[i].ConsumedSequenceNumbersCount());
|
||||
consumed_seqno_count +=
|
||||
ingestion_jobs[i].ConsumedSequenceNumbersCount();
|
||||
}
|
||||
#endif
|
||||
if (consumed_seqno_count > 0) {
|
||||
const SequenceNumber last_seqno = versions_->LastSequence();
|
||||
versions_->SetLastAllocatedSequence(last_seqno + consumed_seqno_count);
|
||||
@@ -4925,11 +4936,6 @@ Status DBImpl::VerifyChecksum(const ReadOptions& read_options) {
|
||||
|
||||
Status DBImpl::VerifyChecksumInternal(const ReadOptions& read_options,
|
||||
bool use_file_checksum) {
|
||||
// `bytes_read` stat is enabled based on compile-time support and cannot
|
||||
// be dynamically toggled. So we do not need to worry about `PerfLevel`
|
||||
// here, unlike many other `IOStatsContext` / `PerfContext` stats.
|
||||
uint64_t prev_bytes_read = IOSTATS(bytes_read);
|
||||
|
||||
Status s;
|
||||
|
||||
if (use_file_checksum) {
|
||||
@@ -4984,9 +4990,6 @@ Status DBImpl::VerifyChecksumInternal(const ReadOptions& read_options,
|
||||
s = ROCKSDB_NAMESPACE::VerifySstFileChecksum(opts, file_options_,
|
||||
read_options, fname);
|
||||
}
|
||||
RecordTick(stats_, VERIFY_CHECKSUM_READ_BYTES,
|
||||
IOSTATS(bytes_read) - prev_bytes_read);
|
||||
prev_bytes_read = IOSTATS(bytes_read);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5001,9 +5004,6 @@ Status DBImpl::VerifyChecksumInternal(const ReadOptions& read_options,
|
||||
s = VerifyFullFileChecksum(meta->GetChecksumValue(),
|
||||
meta->GetChecksumMethod(), blob_file_name,
|
||||
read_options);
|
||||
RecordTick(stats_, VERIFY_CHECKSUM_READ_BYTES,
|
||||
IOSTATS(bytes_read) - prev_bytes_read);
|
||||
prev_bytes_read = IOSTATS(bytes_read);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
@@ -5035,8 +5035,6 @@ Status DBImpl::VerifyChecksumInternal(const ReadOptions& read_options,
|
||||
cfd->UnrefAndTryDelete();
|
||||
}
|
||||
}
|
||||
RecordTick(stats_, VERIFY_CHECKSUM_READ_BYTES,
|
||||
IOSTATS(bytes_read) - prev_bytes_read);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -1099,10 +1099,8 @@ class DBImpl : public DB {
|
||||
// Called from WriteBufferManager. This function changes the state_
|
||||
// to State::RUNNING indicating the stall is cleared and DB can proceed.
|
||||
void Signal() override {
|
||||
{
|
||||
MutexLock lock(&state_mutex_);
|
||||
state_ = State::RUNNING;
|
||||
}
|
||||
MutexLock lock(&state_mutex_);
|
||||
state_ = State::RUNNING;
|
||||
state_cv_.Signal();
|
||||
}
|
||||
|
||||
@@ -1755,7 +1753,7 @@ class DBImpl : public DB {
|
||||
// specified value, this flush request is considered to have completed its
|
||||
// work of flushing this column family. After completing the work for all
|
||||
// column families in this request, this flush is considered complete.
|
||||
using FlushRequest = std::vector<std::pair<ColumnFamilyData*, uint64_t>>;
|
||||
typedef std::vector<std::pair<ColumnFamilyData*, uint64_t>> FlushRequest;
|
||||
|
||||
void GenerateFlushRequest(const autovector<ColumnFamilyData*>& cfds,
|
||||
FlushRequest* req);
|
||||
@@ -2017,7 +2015,7 @@ class DBImpl : public DB {
|
||||
// accessed from the same write_thread_ without any locks. With
|
||||
// two_write_queues writes, where it can be updated in different threads,
|
||||
// read and writes are protected by log_write_mutex_ instead. This is to avoid
|
||||
// expensive mutex_ lock during WAL write, which update log_empty_.
|
||||
// expesnive mutex_ lock during WAL write, which update log_empty_.
|
||||
bool log_empty_;
|
||||
|
||||
ColumnFamilyHandleImpl* persist_stats_cf_handle_;
|
||||
|
||||
@@ -1353,15 +1353,10 @@ Status DBImpl::CompactFilesImpl(
|
||||
|
||||
if (output_file_names != nullptr) {
|
||||
for (const auto& newf : c->edit()->GetNewFiles()) {
|
||||
output_file_names->push_back(TableFileName(
|
||||
c->immutable_options()->cf_paths, newf.second.fd.GetNumber(),
|
||||
newf.second.fd.GetPathId()));
|
||||
}
|
||||
|
||||
for (const auto& blob_file : c->edit()->GetBlobFileAdditions()) {
|
||||
output_file_names->push_back(
|
||||
BlobFileName(c->immutable_options()->cf_paths.front().path,
|
||||
blob_file.GetBlobFileNumber()));
|
||||
(*output_file_names)
|
||||
.push_back(TableFileName(c->immutable_options()->cf_paths,
|
||||
newf.second.fd.GetNumber(),
|
||||
newf.second.fd.GetPathId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1714,11 +1709,8 @@ Status DBImpl::RunManualCompaction(
|
||||
|
||||
// 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
|
||||
// compaction can compact any range of keys/files. Now it is optional
|
||||
// (see `CompactRangeOptions::exclusive_manual_compaction`). The use case for
|
||||
// `exclusive_manual_compaction=true` (the default) is unclear beyond not
|
||||
// trusting the new code.
|
||||
// jobs drops to zero. This is needed to ensure that this manual compaction
|
||||
// can compact any range of keys/files.
|
||||
//
|
||||
// HasPendingManualCompaction() is true when at least one thread is inside
|
||||
// RunManualCompaction(), i.e. during that time no other compaction will
|
||||
@@ -1732,20 +1724,8 @@ Status DBImpl::RunManualCompaction(
|
||||
AddManualCompaction(&manual);
|
||||
TEST_SYNC_POINT_CALLBACK("DBImpl::RunManualCompaction:NotScheduled", &mutex_);
|
||||
if (exclusive) {
|
||||
// Limitation: there's no way to wake up the below loop when user sets
|
||||
// `*manual.canceled`. So `CompactRangeOptions::exclusive_manual_compaction`
|
||||
// and `CompactRangeOptions::canceled` might not work well together.
|
||||
while (bg_bottom_compaction_scheduled_ > 0 ||
|
||||
bg_compaction_scheduled_ > 0) {
|
||||
if (manual_compaction_paused_ > 0 ||
|
||||
(manual.canceled != nullptr && *manual.canceled == true)) {
|
||||
// Pretend the error came from compaction so the below cleanup/error
|
||||
// handling code can process it.
|
||||
manual.done = true;
|
||||
manual.status =
|
||||
Status::Incomplete(Status::SubCode::kManualCompactionPaused);
|
||||
break;
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::RunManualCompaction:WaitScheduled");
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
@@ -2238,10 +2218,6 @@ Status DBImpl::EnableAutoCompaction(
|
||||
void DBImpl::DisableManualCompaction() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
manual_compaction_paused_.fetch_add(1, std::memory_order_release);
|
||||
|
||||
// Wake up manual compactions waiting to start.
|
||||
bg_cv_.SignalAll();
|
||||
|
||||
// Wait for any pending manual compactions to finish (typically through
|
||||
// failing with `Status::Incomplete`) prior to returning. This way we are
|
||||
// guaranteed no pending manual compaction will commit while manual
|
||||
@@ -3485,30 +3461,6 @@ void DBImpl::BuildCompactionJobInfo(
|
||||
compaction_job_info->output_file_infos.push_back(CompactionFileInfo{
|
||||
newf.first, file_number, meta.oldest_blob_file_number});
|
||||
}
|
||||
compaction_job_info->blob_compression_type =
|
||||
c->mutable_cf_options()->blob_compression_type;
|
||||
|
||||
// Update BlobFilesInfo.
|
||||
for (const auto& blob_file : c->edit()->GetBlobFileAdditions()) {
|
||||
BlobFileAdditionInfo blob_file_addition_info(
|
||||
BlobFileName(c->immutable_options()->cf_paths.front().path,
|
||||
blob_file.GetBlobFileNumber()) /*blob_file_path*/,
|
||||
blob_file.GetBlobFileNumber(), blob_file.GetTotalBlobCount(),
|
||||
blob_file.GetTotalBlobBytes());
|
||||
compaction_job_info->blob_file_addition_infos.emplace_back(
|
||||
std::move(blob_file_addition_info));
|
||||
}
|
||||
|
||||
// Update BlobFilesGarbageInfo.
|
||||
for (const auto& blob_file : c->edit()->GetBlobFileGarbages()) {
|
||||
BlobFileGarbageInfo blob_file_garbage_info(
|
||||
BlobFileName(c->immutable_options()->cf_paths.front().path,
|
||||
blob_file.GetBlobFileNumber()) /*blob_file_path*/,
|
||||
blob_file.GetBlobFileNumber(), blob_file.GetGarbageBlobCount(),
|
||||
blob_file.GetGarbageBlobBytes());
|
||||
compaction_job_info->blob_file_garbage_infos.emplace_back(
|
||||
std::move(blob_file_garbage_info));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ bool CompareCandidateFile(const JobContext::CandidateFileInfo& first,
|
||||
return (first.file_path > second.file_path);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
}; // namespace
|
||||
|
||||
// Delete obsolete files and log status and information of file deletion
|
||||
void DBImpl::DeleteObsoleteFileImpl(int job_id, const std::string& fname,
|
||||
@@ -360,11 +360,6 @@ void DBImpl::DeleteObsoleteFileImpl(int job_id, const std::string& fname,
|
||||
&event_logger_, job_id, number, fname, file_deletion_status, GetName(),
|
||||
immutable_db_options_.listeners);
|
||||
}
|
||||
if (type == kBlobFile) {
|
||||
EventHelpers::LogAndNotifyBlobFileDeletion(
|
||||
&event_logger_, immutable_db_options_.listeners, job_id, number, fname,
|
||||
file_deletion_status, GetName());
|
||||
}
|
||||
}
|
||||
|
||||
// Diffs the files listed in filenames and those that do not
|
||||
|
||||
@@ -1424,9 +1424,8 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
|
||||
std::move(range_del_iters), &meta, &blob_file_additions,
|
||||
snapshot_seqs, earliest_write_conflict_snapshot, snapshot_checker,
|
||||
paranoid_file_checks, cfd->internal_stats(), &io_s, io_tracer_,
|
||||
BlobFileCreationReason::kRecovery, &event_logger_, job_id,
|
||||
Env::IO_HIGH, nullptr /* table_properties */, write_hint,
|
||||
nullptr /*full_history_ts_low*/, &blob_callback_);
|
||||
&event_logger_, job_id, Env::IO_HIGH, nullptr /* table_properties */,
|
||||
write_hint, nullptr /*full_history_ts_low*/, &blob_callback_);
|
||||
LogFlush(immutable_db_options_.info_log);
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log,
|
||||
"[%s] [WriteLevel0TableForRecovery]"
|
||||
|
||||
@@ -415,7 +415,7 @@ Iterator* DBImplSecondary::NewIterator(const ReadOptions& read_options,
|
||||
return NewErrorIterator(
|
||||
Status::NotSupported("snapshot not supported in secondary mode"));
|
||||
} else {
|
||||
SequenceNumber snapshot(kMaxSequenceNumber);
|
||||
auto snapshot = versions_->LastSequence();
|
||||
result = NewIteratorImpl(read_options, cfd, snapshot, read_callback);
|
||||
}
|
||||
return result;
|
||||
@@ -423,19 +423,14 @@ Iterator* DBImplSecondary::NewIterator(const ReadOptions& read_options,
|
||||
|
||||
ArenaWrappedDBIter* DBImplSecondary::NewIteratorImpl(
|
||||
const ReadOptions& read_options, ColumnFamilyData* cfd,
|
||||
SequenceNumber snapshot, ReadCallback* read_callback,
|
||||
bool expose_blob_index, bool allow_refresh) {
|
||||
SequenceNumber snapshot, ReadCallback* read_callback) {
|
||||
assert(nullptr != cfd);
|
||||
SuperVersion* super_version = cfd->GetReferencedSuperVersion(this);
|
||||
assert(snapshot == kMaxSequenceNumber);
|
||||
snapshot = versions_->LastSequence();
|
||||
assert(snapshot != kMaxSequenceNumber);
|
||||
auto db_iter = NewArenaWrappedDbIterator(
|
||||
env_, read_options, *cfd->ioptions(), super_version->mutable_cf_options,
|
||||
super_version->current, snapshot,
|
||||
super_version->mutable_cf_options.max_sequential_skip_in_iterations,
|
||||
super_version->version_number, read_callback, this, cfd,
|
||||
expose_blob_index, read_options.snapshot ? false : allow_refresh);
|
||||
super_version->version_number, read_callback);
|
||||
auto internal_iter = NewInternalIterator(
|
||||
db_iter->GetReadOptions(), cfd, super_version, db_iter->GetArena(),
|
||||
db_iter->GetRangeDelAggregator(), snapshot,
|
||||
|
||||
@@ -97,9 +97,7 @@ class DBImplSecondary : public DBImpl {
|
||||
ArenaWrappedDBIter* NewIteratorImpl(const ReadOptions& read_options,
|
||||
ColumnFamilyData* cfd,
|
||||
SequenceNumber snapshot,
|
||||
ReadCallback* read_callback,
|
||||
bool expose_blob_index = false,
|
||||
bool allow_refresh = true);
|
||||
ReadCallback* read_callback);
|
||||
|
||||
Status NewIterators(const ReadOptions& options,
|
||||
const std::vector<ColumnFamilyHandle*>& column_families,
|
||||
|
||||
+16
-39
@@ -1124,18 +1124,6 @@ IOStatus DBImpl::WriteToWAL(const WriteThread::WriteGroup& write_group,
|
||||
// writer thread, so no one will push to logs_,
|
||||
// - as long as other threads don't modify it, it's safe to read
|
||||
// from std::deque from multiple threads concurrently.
|
||||
//
|
||||
// Sync operation should work with locked log_write_mutex_, because:
|
||||
// when DBOptions.manual_wal_flush_ is set,
|
||||
// FlushWAL function will be invoked by another thread.
|
||||
// if without locked log_write_mutex_, the log file may get data
|
||||
// corruption
|
||||
|
||||
const bool needs_locking = manual_wal_flush_ && !two_write_queues_;
|
||||
if (UNLIKELY(needs_locking)) {
|
||||
log_write_mutex_.Lock();
|
||||
}
|
||||
|
||||
for (auto& log : logs_) {
|
||||
io_s = log.writer->file()->Sync(immutable_db_options_.use_fsync);
|
||||
if (!io_s.ok()) {
|
||||
@@ -1143,10 +1131,6 @@ IOStatus DBImpl::WriteToWAL(const WriteThread::WriteGroup& write_group,
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(needs_locking)) {
|
||||
log_write_mutex_.Unlock();
|
||||
}
|
||||
|
||||
if (io_s.ok() && need_log_dir_sync) {
|
||||
// We only sync WAL directory the first time WAL syncing is
|
||||
// requested, so that in case users never turn on WAL sync,
|
||||
@@ -2014,18 +1998,13 @@ Status DB::Put(const WriteOptions& opt, ColumnFamilyHandle* column_family,
|
||||
size_t ts_sz = ts->size();
|
||||
assert(column_family->GetComparator());
|
||||
assert(ts_sz == column_family->GetComparator()->timestamp_size());
|
||||
WriteBatch batch;
|
||||
Status s;
|
||||
if (key.data() + key.size() == ts->data()) {
|
||||
Slice key_with_ts = Slice(key.data(), key.size() + ts_sz);
|
||||
s = batch.Put(column_family, key_with_ts, value);
|
||||
} else {
|
||||
std::array<Slice, 2> key_with_ts_slices{{key, *ts}};
|
||||
SliceParts key_with_ts(key_with_ts_slices.data(), 2);
|
||||
std::array<Slice, 1> value_slices{{value}};
|
||||
SliceParts values(value_slices.data(), 1);
|
||||
s = batch.Put(column_family, key_with_ts, values);
|
||||
WriteBatch batch(key.size() + ts_sz + value.size() + 24, /*max_bytes=*/0,
|
||||
ts_sz);
|
||||
Status s = batch.Put(column_family, key, value);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
s = batch.AssignTimestamp(*ts);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -2044,19 +2023,17 @@ Status DB::Delete(const WriteOptions& opt, ColumnFamilyHandle* column_family,
|
||||
}
|
||||
const Slice* ts = opt.timestamp;
|
||||
assert(ts != nullptr);
|
||||
size_t ts_sz = ts->size();
|
||||
assert(column_family->GetComparator());
|
||||
assert(ts_sz == column_family->GetComparator()->timestamp_size());
|
||||
WriteBatch batch;
|
||||
Status s;
|
||||
if (key.data() + key.size() == ts->data()) {
|
||||
Slice key_with_ts = Slice(key.data(), key.size() + ts_sz);
|
||||
s = batch.Delete(column_family, key_with_ts);
|
||||
} else {
|
||||
std::array<Slice, 2> key_with_ts_slices{{key, *ts}};
|
||||
SliceParts key_with_ts(key_with_ts_slices.data(), 2);
|
||||
s = batch.Delete(column_family, key_with_ts);
|
||||
const size_t ts_sz = ts->size();
|
||||
constexpr size_t kKeyAndValueLenSize = 11;
|
||||
constexpr size_t kWriteBatchOverhead =
|
||||
WriteBatchInternal::kHeader + sizeof(ValueType) + kKeyAndValueLenSize;
|
||||
WriteBatch batch(key.size() + ts_sz + kWriteBatchOverhead, /*max_bytes=*/0,
|
||||
ts_sz);
|
||||
Status s = batch.Delete(column_family, key);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
s = batch.AssignTimestamp(*ts);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -270,7 +269,7 @@ TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
options.writable_file_max_buffer_size = 128 * 1024;
|
||||
options.bytes_per_sync = 128 * 1024;
|
||||
options.level0_file_num_compaction_trigger = 4;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(10));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(10));
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.filter_policy.reset(NewBloomFilterPolicy(10));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
@@ -397,7 +396,7 @@ TEST_F(DBIOFailureTest, FlushSstCloseError) {
|
||||
options.error_if_exists = false;
|
||||
options.paranoid_checks = true;
|
||||
options.level0_file_num_compaction_trigger = 4;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(2));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(2));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
@@ -493,7 +492,7 @@ TEST_F(DBIOFailureTest, FlushSstSyncError) {
|
||||
options.paranoid_checks = true;
|
||||
options.use_fsync = false;
|
||||
options.level0_file_num_compaction_trigger = 4;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(2));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(2));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
+7
-9
@@ -2588,11 +2588,10 @@ TEST_F(DBIteratorTest, DBIteratorTestDifferentialSnapshots) {
|
||||
std::string values[4] = {"1c", "2c", "3c", "4b"};
|
||||
int i = 0;
|
||||
for (db_iter->SeekToFirst(); db_iter->Valid(); db_iter->Next()) {
|
||||
ParsedInternalKey fkey;
|
||||
ASSERT_OK(
|
||||
ParseInternalKey(db_iter->key(), &fkey, true /* log_err_key */));
|
||||
FullKey fkey;
|
||||
ParseFullKey(db_iter->key(), &fkey);
|
||||
ASSERT_EQ(user_keys[i], fkey.user_key.ToString());
|
||||
ASSERT_EQ(kTypeValue, fkey.type);
|
||||
ASSERT_EQ(EntryType::kEntryPut, fkey.type);
|
||||
ASSERT_EQ(seqnums[i], fkey.sequence);
|
||||
ASSERT_EQ(values[i], db_iter->value().ToString());
|
||||
i++;
|
||||
@@ -2621,15 +2620,14 @@ TEST_F(DBIteratorTest, DBIteratorTestDifferentialSnapshots) {
|
||||
nullptr /* read_callback */));
|
||||
// Expecting InternalKeys in [5,8] range with correct type
|
||||
int seqnums[4] = {5,8,11,13};
|
||||
ValueType key_types[4] = {kTypeDeletion, kTypeDeletion, kTypeDeletion,
|
||||
kTypeValue};
|
||||
EntryType key_types[4] = {EntryType::kEntryDelete,EntryType::kEntryDelete,
|
||||
EntryType::kEntryDelete,EntryType::kEntryPut};
|
||||
std::string user_keys[4] = {"1","2","3","4"};
|
||||
std::string values[4] = {"", "", "", "4b"};
|
||||
int i = 0;
|
||||
for (db_iter->SeekToFirst(); db_iter->Valid(); db_iter->Next()) {
|
||||
ParsedInternalKey fkey;
|
||||
ASSERT_OK(
|
||||
ParseInternalKey(db_iter->key(), &fkey, true /* log_err_key */));
|
||||
FullKey fkey;
|
||||
ParseFullKey(db_iter->key(), &fkey);
|
||||
ASSERT_EQ(user_keys[i], fkey.user_key.ToString());
|
||||
ASSERT_EQ(key_types[i], fkey.type);
|
||||
ASSERT_EQ(seqnums[i], fkey.sequence);
|
||||
|
||||
@@ -34,9 +34,10 @@ class DbKvChecksumTest
|
||||
corrupt_byte_addend_ = std::get<1>(GetParam());
|
||||
}
|
||||
|
||||
std::pair<WriteBatch, Status> GetWriteBatch(ColumnFamilyHandle* cf_handle) {
|
||||
std::pair<WriteBatch, Status> GetWriteBatch(size_t ts_sz,
|
||||
ColumnFamilyHandle* cf_handle) {
|
||||
Status s;
|
||||
WriteBatch wb(0 /* reserved_bytes */, 0 /* max_bytes */,
|
||||
WriteBatch wb(0 /* reserved_bytes */, 0 /* max_bytes */, ts_sz,
|
||||
8 /* protection_bytes_per_entry */);
|
||||
switch (op_type_) {
|
||||
case WriteBatchOpType::kPut:
|
||||
@@ -150,7 +151,8 @@ TEST_P(DbKvChecksumTest, MemTableAddCorrupted) {
|
||||
Reopen(options);
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
auto batch_and_status = GetWriteBatch(nullptr /* cf_handle */);
|
||||
auto batch_and_status =
|
||||
GetWriteBatch(0 /* ts_sz */, nullptr /* cf_handle */);
|
||||
ASSERT_OK(batch_and_status.second);
|
||||
ASSERT_TRUE(
|
||||
db_->Write(WriteOptions(), &batch_and_status.first).IsCorruption());
|
||||
@@ -181,7 +183,7 @@ TEST_P(DbKvChecksumTest, MemTableAddWithColumnFamilyCorrupted) {
|
||||
ReopenWithColumnFamilies({kDefaultColumnFamilyName, "pikachu"}, options);
|
||||
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
auto batch_and_status = GetWriteBatch(handles_[1]);
|
||||
auto batch_and_status = GetWriteBatch(0 /* ts_sz */, handles_[1]);
|
||||
ASSERT_OK(batch_and_status.second);
|
||||
ASSERT_TRUE(
|
||||
db_->Write(WriteOptions(), &batch_and_status.first).IsCorruption());
|
||||
|
||||
+14
-14
@@ -118,7 +118,7 @@ TEST_F(DBRangeDelTest, CompactionOutputFilesExactlyFilled) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
options.level0_file_num_compaction_trigger = kNumFiles;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
options.num_levels = 2;
|
||||
options.target_file_size_base = kFileBytes;
|
||||
BlockBasedTableOptions table_options;
|
||||
@@ -166,7 +166,7 @@ TEST_F(DBRangeDelTest, MaxCompactionBytesCutsOutputFiles) {
|
||||
opts.disable_auto_compactions = true;
|
||||
opts.level0_file_num_compaction_trigger = kNumFiles;
|
||||
opts.max_compaction_bytes = kNumPerFile * kBytesPerVal;
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
// Want max_compaction_bytes to trigger the end of compaction output file, not
|
||||
// target_file_size_base, so make the latter much bigger
|
||||
opts.target_file_size_base = 100 * opts.max_compaction_bytes;
|
||||
@@ -319,7 +319,7 @@ TEST_F(DBRangeDelTest, CompactionRemovesCoveredKeys) {
|
||||
Options opts = CurrentOptions();
|
||||
opts.comparator = test::Uint64Comparator();
|
||||
opts.disable_auto_compactions = true;
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
opts.num_levels = 2;
|
||||
opts.statistics = CreateDBStatistics();
|
||||
DestroyAndReopen(opts);
|
||||
@@ -377,7 +377,7 @@ TEST_F(DBRangeDelTest, ValidLevelSubcompactionBoundaries) {
|
||||
options.level0_file_num_compaction_trigger = kNumFiles;
|
||||
options.max_bytes_for_level_base = 2 * kFileBytes;
|
||||
options.max_subcompactions = 4;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
options.num_levels = 3;
|
||||
options.target_file_size_base = kFileBytes;
|
||||
options.target_file_size_multiplier = 1;
|
||||
@@ -436,7 +436,7 @@ TEST_F(DBRangeDelTest, ValidUniversalSubcompactionBoundaries) {
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.level0_file_num_compaction_trigger = kFilesPerLevel;
|
||||
options.max_subcompactions = 4;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
options.num_levels = kNumLevels;
|
||||
options.target_file_size_base = kNumPerFile << 10;
|
||||
options.target_file_size_multiplier = 1;
|
||||
@@ -489,7 +489,7 @@ TEST_F(DBRangeDelTest, CompactionRemovesCoveredMergeOperands) {
|
||||
const int kNumPerFile = 3, kNumFiles = 3;
|
||||
Options opts = CurrentOptions();
|
||||
opts.disable_auto_compactions = true;
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(2 * kNumPerFile));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(2 * kNumPerFile));
|
||||
opts.merge_operator = MergeOperators::CreateUInt64AddOperator();
|
||||
opts.num_levels = 2;
|
||||
Reopen(opts);
|
||||
@@ -613,7 +613,7 @@ TEST_F(DBRangeDelTest, TableEvictedDuringScan) {
|
||||
opts.comparator = test::Uint64Comparator();
|
||||
opts.level0_file_num_compaction_trigger = 4;
|
||||
opts.level0_stop_writes_trigger = 4;
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(1));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
opts.num_levels = 2;
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.cache_index_and_filter_blocks = true;
|
||||
@@ -694,7 +694,7 @@ TEST_F(DBRangeDelTest, GetCoveredKeyFromImmutableMemtable) {
|
||||
// memtable can hold. It switches the active memtable to immutable (flush is
|
||||
// prevented by the above options) upon inserting an element that would
|
||||
// overflow the memtable.
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(1));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
DestroyAndReopen(opts);
|
||||
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key", "val"));
|
||||
@@ -759,7 +759,7 @@ TEST_F(DBRangeDelTest, GetIgnoresRangeDeletions) {
|
||||
Options opts = CurrentOptions();
|
||||
opts.max_write_buffer_number = 4;
|
||||
opts.min_write_buffer_number_to_merge = 3;
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(1));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
Reopen(opts);
|
||||
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "sst_key", "val"));
|
||||
@@ -788,7 +788,7 @@ TEST_F(DBRangeDelTest, IteratorRemovesCoveredKeys) {
|
||||
const int kNum = 200, kRangeBegin = 50, kRangeEnd = 150, kNumPerFile = 25;
|
||||
Options opts = CurrentOptions();
|
||||
opts.comparator = test::Uint64Comparator();
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
DestroyAndReopen(opts);
|
||||
|
||||
// Write half of the keys before the tombstone and half after the tombstone.
|
||||
@@ -823,7 +823,7 @@ TEST_F(DBRangeDelTest, IteratorOverUserSnapshot) {
|
||||
const int kNum = 200, kRangeBegin = 50, kRangeEnd = 150, kNumPerFile = 25;
|
||||
Options opts = CurrentOptions();
|
||||
opts.comparator = test::Uint64Comparator();
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(kNumPerFile));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(kNumPerFile));
|
||||
DestroyAndReopen(opts);
|
||||
|
||||
const Snapshot* snapshot = nullptr;
|
||||
@@ -857,7 +857,7 @@ TEST_F(DBRangeDelTest, IteratorIgnoresRangeDeletions) {
|
||||
Options opts = CurrentOptions();
|
||||
opts.max_write_buffer_number = 4;
|
||||
opts.min_write_buffer_number_to_merge = 3;
|
||||
opts.memtable_factory.reset(test::NewSpecialSkipListFactory(1));
|
||||
opts.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
Reopen(opts);
|
||||
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "sst_key", "val"));
|
||||
@@ -1005,7 +1005,7 @@ TEST_F(DBRangeDelTest, CompactionTreatsSplitInputLevelDeletionAtomically) {
|
||||
options.compression = kNoCompression;
|
||||
options.level0_file_num_compaction_trigger = kNumFilesPerLevel;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2 /* num_entries_flush */));
|
||||
new SpecialSkipListFactory(2 /* num_entries_flush */));
|
||||
options.target_file_size_base = kValueBytes;
|
||||
// i == 0: CompactFiles
|
||||
// i == 1: CompactRange
|
||||
@@ -1073,7 +1073,7 @@ TEST_F(DBRangeDelTest, RangeTombstoneEndKeyAsSstableUpperBound) {
|
||||
options.compression = kNoCompression;
|
||||
options.level0_file_num_compaction_trigger = kNumFilesPerLevel;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(2 /* num_entries_flush */));
|
||||
new SpecialSkipListFactory(2 /* num_entries_flush */));
|
||||
options.target_file_size_base = kValueBytes;
|
||||
options.disable_auto_compactions = true;
|
||||
|
||||
|
||||
+3
-82
@@ -12,7 +12,6 @@
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/utilities/transaction_db.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -561,84 +560,6 @@ TEST_F(DBSecondaryTest, OpenAsSecondaryWALTailing) {
|
||||
verify_db_func("new_foo_value_1", "new_bar_value");
|
||||
}
|
||||
|
||||
TEST_F(DBSecondaryTest, SecondaryTailingBug_ISSUE_8467) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
Reopen(options);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ASSERT_OK(Put("foo", "foo_value" + std::to_string(i)));
|
||||
ASSERT_OK(Put("bar", "bar_value" + std::to_string(i)));
|
||||
}
|
||||
|
||||
Options options1;
|
||||
options1.env = env_;
|
||||
options1.max_open_files = -1;
|
||||
OpenSecondary(options1);
|
||||
|
||||
const auto verify_db = [&](const std::string& foo_val,
|
||||
const std::string& bar_val) {
|
||||
std::string value;
|
||||
ReadOptions ropts;
|
||||
Status s = db_secondary_->Get(ropts, "foo", &value);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ(foo_val, value);
|
||||
|
||||
s = db_secondary_->Get(ropts, "bar", &value);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_EQ(bar_val, value);
|
||||
};
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ASSERT_OK(db_secondary_->TryCatchUpWithPrimary());
|
||||
verify_db("foo_value2", "bar_value2");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBSecondaryTest, RefreshIterator) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
Reopen(options);
|
||||
|
||||
Options options1;
|
||||
options1.env = env_;
|
||||
options1.max_open_files = -1;
|
||||
OpenSecondary(options1);
|
||||
|
||||
std::unique_ptr<Iterator> it(db_secondary_->NewIterator(ReadOptions()));
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ASSERT_OK(Put("foo", "foo_value" + std::to_string(i)));
|
||||
|
||||
ASSERT_OK(db_secondary_->TryCatchUpWithPrimary());
|
||||
if (0 == i) {
|
||||
it->Seek("foo");
|
||||
ASSERT_FALSE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
|
||||
ASSERT_OK(it->Refresh());
|
||||
|
||||
it->Seek("foo");
|
||||
ASSERT_OK(it->status());
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("foo", it->key());
|
||||
ASSERT_EQ("foo_value0", it->value());
|
||||
} else {
|
||||
it->Seek("foo");
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("foo", it->key());
|
||||
ASSERT_EQ("foo_value" + std::to_string(i - 1), it->value());
|
||||
ASSERT_OK(it->status());
|
||||
|
||||
ASSERT_OK(it->Refresh());
|
||||
|
||||
it->Seek("foo");
|
||||
ASSERT_OK(it->status());
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("foo", it->key());
|
||||
ASSERT_EQ("foo_value" + std::to_string(i), it->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DBSecondaryTest, OpenWithNonExistColumnFamily) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
@@ -938,7 +859,7 @@ TEST_F(DBSecondaryTest, DISABLED_SwitchWAL) {
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 2;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
new SpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
Reopen(options);
|
||||
|
||||
Options options1;
|
||||
@@ -993,7 +914,7 @@ TEST_F(DBSecondaryTest, DISABLED_SwitchWALMultiColumnFamilies) {
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 2;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
new SpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
CreateAndReopenWithCF({kCFName1}, options);
|
||||
|
||||
Options options1;
|
||||
@@ -1057,7 +978,7 @@ TEST_F(DBSecondaryTest, CatchUpAfterFlush) {
|
||||
options.max_write_buffer_number = 4;
|
||||
options.min_write_buffer_number_to_merge = 2;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
new SpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
Reopen(options);
|
||||
|
||||
Options options1;
|
||||
|
||||
+1
-12
@@ -809,11 +809,9 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
|
||||
// Create 4 files in L0
|
||||
for (char v = 'a'; v <= 'd'; v++) {
|
||||
if (v == 'c') {
|
||||
if (v == 'd') {
|
||||
// Maximize the change that the last log file will be preserved in trash
|
||||
// before restarting the DB.
|
||||
// We have to set this on the 2nd to last file for it to delay deletion
|
||||
// on the last file. (Quirk of DeleteScheduler::BackgroundEmptyTrash())
|
||||
options.sst_file_manager->SetDeleteRateBytesPerSecond(1);
|
||||
}
|
||||
ASSERT_OK(Put("Key2", DummyString(1024, v)));
|
||||
@@ -1665,17 +1663,8 @@ TEST_F(DBSSTTest, DBWithSFMForBlobFilesAtomicFlush) {
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
void RegisterCustomObjects(int argc, char** argv);
|
||||
}
|
||||
#else
|
||||
void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -155,55 +155,6 @@ TEST_F(DBStatisticsTest, ExcludeTickers) {
|
||||
ASSERT_GT(options.statistics->getTickerCount(BYTES_READ), 0);
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
TEST_F(DBStatisticsTest, VerifyChecksumReadStat) {
|
||||
Options options = CurrentOptions();
|
||||
options.file_checksum_gen_factory = GetFileChecksumGenCrc32cFactory();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
Reopen(options);
|
||||
|
||||
// Expected to be populated regardless of `PerfLevel` in user thread
|
||||
SetPerfLevel(kDisable);
|
||||
|
||||
{
|
||||
// Scenario 0: only WAL data. Not verified so require ticker to be zero.
|
||||
ASSERT_OK(Put("foo", "value"));
|
||||
ASSERT_OK(db_->VerifyFileChecksums(ReadOptions()));
|
||||
ASSERT_OK(db_->VerifyChecksum());
|
||||
ASSERT_EQ(0,
|
||||
options.statistics->getTickerCount(VERIFY_CHECKSUM_READ_BYTES));
|
||||
}
|
||||
|
||||
// Create one SST.
|
||||
ASSERT_OK(Flush());
|
||||
std::unordered_map<std::string, uint64_t> table_files;
|
||||
uint64_t table_files_size = 0;
|
||||
GetAllDataFiles(kTableFile, &table_files, &table_files_size);
|
||||
|
||||
{
|
||||
// Scenario 1: Table verified in `VerifyFileChecksums()`. This should read
|
||||
// the whole file so we require the ticker stat exactly matches the file
|
||||
// size.
|
||||
ASSERT_OK(options.statistics->Reset());
|
||||
ASSERT_OK(db_->VerifyFileChecksums(ReadOptions()));
|
||||
ASSERT_EQ(table_files_size,
|
||||
options.statistics->getTickerCount(VERIFY_CHECKSUM_READ_BYTES));
|
||||
}
|
||||
|
||||
{
|
||||
// Scenario 2: Table verified in `VerifyChecksum()`. This opens a
|
||||
// `TableReader` to verify each block. It can involve duplicate reads of the
|
||||
// same data so we set a lower-bound only.
|
||||
ASSERT_OK(options.statistics->Reset());
|
||||
ASSERT_OK(db_->VerifyChecksum());
|
||||
ASSERT_GE(options.statistics->getTickerCount(VERIFY_CHECKSUM_READ_BYTES),
|
||||
table_files_size);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
+7
-89
@@ -34,6 +34,7 @@
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "env/mock_env.h"
|
||||
#include "file/filename.h"
|
||||
#include "memtable/hash_linklist_rep.h"
|
||||
#include "monitoring/thread_status_util.h"
|
||||
#include "port/port.h"
|
||||
#include "port/stack_trace.h"
|
||||
@@ -2811,7 +2812,7 @@ TEST_F(DBTest, GroupCommitTest) {
|
||||
#endif // TRAVIS
|
||||
|
||||
namespace {
|
||||
using KVMap = std::map<std::string, std::string>;
|
||||
typedef std::map<std::string, std::string> KVMap;
|
||||
}
|
||||
|
||||
class ModelDB : public DB {
|
||||
@@ -3937,56 +3938,6 @@ TEST_F(DBTest, DISABLED_RateLimitingTest) {
|
||||
ASSERT_LT(ratio, 0.6);
|
||||
}
|
||||
|
||||
// This is a mocked customed rate limiter without implementing optional APIs
|
||||
// (e.g, RateLimiter::GetTotalPendingRequests())
|
||||
class MockedRateLimiterWithNoOptionalAPIImpl : public RateLimiter {
|
||||
public:
|
||||
MockedRateLimiterWithNoOptionalAPIImpl() {}
|
||||
|
||||
~MockedRateLimiterWithNoOptionalAPIImpl() override {}
|
||||
|
||||
void SetBytesPerSecond(int64_t bytes_per_second) override {
|
||||
(void)bytes_per_second;
|
||||
}
|
||||
|
||||
using RateLimiter::Request;
|
||||
void Request(const int64_t bytes, const Env::IOPriority pri,
|
||||
Statistics* stats) override {
|
||||
(void)bytes;
|
||||
(void)pri;
|
||||
(void)stats;
|
||||
}
|
||||
|
||||
int64_t GetSingleBurstBytes() const override { return 200; }
|
||||
|
||||
int64_t GetTotalBytesThrough(
|
||||
const Env::IOPriority pri = Env::IO_TOTAL) const override {
|
||||
(void)pri;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t GetTotalRequests(
|
||||
const Env::IOPriority pri = Env::IO_TOTAL) const override {
|
||||
(void)pri;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t GetBytesPerSecond() const override { return 0; }
|
||||
};
|
||||
|
||||
// To test that customed rate limiter not implementing optional APIs (e.g,
|
||||
// RateLimiter::GetTotalPendingRequests()) works fine with RocksDB basic
|
||||
// operations (e.g, Put, Get, Flush)
|
||||
TEST_F(DBTest, CustomedRateLimiterWithNoOptionalAPIImplTest) {
|
||||
Options options = CurrentOptions();
|
||||
options.rate_limiter.reset(new MockedRateLimiterWithNoOptionalAPIImpl());
|
||||
DestroyAndReopen(options);
|
||||
ASSERT_OK(Put("abc", "def"));
|
||||
ASSERT_EQ(Get("abc"), "def");
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(Get("abc"), "def");
|
||||
}
|
||||
|
||||
TEST_F(DBTest, TableOptionsSanitizeTest) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -4148,39 +4099,6 @@ TEST_F(DBTest, ConcurrentFlushWAL) {
|
||||
}
|
||||
}
|
||||
|
||||
// This test failure will be caught with a probability
|
||||
TEST_F(DBTest, ManualFlushWalAndWriteRace) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
options.manual_wal_flush = true;
|
||||
options.create_if_missing = true;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
WriteOptions wopts;
|
||||
wopts.sync = true;
|
||||
|
||||
port::Thread writeThread([&]() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
auto istr = ToString(i);
|
||||
dbfull()->Put(wopts, "key_" + istr, "value_" + istr);
|
||||
}
|
||||
});
|
||||
port::Thread flushThread([&]() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ASSERT_OK(dbfull()->FlushWAL(false));
|
||||
}
|
||||
});
|
||||
|
||||
writeThread.join();
|
||||
flushThread.join();
|
||||
ASSERT_OK(dbfull()->Put(wopts, "foo1", "value1"));
|
||||
ASSERT_OK(dbfull()->Put(wopts, "foo2", "value2"));
|
||||
Reopen(options);
|
||||
ASSERT_EQ("value1", Get("foo1"));
|
||||
ASSERT_EQ("value2", Get("foo2"));
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBTest, DynamicMemtableOptions) {
|
||||
const uint64_t k64KB = 1 << 16;
|
||||
@@ -5814,8 +5732,8 @@ TEST_F(DBTest, DISABLED_SuggestCompactRangeTest) {
|
||||
};
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(
|
||||
DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.compaction_filter_factory.reset(
|
||||
new CompactionFilterFactoryGetContext());
|
||||
@@ -6220,7 +6138,7 @@ TEST_F(DBTest, DelayedWriteRate) {
|
||||
options.level0_stop_writes_trigger = 999999;
|
||||
options.delayed_write_rate = 20000000; // Start with 200MB/s
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kEntriesPerMemTable));
|
||||
new SpecialSkipListFactory(kEntriesPerMemTable));
|
||||
|
||||
SetTimeElapseOnlySleepOnReopen(&options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
@@ -6283,7 +6201,7 @@ TEST_F(DBTest, HardLimit) {
|
||||
options.max_bytes_for_level_base = 10000000000u;
|
||||
options.max_background_compactions = 1;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
|
||||
env_->SetBackgroundThreads(1, Env::LOW);
|
||||
test::SleepingBackgroundTask sleeping_task_low;
|
||||
@@ -6532,7 +6450,7 @@ TEST_F(DBTest, LastWriteBufferDelay) {
|
||||
options.disable_auto_compactions = true;
|
||||
int kNumKeysPerMemtable = 3;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
new SpecialSkipListFactory(kNumKeysPerMemtable));
|
||||
|
||||
Reopen(options);
|
||||
test::SleepingBackgroundTask sleeping_task;
|
||||
|
||||
+8
-11
@@ -22,7 +22,6 @@
|
||||
#include "rocksdb/trace_record_result.h"
|
||||
#include "rocksdb/utilities/replayer.h"
|
||||
#include "rocksdb/wal_filter.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/random.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
|
||||
@@ -1265,7 +1264,7 @@ TEST_F(DBTest2, PresetCompressionDict) {
|
||||
options.disable_auto_compactions = true;
|
||||
options.level0_file_num_compaction_trigger = kNumL0Files;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kL0FileBytes / kBlockSizeBytes));
|
||||
new SpecialSkipListFactory(kL0FileBytes / kBlockSizeBytes));
|
||||
options.num_levels = 2;
|
||||
options.target_file_size_base = kL0FileBytes;
|
||||
options.target_file_size_multiplier = 2;
|
||||
@@ -1485,7 +1484,7 @@ TEST_P(PresetCompressionDictTest, Flush) {
|
||||
options.compression_opts.max_dict_bytes = kDictLen;
|
||||
options.compression_opts.max_dict_buffer_bytes = kBlockLen;
|
||||
}
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(kKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kKeysPerFile));
|
||||
options.statistics = CreateDBStatistics();
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.block_size = kBlockLen;
|
||||
@@ -1685,9 +1684,9 @@ class CompactionCompressionListener : public EventListener {
|
||||
int bottommost_level = 0;
|
||||
for (int level = 0; level < db->NumberLevels(); level++) {
|
||||
std::string files_at_level;
|
||||
ASSERT_TRUE(db->GetProperty(
|
||||
"rocksdb.num-files-at-level" + ROCKSDB_NAMESPACE::ToString(level),
|
||||
&files_at_level));
|
||||
ASSERT_TRUE(
|
||||
db->GetProperty("rocksdb.num-files-at-level" + NumberToString(level),
|
||||
&files_at_level));
|
||||
if (files_at_level != "0") {
|
||||
bottommost_level = level;
|
||||
}
|
||||
@@ -2320,8 +2319,8 @@ INSTANTIATE_TEST_CASE_P(PinL0IndexAndFilterBlocksTest,
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBTest2, MaxCompactionBytesTest) {
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(
|
||||
DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 200 << 10;
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -3946,8 +3945,7 @@ TEST_F(DBTest2, RateLimitedCompactionReads) {
|
||||
Options options = CurrentOptions();
|
||||
options.compression = kNoCompression;
|
||||
options.level0_file_num_compaction_trigger = kNumL0Files;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.new_table_reader_for_compaction_inputs = true;
|
||||
// takes roughly one second, split into 100 x 10ms intervals. Each interval
|
||||
// permits 5.12KB, which is smaller than the block size, so this test
|
||||
@@ -5588,7 +5586,6 @@ TEST_F(DBTest2, MultiDBParallelOpenTest) {
|
||||
namespace {
|
||||
class DummyOldStats : public Statistics {
|
||||
public:
|
||||
const char* Name() const override { return "DummyOldStats"; }
|
||||
uint64_t getTickerCount(uint32_t /*ticker_type*/) const override { return 0; }
|
||||
void recordTick(uint32_t /* ticker_type */, uint64_t /* count */) override {
|
||||
num_rt++;
|
||||
|
||||
+9
-7
@@ -1070,12 +1070,12 @@ int DBTestBase::NumTableFilesAtLevel(int level, int cf) {
|
||||
std::string property;
|
||||
if (cf == 0) {
|
||||
// default cfd
|
||||
EXPECT_TRUE(db_->GetProperty("rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(level), &property));
|
||||
} else {
|
||||
EXPECT_TRUE(db_->GetProperty(handles_[cf],
|
||||
"rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
handles_[cf], "rocksdb.num-files-at-level" + NumberToString(level),
|
||||
&property));
|
||||
}
|
||||
return atoi(property.c_str());
|
||||
}
|
||||
@@ -1085,10 +1085,12 @@ double DBTestBase::CompressionRatioAtLevel(int level, int cf) {
|
||||
if (cf == 0) {
|
||||
// default cfd
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.compression-ratio-at-level" + ToString(level), &property));
|
||||
"rocksdb.compression-ratio-at-level" + NumberToString(level),
|
||||
&property));
|
||||
} else {
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
handles_[cf], "rocksdb.compression-ratio-at-level" + ToString(level),
|
||||
handles_[cf],
|
||||
"rocksdb.compression-ratio-at-level" + NumberToString(level),
|
||||
&property));
|
||||
}
|
||||
return std::stod(property);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "db/db_impl/db_impl.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "file/filename.h"
|
||||
#include "memtable/hash_linklist_rep.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
@@ -111,6 +112,94 @@ struct OptionsOverride {
|
||||
|
||||
enum SkipPolicy { kSkipNone = 0, kSkipNoSnapshot = 1, kSkipNoPrefix = 2 };
|
||||
|
||||
// A hacky skip list mem table that triggers flush after number of entries.
|
||||
class SpecialMemTableRep : public MemTableRep {
|
||||
public:
|
||||
explicit SpecialMemTableRep(Allocator* allocator, MemTableRep* memtable,
|
||||
int num_entries_flush)
|
||||
: MemTableRep(allocator),
|
||||
memtable_(memtable),
|
||||
num_entries_flush_(num_entries_flush),
|
||||
num_entries_(0) {}
|
||||
|
||||
virtual KeyHandle Allocate(const size_t len, char** buf) override {
|
||||
return memtable_->Allocate(len, buf);
|
||||
}
|
||||
|
||||
// Insert key into the list.
|
||||
// REQUIRES: nothing that compares equal to key is currently in the list.
|
||||
virtual void Insert(KeyHandle handle) override {
|
||||
num_entries_++;
|
||||
memtable_->Insert(handle);
|
||||
}
|
||||
|
||||
void InsertConcurrently(KeyHandle handle) override {
|
||||
num_entries_++;
|
||||
memtable_->Insert(handle);
|
||||
}
|
||||
|
||||
// Returns true iff an entry that compares equal to key is in the list.
|
||||
virtual bool Contains(const char* key) const override {
|
||||
return memtable_->Contains(key);
|
||||
}
|
||||
|
||||
virtual size_t ApproximateMemoryUsage() override {
|
||||
// Return a high memory usage when number of entries exceeds the threshold
|
||||
// to trigger a flush.
|
||||
return (num_entries_ < num_entries_flush_) ? 0 : 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
virtual void Get(const LookupKey& k, void* callback_args,
|
||||
bool (*callback_func)(void* arg,
|
||||
const char* entry)) override {
|
||||
memtable_->Get(k, callback_args, callback_func);
|
||||
}
|
||||
|
||||
uint64_t ApproximateNumEntries(const Slice& start_ikey,
|
||||
const Slice& end_ikey) override {
|
||||
return memtable_->ApproximateNumEntries(start_ikey, end_ikey);
|
||||
}
|
||||
|
||||
virtual MemTableRep::Iterator* GetIterator(Arena* arena = nullptr) override {
|
||||
return memtable_->GetIterator(arena);
|
||||
}
|
||||
|
||||
virtual ~SpecialMemTableRep() override {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<MemTableRep> memtable_;
|
||||
int num_entries_flush_;
|
||||
int num_entries_;
|
||||
};
|
||||
|
||||
// The factory for the hacky skip list mem table that triggers flush after
|
||||
// number of entries exceeds a threshold.
|
||||
class SpecialSkipListFactory : public MemTableRepFactory {
|
||||
public:
|
||||
// After number of inserts exceeds `num_entries_flush` in a mem table, trigger
|
||||
// flush.
|
||||
explicit SpecialSkipListFactory(int num_entries_flush)
|
||||
: num_entries_flush_(num_entries_flush) {}
|
||||
|
||||
using MemTableRepFactory::CreateMemTableRep;
|
||||
virtual MemTableRep* CreateMemTableRep(
|
||||
const MemTableRep::KeyComparator& compare, Allocator* allocator,
|
||||
const SliceTransform* transform, Logger* /*logger*/) override {
|
||||
return new SpecialMemTableRep(
|
||||
allocator, factory_.CreateMemTableRep(compare, allocator, transform, 0),
|
||||
num_entries_flush_);
|
||||
}
|
||||
virtual const char* Name() const override { return "SkipListFactory"; }
|
||||
|
||||
bool IsInsertConcurrentlySupported() const override {
|
||||
return factory_.IsInsertConcurrentlySupported();
|
||||
}
|
||||
|
||||
private:
|
||||
SkipListFactory factory_;
|
||||
int num_entries_flush_;
|
||||
};
|
||||
|
||||
// Special Env used to delay background operations
|
||||
class SpecialEnv : public EnvWrapper {
|
||||
public:
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "rocksdb/utilities/table_properties_collectors.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -152,7 +151,7 @@ TEST_P(DBTestUniversalCompaction, OptimizeFiltersForHits) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
options.optimize_filters_for_hits = true;
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(3));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(3));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
@@ -1231,7 +1230,7 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionFourPaths) {
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 500 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_4", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.compaction_options_universal.size_ratio = 5;
|
||||
options.write_buffer_size = 111 << 10; // 114KB
|
||||
@@ -1335,7 +1334,7 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionCFPathUse) {
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 500 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_4", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.compaction_options_universal.size_ratio = 10;
|
||||
options.write_buffer_size = 111 << 10; // 114KB
|
||||
@@ -1499,8 +1498,7 @@ TEST_P(DBTestUniversalCompaction, IncreaseUniversalCompactionNumLevels) {
|
||||
options.num_levels = 1;
|
||||
options.write_buffer_size = 200 << 10; // 200KB
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(KNumKeysPerFile));
|
||||
options = CurrentOptions(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
@@ -1581,7 +1579,7 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionSecondPathRatio) {
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.num_levels = 1;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
|
||||
std::vector<std::string> filenames;
|
||||
if (env_->GetChildren(options.db_paths[1].path, &filenames).ok()) {
|
||||
@@ -1731,7 +1729,7 @@ TEST_P(DBTestUniversalCompaction, RecalculateScoreAfterPicking) {
|
||||
const int kNumFilesTrigger = 8;
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_options_universal.max_merge_width = kNumFilesTrigger / 2;
|
||||
options.compaction_options_universal.max_size_amplification_percent =
|
||||
static_cast<unsigned int>(-1);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "test_util/sync_point.h"
|
||||
#endif
|
||||
#include "test_util/testutil.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -196,69 +195,6 @@ class DBBasicTestWithTimestamp : public DBBasicTestWithTimestampBase {
|
||||
: DBBasicTestWithTimestampBase("db_basic_test_with_timestamp") {}
|
||||
};
|
||||
|
||||
TEST_F(DBBasicTestWithTimestamp, MixedCfs) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
options.avoid_flush_during_shutdown = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Options options1 = CurrentOptions();
|
||||
options1.env = env_;
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options1.comparator = &test_cmp;
|
||||
ColumnFamilyHandle* handle = nullptr;
|
||||
Status s = db_->CreateColumnFamily(options1, "data", &handle);
|
||||
ASSERT_OK(s);
|
||||
|
||||
WriteBatch wb;
|
||||
ASSERT_OK(wb.Put("a", "value"));
|
||||
{
|
||||
std::string key("a");
|
||||
std::string ts(kTimestampSize, '\0');
|
||||
std::array<Slice, 2> key_with_ts_slices{{key, ts}};
|
||||
SliceParts key_with_ts(key_with_ts_slices.data(), 2);
|
||||
std::string value_str("value");
|
||||
Slice value_slice(value_str.data(), value_str.size());
|
||||
SliceParts value(&value_slice, 1);
|
||||
ASSERT_OK(wb.Put(handle, key_with_ts, value));
|
||||
}
|
||||
{
|
||||
std::string ts = Timestamp(1, 0);
|
||||
std::vector<Slice> ts_list({Slice(), ts});
|
||||
ASSERT_OK(wb.AssignTimestamps(ts_list));
|
||||
ASSERT_OK(db_->Write(WriteOptions(), &wb));
|
||||
}
|
||||
|
||||
const auto verify_db = [this](ColumnFamilyHandle* h) {
|
||||
ASSERT_EQ("value", Get("a"));
|
||||
std::string ts = Timestamp(1, 0);
|
||||
Slice read_ts_slice(ts);
|
||||
ReadOptions read_opts;
|
||||
read_opts.timestamp = &read_ts_slice;
|
||||
std::string value;
|
||||
ASSERT_OK(db_->Get(read_opts, h, "a", &value));
|
||||
ASSERT_EQ("value", value);
|
||||
};
|
||||
|
||||
verify_db(handle);
|
||||
|
||||
delete handle;
|
||||
Close();
|
||||
|
||||
std::vector<ColumnFamilyDescriptor> cf_descs;
|
||||
cf_descs.emplace_back(kDefaultColumnFamilyName, options);
|
||||
cf_descs.emplace_back("data", options1);
|
||||
options.create_if_missing = false;
|
||||
s = DB::Open(options, dbname_, cf_descs, &handles_, &db_);
|
||||
ASSERT_OK(s);
|
||||
|
||||
verify_db(handles_[1]);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTestWithTimestamp, CompactRangeWithSpecifiedRange) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
@@ -479,8 +415,7 @@ TEST_F(DBBasicTestWithTimestamp, SimpleIterate) {
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
const std::vector<uint64_t> start_keys = {1, 0};
|
||||
const std::vector<std::string> write_timestamps = {Timestamp(1, 0),
|
||||
@@ -829,15 +764,11 @@ TEST_F(DBBasicTestWithTimestamp, ChangeIterationDirection) {
|
||||
const std::vector<std::tuple<std::string, std::string>> kvs = {
|
||||
std::make_tuple("aa", "value1"), std::make_tuple("ab", "value2")};
|
||||
for (const auto& ts : timestamps) {
|
||||
WriteBatch wb;
|
||||
WriteBatch wb(0, 0, kTimestampSize);
|
||||
for (const auto& kv : kvs) {
|
||||
const std::string& key = std::get<0>(kv);
|
||||
const std::string& value = std::get<1>(kv);
|
||||
std::array<Slice, 2> key_with_ts_slices{{Slice(key), Slice(ts)}};
|
||||
SliceParts key_with_ts(key_with_ts_slices.data(), 2);
|
||||
std::array<Slice, 1> value_slices{{Slice(value)}};
|
||||
SliceParts values(value_slices.data(), 1);
|
||||
ASSERT_OK(wb.Put(key_with_ts, values));
|
||||
ASSERT_OK(wb.Put(key, value));
|
||||
}
|
||||
|
||||
ASSERT_OK(wb.AssignTimestamp(ts));
|
||||
@@ -911,8 +842,7 @@ TEST_F(DBBasicTestWithTimestamp, SimpleForwardIterateLowerTsBound) {
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
const std::vector<std::string> write_timestamps = {Timestamp(1, 0),
|
||||
Timestamp(3, 0)};
|
||||
@@ -997,8 +927,7 @@ TEST_F(DBBasicTestWithTimestamp, ForwardIterateStartSeqnum) {
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
std::vector<SequenceNumber> start_seqs;
|
||||
|
||||
@@ -1139,20 +1068,9 @@ TEST_F(DBBasicTestWithTimestamp, ReseekToNextUserKey) {
|
||||
}
|
||||
{
|
||||
std::string ts_str = Timestamp(static_cast<uint64_t>(kNumKeys + 1), 0);
|
||||
WriteBatch batch;
|
||||
const std::string dummy_ts(kTimestampSize, '\0');
|
||||
{
|
||||
std::array<Slice, 2> key_with_ts_slices{{"a", dummy_ts}};
|
||||
SliceParts key_with_ts(key_with_ts_slices.data(), 2);
|
||||
std::array<Slice, 1> value_slices{{"new_value"}};
|
||||
SliceParts values(value_slices.data(), 1);
|
||||
ASSERT_OK(batch.Put(key_with_ts, values));
|
||||
}
|
||||
{
|
||||
std::string key_with_ts("b");
|
||||
key_with_ts.append(dummy_ts);
|
||||
ASSERT_OK(batch.Put(key_with_ts, "new_value"));
|
||||
}
|
||||
WriteBatch batch(0, 0, kTimestampSize);
|
||||
ASSERT_OK(batch.Put("a", "new_value"));
|
||||
ASSERT_OK(batch.Put("b", "new_value"));
|
||||
s = batch.AssignTimestamp(ts_str);
|
||||
ASSERT_OK(s);
|
||||
s = db_->Write(write_opts, &batch);
|
||||
@@ -2317,8 +2235,7 @@ TEST_P(DBBasicTestWithTimestampCompressionSettings, PutAndGet) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.env = env_;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
size_t ts_sz = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(ts_sz);
|
||||
options.comparator = &test_cmp;
|
||||
@@ -2396,8 +2313,7 @@ TEST_P(DBBasicTestWithTimestampCompressionSettings, PutDeleteGet) {
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
const int kNumKeysPerFile = 1024;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy = std::get<0>(GetParam());
|
||||
bbto.whole_key_filtering = true;
|
||||
@@ -2526,8 +2442,7 @@ TEST_P(DBBasicTestWithTimestampCompressionSettings, PutAndGetWithCompaction) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.env = env_;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
|
||||
FlushedFileCollector* collector = new FlushedFileCollector();
|
||||
options.listeners.emplace_back(collector);
|
||||
@@ -2643,8 +2558,7 @@ TEST_F(DBBasicTestWithTimestamp, BatchWriteAndMultiGet) {
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
options.env = env_;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_prefix_bloom_size_ratio = 0.1;
|
||||
options.memtable_whole_key_filtering = true;
|
||||
|
||||
@@ -2693,23 +2607,17 @@ TEST_F(DBBasicTestWithTimestamp, BatchWriteAndMultiGet) {
|
||||
}
|
||||
};
|
||||
|
||||
const std::string dummy_ts(ts_sz, '\0');
|
||||
for (size_t i = 0; i != kNumTimestamps; ++i) {
|
||||
write_ts_list.push_back(Timestamp(i * 2, 0));
|
||||
read_ts_list.push_back(Timestamp(1 + i * 2, 0));
|
||||
const Slice& write_ts = write_ts_list.back();
|
||||
for (int cf = 0; cf != static_cast<int>(num_cfs); ++cf) {
|
||||
WriteOptions wopts;
|
||||
WriteBatch batch;
|
||||
WriteBatch batch(0, 0, ts_sz);
|
||||
for (size_t j = 0; j != kNumKeysPerTimestamp; ++j) {
|
||||
const std::string key = Key1(j);
|
||||
const std::string value =
|
||||
"value_" + std::to_string(j) + "_" + std::to_string(i);
|
||||
std::array<Slice, 2> key_with_ts_slices{{key, dummy_ts}};
|
||||
SliceParts key_with_ts(key_with_ts_slices.data(), 2);
|
||||
std::array<Slice, 1> value_slices{{value}};
|
||||
SliceParts values(value_slices.data(), 1);
|
||||
ASSERT_OK(batch.Put(handles_[cf], key_with_ts, values));
|
||||
ASSERT_OK(
|
||||
batch.Put(handles_[cf], Key1(j),
|
||||
"value_" + std::to_string(j) + "_" + std::to_string(i)));
|
||||
}
|
||||
ASSERT_OK(batch.AssignTimestamp(write_ts));
|
||||
ASSERT_OK(db_->Write(wopts, &batch));
|
||||
@@ -2817,8 +2725,7 @@ TEST_P(DBBasicTestWithTimestampPrefixSeek, IterateWithPrefix) {
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.prefix_extractor = std::get<0>(GetParam());
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy = std::get<1>(GetParam());
|
||||
bbto.index_type = std::get<3>(GetParam());
|
||||
@@ -2972,8 +2879,7 @@ TEST_P(DBBasicTestWithTsIterTombstones, IterWithDelete) {
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.prefix_extractor = std::get<0>(GetParam());
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy = std::get<1>(GetParam());
|
||||
bbto.index_type = std::get<3>(GetParam());
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "db/compaction/compaction.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/testutil.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -57,8 +56,7 @@ TEST_F(TimestampCompatibleCompactionTest, UserKeyCrossFileBoundary) {
|
||||
options.comparator = test::ComparatorWithU64Ts();
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
constexpr size_t kNumKeysPerFile = 101;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
|
||||
@@ -47,6 +47,18 @@ EntryType GetEntryType(ValueType value_type) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ParseFullKey(const Slice& internal_key, FullKey* fkey) {
|
||||
ParsedInternalKey ikey;
|
||||
if (!ParseInternalKey(internal_key, &ikey, false /*log_err_key */)
|
||||
.ok()) { // TODO
|
||||
return false;
|
||||
}
|
||||
fkey->user_key = ikey.user_key;
|
||||
fkey->sequence = ikey.sequence;
|
||||
fkey->type = GetEntryType(ikey.type);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
|
||||
result->append(key.user_key.data(), key.user_key.size());
|
||||
PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
|
||||
|
||||
@@ -1576,11 +1576,11 @@ TEST_F(DBErrorHandlingFSTest, MultiDBCompactionError) {
|
||||
std::string prop;
|
||||
ASSERT_EQ(listener[i]->WaitForRecovery(5000000), true);
|
||||
ASSERT_OK(static_cast<DBImpl*>(db[i])->TEST_WaitForCompact(true));
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(0), &prop));
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(0), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 0);
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(1), &prop));
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(1), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 1);
|
||||
}
|
||||
|
||||
@@ -1713,11 +1713,11 @@ TEST_F(DBErrorHandlingFSTest, MultiDBVariousErrors) {
|
||||
if (i == 1) {
|
||||
ASSERT_OK(static_cast<DBImpl*>(db[i])->TEST_WaitForCompact(true));
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(0), &prop));
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(0), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 0);
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(1), &prop));
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(1), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 1);
|
||||
}
|
||||
|
||||
|
||||
+3
-103
@@ -37,9 +37,6 @@ void EventHelpers::NotifyTableFileCreationStarted(
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
const std::string& db_name, const std::string& cf_name,
|
||||
const std::string& file_path, int job_id, TableFileCreationReason reason) {
|
||||
if (listeners.empty()) {
|
||||
return;
|
||||
}
|
||||
TableFileCreationBriefInfo info;
|
||||
info.db_name = db_name;
|
||||
info.cf_name = cf_name;
|
||||
@@ -57,7 +54,7 @@ void EventHelpers::NotifyOnBackgroundError(
|
||||
BackgroundErrorReason reason, Status* bg_error, InstrumentedMutex* db_mutex,
|
||||
bool* auto_recovery) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.empty()) {
|
||||
if (listeners.size() == 0U) {
|
||||
return;
|
||||
}
|
||||
db_mutex->AssertHeld();
|
||||
@@ -166,7 +163,7 @@ void EventHelpers::LogAndNotifyTableFileCreationFinished(
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.empty()) {
|
||||
if (listeners.size() == 0) {
|
||||
return;
|
||||
}
|
||||
TableFileCreationInfo info;
|
||||
@@ -213,9 +210,6 @@ void EventHelpers::LogAndNotifyTableFileDeletion(
|
||||
event_logger->Log(jwriter);
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.empty()) {
|
||||
return;
|
||||
}
|
||||
TableFileDeletionInfo info;
|
||||
info.db_name = dbname;
|
||||
info.job_id = job_id;
|
||||
@@ -236,7 +230,7 @@ void EventHelpers::NotifyOnErrorRecoveryCompleted(
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
Status old_bg_error, InstrumentedMutex* db_mutex) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (!listeners.empty()) {
|
||||
if (listeners.size() > 0) {
|
||||
db_mutex->AssertHeld();
|
||||
// release lock while notifying events
|
||||
db_mutex->Unlock();
|
||||
@@ -253,98 +247,4 @@ void EventHelpers::NotifyOnErrorRecoveryCompleted(
|
||||
#endif // ROCKSDB_LITE
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
void EventHelpers::NotifyBlobFileCreationStarted(
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
const std::string& db_name, const std::string& cf_name,
|
||||
const std::string& file_path, int job_id,
|
||||
BlobFileCreationReason creation_reason) {
|
||||
if (listeners.empty()) {
|
||||
return;
|
||||
}
|
||||
BlobFileCreationBriefInfo info(db_name, cf_name, file_path, job_id,
|
||||
creation_reason);
|
||||
for (const auto& listener : listeners) {
|
||||
listener->OnBlobFileCreationStarted(info);
|
||||
}
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
void EventHelpers::LogAndNotifyBlobFileCreationFinished(
|
||||
EventLogger* event_logger,
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
const std::string& db_name, const std::string& cf_name,
|
||||
const std::string& file_path, int job_id, uint64_t file_number,
|
||||
BlobFileCreationReason creation_reason, const Status& s,
|
||||
const std::string& file_checksum,
|
||||
const std::string& file_checksum_func_name, uint64_t total_blob_count,
|
||||
uint64_t total_blob_bytes) {
|
||||
if (s.ok() && event_logger) {
|
||||
JSONWriter jwriter;
|
||||
AppendCurrentTime(&jwriter);
|
||||
jwriter << "cf_name" << cf_name << "job" << job_id << "event"
|
||||
<< "blob_file_creation"
|
||||
<< "file_number" << file_number << "total_blob_count"
|
||||
<< total_blob_count << "total_blob_bytes" << total_blob_bytes
|
||||
<< "file_checksum" << file_checksum << "file_checksum_func_name"
|
||||
<< file_checksum_func_name << "status" << s.ToString();
|
||||
|
||||
jwriter.EndObject();
|
||||
event_logger->Log(jwriter);
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.empty()) {
|
||||
return;
|
||||
}
|
||||
BlobFileCreationInfo info(db_name, cf_name, file_path, job_id,
|
||||
creation_reason, total_blob_count, total_blob_bytes,
|
||||
s, file_checksum, file_checksum_func_name);
|
||||
for (const auto& listener : listeners) {
|
||||
listener->OnBlobFileCreated(info);
|
||||
}
|
||||
info.status.PermitUncheckedError();
|
||||
#else
|
||||
(void)listeners;
|
||||
(void)db_name;
|
||||
(void)file_path;
|
||||
(void)creation_reason;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EventHelpers::LogAndNotifyBlobFileDeletion(
|
||||
EventLogger* event_logger,
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners, int job_id,
|
||||
uint64_t file_number, const std::string& file_path, const Status& status,
|
||||
const std::string& dbname) {
|
||||
if (event_logger) {
|
||||
JSONWriter jwriter;
|
||||
AppendCurrentTime(&jwriter);
|
||||
|
||||
jwriter << "job" << job_id << "event"
|
||||
<< "blob_file_deletion"
|
||||
<< "file_number" << file_number;
|
||||
if (!status.ok()) {
|
||||
jwriter << "status" << status.ToString();
|
||||
}
|
||||
|
||||
jwriter.EndObject();
|
||||
event_logger->Log(jwriter);
|
||||
}
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.empty()) {
|
||||
return;
|
||||
}
|
||||
BlobFileDeletionInfo info(dbname, file_path, job_id, status);
|
||||
for (const auto& listener : listeners) {
|
||||
listener->OnBlobFileDeleted(info);
|
||||
}
|
||||
info.status.PermitUncheckedError();
|
||||
#else
|
||||
(void)listeners;
|
||||
(void)dbname;
|
||||
(void)file_path;
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -47,30 +47,6 @@ class EventHelpers {
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
Status bg_error, InstrumentedMutex* db_mutex);
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
static void NotifyBlobFileCreationStarted(
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
const std::string& db_name, const std::string& cf_name,
|
||||
const std::string& file_path, int job_id,
|
||||
BlobFileCreationReason creation_reason);
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
static void LogAndNotifyBlobFileCreationFinished(
|
||||
EventLogger* event_logger,
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
const std::string& db_name, const std::string& cf_name,
|
||||
const std::string& file_path, int job_id, uint64_t file_number,
|
||||
BlobFileCreationReason creation_reason, const Status& s,
|
||||
const std::string& file_checksum,
|
||||
const std::string& file_checksum_func_name, uint64_t total_blob_count,
|
||||
uint64_t total_blob_bytes);
|
||||
|
||||
static void LogAndNotifyBlobFileDeletion(
|
||||
EventLogger* event_logger,
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners, int job_id,
|
||||
uint64_t file_number, const std::string& file_path, const Status& status,
|
||||
const std::string& db_name);
|
||||
|
||||
private:
|
||||
static void LogAndNotifyTableFileCreation(
|
||||
EventLogger* event_logger,
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "port/port.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/sst_file_writer.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/random.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
@@ -24,25 +23,9 @@ class ExternalSSTFileBasicTest
|
||||
public:
|
||||
ExternalSSTFileBasicTest()
|
||||
: DBTestBase("external_sst_file_basic_test", /*env_do_fsync=*/true) {
|
||||
sst_files_dir_ = dbname_ + "_sst_files/";
|
||||
sst_files_dir_ = dbname_ + "/sst_files/";
|
||||
fault_injection_test_env_.reset(new FaultInjectionTestEnv(env_));
|
||||
DestroyAndRecreateExternalSSTFilesDir();
|
||||
|
||||
// Check if the Env supports RandomRWFile
|
||||
std::string file_path = sst_files_dir_ + "test_random_rw_file";
|
||||
std::unique_ptr<WritableFile> wfile;
|
||||
assert(env_->NewWritableFile(file_path, &wfile, EnvOptions()).ok());
|
||||
wfile.reset();
|
||||
std::unique_ptr<RandomRWFile> rwfile;
|
||||
Status s = env_->NewRandomRWFile(file_path, &rwfile, EnvOptions());
|
||||
if (s.IsNotSupported()) {
|
||||
random_rwfile_supported_ = false;
|
||||
} else {
|
||||
EXPECT_OK(s);
|
||||
random_rwfile_supported_ = true;
|
||||
}
|
||||
rwfile.reset();
|
||||
EXPECT_OK(env_->DeleteFile(file_path));
|
||||
}
|
||||
|
||||
void DestroyAndRecreateExternalSSTFilesDir() {
|
||||
@@ -186,7 +169,6 @@ class ExternalSSTFileBasicTest
|
||||
protected:
|
||||
std::string sst_files_dir_;
|
||||
std::unique_ptr<FaultInjectionTestEnv> fault_injection_test_env_;
|
||||
bool random_rwfile_supported_;
|
||||
};
|
||||
|
||||
TEST_F(ExternalSSTFileBasicTest, Basic) {
|
||||
@@ -1114,31 +1096,12 @@ TEST_F(ExternalSSTFileBasicTest, SyncFailure) {
|
||||
"ExternalSstFileIngestionJob::AfterSyncGlobalSeqno"}};
|
||||
|
||||
for (size_t i = 0; i < test_cases.size(); i++) {
|
||||
bool no_sync = false;
|
||||
SyncPoint::GetInstance()->SetCallBack(test_cases[i].first, [&](void*) {
|
||||
fault_injection_test_env_->SetFilesystemActive(false);
|
||||
});
|
||||
SyncPoint::GetInstance()->SetCallBack(test_cases[i].second, [&](void*) {
|
||||
fault_injection_test_env_->SetFilesystemActive(true);
|
||||
});
|
||||
if (i == 0) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"ExternalSstFileIngestionJob::Prepare:Reopen", [&](void* s) {
|
||||
Status* status = static_cast<Status*>(s);
|
||||
if (status->IsNotSupported()) {
|
||||
no_sync = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (i == 2) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"ExternalSstFileIngestionJob::NewRandomRWFile", [&](void* s) {
|
||||
Status* status = static_cast<Status*>(s);
|
||||
if (status->IsNotSupported()) {
|
||||
no_sync = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
DestroyAndReopen(options);
|
||||
@@ -1147,7 +1110,7 @@ TEST_F(ExternalSSTFileBasicTest, SyncFailure) {
|
||||
}
|
||||
|
||||
Options sst_file_writer_options;
|
||||
sst_file_writer_options.env = fault_injection_test_env_.get();
|
||||
sst_file_writer_options.env = env_;
|
||||
std::unique_ptr<SstFileWriter> sst_file_writer(
|
||||
new SstFileWriter(EnvOptions(), sst_file_writer_options));
|
||||
std::string file_name =
|
||||
@@ -1164,12 +1127,7 @@ TEST_F(ExternalSSTFileBasicTest, SyncFailure) {
|
||||
if (i == 2) {
|
||||
ingest_opt.write_global_seqno = true;
|
||||
}
|
||||
Status s = db_->IngestExternalFile({file_name}, ingest_opt);
|
||||
if (no_sync) {
|
||||
ASSERT_OK(s);
|
||||
} else {
|
||||
ASSERT_NOK(s);
|
||||
}
|
||||
ASSERT_NOK(db_->IngestExternalFile({file_name}, ingest_opt));
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
@@ -1472,10 +1430,6 @@ TEST_P(ExternalSSTFileBasicTest, IngestFileWithBadBlockChecksum) {
|
||||
}
|
||||
|
||||
TEST_P(ExternalSSTFileBasicTest, IngestFileWithFirstByteTampered) {
|
||||
if (!random_rwfile_supported_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires NewRandomRWFile support");
|
||||
return;
|
||||
}
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
int file_id = 0;
|
||||
EnvOptions env_options;
|
||||
@@ -1525,11 +1479,6 @@ TEST_P(ExternalSSTFileBasicTest, IngestFileWithFirstByteTampered) {
|
||||
TEST_P(ExternalSSTFileBasicTest, IngestExternalFileWithCorruptedPropsBlock) {
|
||||
bool verify_checksums_before_ingest = std::get<1>(GetParam());
|
||||
if (!verify_checksums_before_ingest) {
|
||||
ROCKSDB_GTEST_BYPASS("Bypassing test when !verify_checksums_before_ingest");
|
||||
return;
|
||||
}
|
||||
if (!random_rwfile_supported_) {
|
||||
ROCKSDB_GTEST_SKIP("Test requires NewRandomRWFile support");
|
||||
return;
|
||||
}
|
||||
uint64_t props_block_offset = 0;
|
||||
@@ -1676,17 +1625,8 @@ INSTANTIATE_TEST_CASE_P(ExternalSSTFileBasicTest, ExternalSSTFileBasicTest,
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
extern "C" {
|
||||
void RegisterCustomObjects(int argc, char** argv);
|
||||
}
|
||||
#else
|
||||
void RegisterCustomObjects(int /*argc*/, char** /*argv*/) {}
|
||||
#endif // ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -842,8 +842,6 @@ Status ExternalSstFileIngestionJob::AssignGlobalSeqnoForIngestedFile(
|
||||
Status status =
|
||||
fs_->NewRandomRWFile(file_to_ingest->internal_file_path, env_options_,
|
||||
&rwfile, nullptr);
|
||||
TEST_SYNC_POINT_CALLBACK("ExternalSstFileIngestionJob::NewRandomRWFile",
|
||||
&status);
|
||||
if (status.ok()) {
|
||||
FSRandomRWFilePtr fsptr(std::move(rwfile), io_tracer_,
|
||||
file_to_ingest->internal_file_path);
|
||||
|
||||
@@ -139,7 +139,7 @@ class ExternalSstFileIngestionJob {
|
||||
IngestedFileInfo* file_to_ingest,
|
||||
SuperVersion* sv);
|
||||
|
||||
// Assign `file_to_ingest` the appropriate sequence number and the lowest
|
||||
// Assign `file_to_ingest` the appropriate sequence number and the lowest
|
||||
// possible level that it can be ingested to according to compaction_style.
|
||||
// REQUIRES: Mutex held
|
||||
Status AssignLevelAndSeqnoForIngestedFile(SuperVersion* sv,
|
||||
|
||||
@@ -2421,12 +2421,6 @@ TEST_P(ExternalSSTFileTest, IngestFilesIntoMultipleColumnFamilies_Success) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = fault_injection_env.get();
|
||||
CreateAndReopenWithCF({"pikachu", "eevee"}, options);
|
||||
|
||||
// Exercise different situations in different column families: two are empty
|
||||
// (so no new sequence number is needed), but at least one overlaps with the
|
||||
// DB and needs to bump the sequence number.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "foo1", "oldvalue"));
|
||||
|
||||
std::vector<ColumnFamilyHandle*> column_families;
|
||||
column_families.push_back(handles_[0]);
|
||||
column_families.push_back(handles_[1]);
|
||||
|
||||
+3
-17
@@ -900,10 +900,9 @@ Status FlushJob::WriteLevel0Table() {
|
||||
&blob_file_additions, existing_snapshots_,
|
||||
earliest_write_conflict_snapshot_, snapshot_checker_,
|
||||
mutable_cf_options_.paranoid_file_checks, cfd_->internal_stats(),
|
||||
&io_s, io_tracer_, BlobFileCreationReason::kFlush, event_logger_,
|
||||
job_context_->job_id, Env::IO_HIGH, &table_properties_, write_hint,
|
||||
full_history_ts_low, blob_callback_, &num_input_entries,
|
||||
&memtable_payload_bytes, &memtable_garbage_bytes);
|
||||
&io_s, io_tracer_, event_logger_, job_context_->job_id, Env::IO_HIGH,
|
||||
&table_properties_, write_hint, full_history_ts_low, blob_callback_,
|
||||
&num_input_entries, &memtable_payload_bytes, &memtable_garbage_bytes);
|
||||
if (!io_s.ok()) {
|
||||
io_status_ = io_s;
|
||||
}
|
||||
@@ -1022,21 +1021,8 @@ std::unique_ptr<FlushJobInfo> FlushJob::GetFlushJobInfo() const {
|
||||
info->largest_seqno = meta_.fd.largest_seqno;
|
||||
info->table_properties = table_properties_;
|
||||
info->flush_reason = cfd_->GetFlushReason();
|
||||
info->blob_compression_type = mutable_cf_options_.blob_compression_type;
|
||||
|
||||
// Update BlobFilesInfo.
|
||||
for (const auto& blob_file : edit_->GetBlobFileAdditions()) {
|
||||
BlobFileAdditionInfo blob_file_addition_info(
|
||||
BlobFileName(cfd_->ioptions()->cf_paths.front().path,
|
||||
blob_file.GetBlobFileNumber()) /*blob_file_path*/,
|
||||
blob_file.GetBlobFileNumber(), blob_file.GetTotalBlobCount(),
|
||||
blob_file.GetTotalBlobBytes());
|
||||
info->blob_file_addition_infos.emplace_back(
|
||||
std::move(blob_file_addition_info));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -39,9 +39,8 @@ class MinIterComparator {
|
||||
const Comparator* comparator_;
|
||||
};
|
||||
|
||||
using MinIterHeap =
|
||||
std::priority_queue<InternalIterator*, std::vector<InternalIterator*>,
|
||||
MinIterComparator>;
|
||||
typedef std::priority_queue<InternalIterator*, std::vector<InternalIterator*>,
|
||||
MinIterComparator> MinIterHeap;
|
||||
|
||||
/**
|
||||
* ForwardIterator is a special type of iterator that only supports Seek()
|
||||
|
||||
+1
-66
@@ -23,7 +23,6 @@
|
||||
#include "cache/cache_entry_stats.h"
|
||||
#include "db/column_family.h"
|
||||
#include "db/db_impl/db_impl.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/system_clock.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "table/block_based/cachable_entry.h"
|
||||
@@ -281,10 +280,6 @@ static const std::string block_cache_capacity = "block-cache-capacity";
|
||||
static const std::string block_cache_usage = "block-cache-usage";
|
||||
static const std::string block_cache_pinned_usage = "block-cache-pinned-usage";
|
||||
static const std::string options_statistics = "options-statistics";
|
||||
static const std::string num_blob_files = "num-blob-files";
|
||||
static const std::string blob_stats = "blob-stats";
|
||||
static const std::string total_blob_file_size = "total-blob-file-size";
|
||||
static const std::string live_blob_file_size = "live-blob-file-size";
|
||||
|
||||
const std::string DB::Properties::kNumFilesAtLevelPrefix =
|
||||
rocksdb_prefix + num_files_at_level_prefix;
|
||||
@@ -378,13 +373,6 @@ const std::string DB::Properties::kOptionsStatistics =
|
||||
rocksdb_prefix + options_statistics;
|
||||
const std::string DB::Properties::kLiveSstFilesSizeAtTemperature =
|
||||
rocksdb_prefix + live_sst_files_size_at_temperature;
|
||||
const std::string DB::Properties::kNumBlobFiles =
|
||||
rocksdb_prefix + num_blob_files;
|
||||
const std::string DB::Properties::kBlobStats = rocksdb_prefix + blob_stats;
|
||||
const std::string DB::Properties::kTotalBlobFileSize =
|
||||
rocksdb_prefix + total_blob_file_size;
|
||||
const std::string DB::Properties::kLiveBlobFileSize =
|
||||
rocksdb_prefix + live_blob_file_size;
|
||||
|
||||
const std::unordered_map<std::string, DBPropertyInfo>
|
||||
InternalStats::ppt_name_to_info = {
|
||||
@@ -531,17 +519,6 @@ const std::unordered_map<std::string, DBPropertyInfo>
|
||||
{DB::Properties::kOptionsStatistics,
|
||||
{true, nullptr, nullptr, nullptr,
|
||||
&DBImpl::GetPropertyHandleOptionsStatistics}},
|
||||
{DB::Properties::kNumBlobFiles,
|
||||
{false, nullptr, &InternalStats::HandleNumBlobFiles, nullptr,
|
||||
nullptr}},
|
||||
{DB::Properties::kBlobStats,
|
||||
{false, &InternalStats::HandleBlobStats, nullptr, nullptr, nullptr}},
|
||||
{DB::Properties::kTotalBlobFileSize,
|
||||
{false, nullptr, &InternalStats::HandleTotalBlobFileSize, nullptr,
|
||||
nullptr}},
|
||||
{DB::Properties::kLiveBlobFileSize,
|
||||
{false, nullptr, &InternalStats::HandleLiveBlobFileSize, nullptr,
|
||||
nullptr}},
|
||||
};
|
||||
|
||||
InternalStats::InternalStats(int num_levels, SystemClock* clock,
|
||||
@@ -625,8 +602,7 @@ void InternalStats::CacheEntryRoleStats::BeginCollection(
|
||||
++collection_count;
|
||||
role_map_ = CopyCacheDeleterRoleMap();
|
||||
std::ostringstream str;
|
||||
str << cache->Name() << "@" << static_cast<void*>(cache) << "#"
|
||||
<< port::GetProcessID();
|
||||
str << cache->Name() << "@" << static_cast<void*>(cache);
|
||||
cache_id = str.str();
|
||||
cache_capacity = cache->GetCapacity();
|
||||
}
|
||||
@@ -735,47 +711,6 @@ bool InternalStats::HandleLiveSstFilesSizeAtTemperature(std::string* value,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalStats::HandleNumBlobFiles(uint64_t* value, DBImpl* /*db*/,
|
||||
Version* /*version*/) {
|
||||
const auto* vstorage = cfd_->current()->storage_info();
|
||||
const auto& blob_files = vstorage->GetBlobFiles();
|
||||
*value = blob_files.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalStats::HandleBlobStats(std::string* value, Slice /*suffix*/) {
|
||||
std::ostringstream oss;
|
||||
auto* current_version = cfd_->current();
|
||||
const auto& blob_files = current_version->storage_info()->GetBlobFiles();
|
||||
uint64_t current_num_blob_files = blob_files.size();
|
||||
uint64_t current_file_size = 0;
|
||||
uint64_t current_garbage_size = 0;
|
||||
for (const auto& pair : blob_files) {
|
||||
const auto& meta = pair.second;
|
||||
current_file_size += meta->GetBlobFileSize();
|
||||
current_garbage_size += meta->GetGarbageBlobBytes();
|
||||
}
|
||||
oss << "Number of blob files: " << current_num_blob_files
|
||||
<< "\nTotal size of blob files: " << current_file_size
|
||||
<< "\nTotal size of garbage in blob files: " << current_garbage_size
|
||||
<< '\n';
|
||||
value->append(oss.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalStats::HandleTotalBlobFileSize(uint64_t* value, DBImpl* /*db*/,
|
||||
Version* /*version*/) {
|
||||
*value = cfd_->GetTotalBlobFileSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalStats::HandleLiveBlobFileSize(uint64_t* value, DBImpl* /*db*/,
|
||||
Version* /*version*/) {
|
||||
const auto* vstorage = cfd_->current()->storage_info();
|
||||
*value = vstorage->GetTotalBlobFileSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
const DBPropertyInfo* GetPropertyInfo(const Slice& property) {
|
||||
std::string ppt_name = GetPropertyNameAndArg(property).first.ToString();
|
||||
auto ppt_info_iter = InternalStats::ppt_name_to_info.find(ppt_name);
|
||||
|
||||
@@ -676,10 +676,6 @@ class InternalStats {
|
||||
bool HandleBlockCacheEntryStatsMap(std::map<std::string, std::string>* values,
|
||||
Slice suffix);
|
||||
bool HandleLiveSstFilesSizeAtTemperature(std::string* value, Slice suffix);
|
||||
bool HandleNumBlobFiles(uint64_t* value, DBImpl* db, Version* version);
|
||||
bool HandleBlobStats(std::string* value, Slice suffix);
|
||||
bool HandleTotalBlobFileSize(uint64_t* value, DBImpl* db, Version* version);
|
||||
bool HandleLiveBlobFileSize(uint64_t* value, DBImpl* db, Version* version);
|
||||
// Total number of background errors encountered. Every time a flush task
|
||||
// or compaction task fails, this counter is incremented. The failure can
|
||||
// be caused by any possible reason, including file system errors, out of
|
||||
|
||||
+2
-3
@@ -12,9 +12,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "db/column_family.h"
|
||||
#include "db/log_writer.h"
|
||||
#include "db/version_set.h"
|
||||
#include "db/column_family.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -118,7 +117,7 @@ struct JobContext {
|
||||
}
|
||||
}
|
||||
return memtables_to_free.size() > 0 || logs_to_free.size() > 0 ||
|
||||
job_snapshot != nullptr || sv_have_sth;
|
||||
sv_have_sth;
|
||||
}
|
||||
|
||||
// Structure to store information for candidate files to delete.
|
||||
|
||||
+124
-94
@@ -11,12 +11,13 @@
|
||||
// K = key
|
||||
// V = value
|
||||
// O = optype aka value type
|
||||
// T = timestamp
|
||||
// S = seqno
|
||||
// C = CF ID
|
||||
//
|
||||
// Then, for example, a class that protects an entry consisting of key, value,
|
||||
// optype, and CF ID (i.e., a `WriteBatch` entry) would be named
|
||||
// `ProtectionInfoKVOC`.
|
||||
// optype, timestamp, and CF ID (i.e., a `WriteBatch` entry) would be named
|
||||
// `ProtectionInfoKVOTC`.
|
||||
//
|
||||
// The `ProtectionInfo.*` classes are templated on the integer type used to hold
|
||||
// the XOR of hashes for each field. Only unsigned integer types are supported,
|
||||
@@ -41,17 +42,17 @@ namespace ROCKSDB_NAMESPACE {
|
||||
template <typename T>
|
||||
class ProtectionInfo;
|
||||
template <typename T>
|
||||
class ProtectionInfoKVO;
|
||||
class ProtectionInfoKVOT;
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOC;
|
||||
class ProtectionInfoKVOTC;
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOS;
|
||||
class ProtectionInfoKVOTS;
|
||||
|
||||
// Aliases for 64-bit protection infos.
|
||||
using ProtectionInfo64 = ProtectionInfo<uint64_t>;
|
||||
using ProtectionInfoKVO64 = ProtectionInfoKVO<uint64_t>;
|
||||
using ProtectionInfoKVOC64 = ProtectionInfoKVOC<uint64_t>;
|
||||
using ProtectionInfoKVOS64 = ProtectionInfoKVOS<uint64_t>;
|
||||
typedef ProtectionInfo<uint64_t> ProtectionInfo64;
|
||||
typedef ProtectionInfoKVOT<uint64_t> ProtectionInfoKVOT64;
|
||||
typedef ProtectionInfoKVOTC<uint64_t> ProtectionInfoKVOTC64;
|
||||
typedef ProtectionInfoKVOTS<uint64_t> ProtectionInfoKVOTS64;
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfo {
|
||||
@@ -59,16 +60,17 @@ class ProtectionInfo {
|
||||
ProtectionInfo<T>() = default;
|
||||
|
||||
Status GetStatus() const;
|
||||
ProtectionInfoKVO<T> ProtectKVO(const Slice& key, const Slice& value,
|
||||
ValueType op_type) const;
|
||||
ProtectionInfoKVO<T> ProtectKVO(const SliceParts& key,
|
||||
const SliceParts& value,
|
||||
ValueType op_type) const;
|
||||
ProtectionInfoKVOT<T> ProtectKVOT(const Slice& key, const Slice& value,
|
||||
ValueType op_type,
|
||||
const Slice& timestamp) const;
|
||||
ProtectionInfoKVOT<T> ProtectKVOT(const SliceParts& key,
|
||||
const SliceParts& value, ValueType op_type,
|
||||
const Slice& timestamp) const;
|
||||
|
||||
private:
|
||||
friend class ProtectionInfoKVO<T>;
|
||||
friend class ProtectionInfoKVOS<T>;
|
||||
friend class ProtectionInfoKVOC<T>;
|
||||
friend class ProtectionInfoKVOT<T>;
|
||||
friend class ProtectionInfoKVOTS<T>;
|
||||
friend class ProtectionInfoKVOTC<T>;
|
||||
|
||||
// Each field is hashed with an independent value so we can catch fields being
|
||||
// swapped. Per the `NPHash64()` docs, using consecutive seeds is a pitfall,
|
||||
@@ -80,8 +82,9 @@ class ProtectionInfo {
|
||||
static const uint64_t kSeedK = 0;
|
||||
static const uint64_t kSeedV = 0xD28AAD72F49BD50B;
|
||||
static const uint64_t kSeedO = 0xA5155AE5E937AA16;
|
||||
static const uint64_t kSeedS = 0x77A00858DDD37F21;
|
||||
static const uint64_t kSeedC = 0x4A2AB5CBD26F542C;
|
||||
static const uint64_t kSeedT = 0x77A00858DDD37F21;
|
||||
static const uint64_t kSeedS = 0x4A2AB5CBD26F542C;
|
||||
static const uint64_t kSeedC = 0x1CB5633EC70B2937;
|
||||
|
||||
ProtectionInfo<T>(T val) : val_(val) {
|
||||
static_assert(sizeof(ProtectionInfo<T>) == sizeof(T), "");
|
||||
@@ -94,31 +97,32 @@ class ProtectionInfo {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfoKVO {
|
||||
class ProtectionInfoKVOT {
|
||||
public:
|
||||
ProtectionInfoKVO<T>() = default;
|
||||
ProtectionInfoKVOT<T>() = default;
|
||||
|
||||
ProtectionInfo<T> StripKVO(const Slice& key, const Slice& value,
|
||||
ValueType op_type) const;
|
||||
ProtectionInfo<T> StripKVO(const SliceParts& key, const SliceParts& value,
|
||||
ValueType op_type) const;
|
||||
ProtectionInfo<T> StripKVOT(const Slice& key, const Slice& value,
|
||||
ValueType op_type, const Slice& timestamp) const;
|
||||
ProtectionInfo<T> StripKVOT(const SliceParts& key, const SliceParts& value,
|
||||
ValueType op_type, const Slice& timestamp) const;
|
||||
|
||||
ProtectionInfoKVOC<T> ProtectC(ColumnFamilyId column_family_id) const;
|
||||
ProtectionInfoKVOS<T> ProtectS(SequenceNumber sequence_number) const;
|
||||
ProtectionInfoKVOTC<T> ProtectC(ColumnFamilyId column_family_id) const;
|
||||
ProtectionInfoKVOTS<T> ProtectS(SequenceNumber sequence_number) const;
|
||||
|
||||
void UpdateK(const Slice& old_key, const Slice& new_key);
|
||||
void UpdateK(const SliceParts& old_key, const SliceParts& new_key);
|
||||
void UpdateV(const Slice& old_value, const Slice& new_value);
|
||||
void UpdateV(const SliceParts& old_value, const SliceParts& new_value);
|
||||
void UpdateO(ValueType old_op_type, ValueType new_op_type);
|
||||
void UpdateT(const Slice& old_timestamp, const Slice& new_timestamp);
|
||||
|
||||
private:
|
||||
friend class ProtectionInfo<T>;
|
||||
friend class ProtectionInfoKVOS<T>;
|
||||
friend class ProtectionInfoKVOC<T>;
|
||||
friend class ProtectionInfoKVOTS<T>;
|
||||
friend class ProtectionInfoKVOTC<T>;
|
||||
|
||||
ProtectionInfoKVO<T>(T val) : info_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVO<T>) == sizeof(T), "");
|
||||
ProtectionInfoKVOT<T>(T val) : info_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOT<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return info_.GetVal(); }
|
||||
@@ -128,79 +132,85 @@ class ProtectionInfoKVO {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOC {
|
||||
class ProtectionInfoKVOTC {
|
||||
public:
|
||||
ProtectionInfoKVOC<T>() = default;
|
||||
ProtectionInfoKVOTC<T>() = default;
|
||||
|
||||
ProtectionInfoKVO<T> StripC(ColumnFamilyId column_family_id) const;
|
||||
ProtectionInfoKVOT<T> StripC(ColumnFamilyId column_family_id) const;
|
||||
|
||||
void UpdateK(const Slice& old_key, const Slice& new_key) {
|
||||
kvo_.UpdateK(old_key, new_key);
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
|
||||
kvo_.UpdateK(old_key, new_key);
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateV(const Slice& old_value, const Slice& new_value) {
|
||||
kvo_.UpdateV(old_value, new_value);
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
|
||||
kvo_.UpdateV(old_value, new_value);
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateO(ValueType old_op_type, ValueType new_op_type) {
|
||||
kvo_.UpdateO(old_op_type, new_op_type);
|
||||
kvot_.UpdateO(old_op_type, new_op_type);
|
||||
}
|
||||
void UpdateT(const Slice& old_timestamp, const Slice& new_timestamp) {
|
||||
kvot_.UpdateT(old_timestamp, new_timestamp);
|
||||
}
|
||||
void UpdateC(ColumnFamilyId old_column_family_id,
|
||||
ColumnFamilyId new_column_family_id);
|
||||
|
||||
private:
|
||||
friend class ProtectionInfoKVO<T>;
|
||||
friend class ProtectionInfoKVOT<T>;
|
||||
|
||||
ProtectionInfoKVOC<T>(T val) : kvo_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOC<T>) == sizeof(T), "");
|
||||
ProtectionInfoKVOTC<T>(T val) : kvot_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOTC<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return kvo_.GetVal(); }
|
||||
void SetVal(T val) { kvo_.SetVal(val); }
|
||||
T GetVal() const { return kvot_.GetVal(); }
|
||||
void SetVal(T val) { kvot_.SetVal(val); }
|
||||
|
||||
ProtectionInfoKVO<T> kvo_;
|
||||
ProtectionInfoKVOT<T> kvot_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ProtectionInfoKVOS {
|
||||
class ProtectionInfoKVOTS {
|
||||
public:
|
||||
ProtectionInfoKVOS<T>() = default;
|
||||
ProtectionInfoKVOTS<T>() = default;
|
||||
|
||||
ProtectionInfoKVO<T> StripS(SequenceNumber sequence_number) const;
|
||||
ProtectionInfoKVOT<T> StripS(SequenceNumber sequence_number) const;
|
||||
|
||||
void UpdateK(const Slice& old_key, const Slice& new_key) {
|
||||
kvo_.UpdateK(old_key, new_key);
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
|
||||
kvo_.UpdateK(old_key, new_key);
|
||||
kvot_.UpdateK(old_key, new_key);
|
||||
}
|
||||
void UpdateV(const Slice& old_value, const Slice& new_value) {
|
||||
kvo_.UpdateV(old_value, new_value);
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
|
||||
kvo_.UpdateV(old_value, new_value);
|
||||
kvot_.UpdateV(old_value, new_value);
|
||||
}
|
||||
void UpdateO(ValueType old_op_type, ValueType new_op_type) {
|
||||
kvo_.UpdateO(old_op_type, new_op_type);
|
||||
kvot_.UpdateO(old_op_type, new_op_type);
|
||||
}
|
||||
void UpdateT(const Slice& old_timestamp, const Slice& new_timestamp) {
|
||||
kvot_.UpdateT(old_timestamp, new_timestamp);
|
||||
}
|
||||
void UpdateS(SequenceNumber old_sequence_number,
|
||||
SequenceNumber new_sequence_number);
|
||||
|
||||
private:
|
||||
friend class ProtectionInfoKVO<T>;
|
||||
friend class ProtectionInfoKVOT<T>;
|
||||
|
||||
ProtectionInfoKVOS<T>(T val) : kvo_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOS<T>) == sizeof(T), "");
|
||||
ProtectionInfoKVOTS<T>(T val) : kvot_(val) {
|
||||
static_assert(sizeof(ProtectionInfoKVOTS<T>) == sizeof(T), "");
|
||||
}
|
||||
|
||||
T GetVal() const { return kvo_.GetVal(); }
|
||||
void SetVal(T val) { kvo_.SetVal(val); }
|
||||
T GetVal() const { return kvot_.GetVal(); }
|
||||
void SetVal(T val) { kvot_.SetVal(val); }
|
||||
|
||||
ProtectionInfoKVO<T> kvo_;
|
||||
ProtectionInfoKVOT<T> kvot_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -212,9 +222,9 @@ Status ProtectionInfo<T>::GetStatus() const {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const Slice& key,
|
||||
const Slice& value,
|
||||
ValueType op_type) const {
|
||||
ProtectionInfoKVOT<T> ProtectionInfo<T>::ProtectKVOT(
|
||||
const Slice& key, const Slice& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
val =
|
||||
@@ -222,13 +232,15 @@ ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const Slice& key,
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
return ProtectionInfoKVO<T>(val);
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const SliceParts& key,
|
||||
const SliceParts& value,
|
||||
ValueType op_type) const {
|
||||
ProtectionInfoKVOT<T> ProtectionInfo<T>::ProtectKVOT(
|
||||
const SliceParts& key, const SliceParts& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
@@ -237,11 +249,14 @@ ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const SliceParts& key,
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
return ProtectionInfoKVO<T>(val);
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVO<T>::UpdateK(const Slice& old_key, const Slice& new_key) {
|
||||
void ProtectionInfoKVOT<T>::UpdateK(const Slice& old_key,
|
||||
const Slice& new_key) {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(old_key, ProtectionInfo<T>::kSeedK));
|
||||
@@ -251,8 +266,8 @@ void ProtectionInfoKVO<T>::UpdateK(const Slice& old_key, const Slice& new_key) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVO<T>::UpdateK(const SliceParts& old_key,
|
||||
const SliceParts& new_key) {
|
||||
void ProtectionInfoKVOT<T>::UpdateK(const SliceParts& old_key,
|
||||
const SliceParts& new_key) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(
|
||||
GetSlicePartsNPHash64(old_key, ProtectionInfo<T>::kSeedK));
|
||||
@@ -262,8 +277,8 @@ void ProtectionInfoKVO<T>::UpdateK(const SliceParts& old_key,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVO<T>::UpdateV(const Slice& old_value,
|
||||
const Slice& new_value) {
|
||||
void ProtectionInfoKVOT<T>::UpdateV(const Slice& old_value,
|
||||
const Slice& new_value) {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(old_value, ProtectionInfo<T>::kSeedV));
|
||||
@@ -273,8 +288,8 @@ void ProtectionInfoKVO<T>::UpdateV(const Slice& old_value,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVO<T>::UpdateV(const SliceParts& old_value,
|
||||
const SliceParts& new_value) {
|
||||
void ProtectionInfoKVOT<T>::UpdateV(const SliceParts& old_value,
|
||||
const SliceParts& new_value) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(
|
||||
GetSlicePartsNPHash64(old_value, ProtectionInfo<T>::kSeedV));
|
||||
@@ -284,8 +299,8 @@ void ProtectionInfoKVO<T>::UpdateV(const SliceParts& old_value,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVO<T>::UpdateO(ValueType old_op_type,
|
||||
ValueType new_op_type) {
|
||||
void ProtectionInfoKVOT<T>::UpdateO(ValueType old_op_type,
|
||||
ValueType new_op_type) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&old_op_type),
|
||||
sizeof(old_op_type),
|
||||
@@ -297,9 +312,20 @@ void ProtectionInfoKVO<T>::UpdateO(ValueType old_op_type,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const Slice& key,
|
||||
const Slice& value,
|
||||
ValueType op_type) const {
|
||||
void ProtectionInfoKVOT<T>::UpdateT(const Slice& old_timestamp,
|
||||
const Slice& new_timestamp) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(
|
||||
GetSliceNPHash64(old_timestamp, ProtectionInfo<T>::kSeedT));
|
||||
val = val ^ static_cast<T>(
|
||||
GetSliceNPHash64(new_timestamp, ProtectionInfo<T>::kSeedT));
|
||||
SetVal(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfo<T> ProtectionInfoKVOT<T>::StripKVOT(
|
||||
const Slice& key, const Slice& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
val =
|
||||
@@ -307,13 +333,15 @@ ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const Slice& key,
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfo<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const SliceParts& key,
|
||||
const SliceParts& value,
|
||||
ValueType op_type) const {
|
||||
ProtectionInfo<T> ProtectionInfoKVOT<T>::StripKVOT(
|
||||
const SliceParts& key, const SliceParts& value, ValueType op_type,
|
||||
const Slice& timestamp) const {
|
||||
T val = GetVal();
|
||||
val = val ^
|
||||
static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
|
||||
@@ -322,32 +350,34 @@ ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const SliceParts& key,
|
||||
val = val ^
|
||||
static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
|
||||
sizeof(op_type), ProtectionInfo<T>::kSeedO));
|
||||
val = val ^
|
||||
static_cast<T>(GetSliceNPHash64(timestamp, ProtectionInfo<T>::kSeedT));
|
||||
return ProtectionInfo<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOC<T> ProtectionInfoKVO<T>::ProtectC(
|
||||
ProtectionInfoKVOTC<T> ProtectionInfoKVOT<T>::ProtectC(
|
||||
ColumnFamilyId column_family_id) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&column_family_id),
|
||||
sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
|
||||
return ProtectionInfoKVOC<T>(val);
|
||||
return ProtectionInfoKVOTC<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVO<T> ProtectionInfoKVOC<T>::StripC(
|
||||
ProtectionInfoKVOT<T> ProtectionInfoKVOTC<T>::StripC(
|
||||
ColumnFamilyId column_family_id) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&column_family_id),
|
||||
sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
|
||||
return ProtectionInfoKVO<T>(val);
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOC<T>::UpdateC(ColumnFamilyId old_column_family_id,
|
||||
ColumnFamilyId new_column_family_id) {
|
||||
void ProtectionInfoKVOTC<T>::UpdateC(ColumnFamilyId old_column_family_id,
|
||||
ColumnFamilyId new_column_family_id) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&old_column_family_id),
|
||||
@@ -359,28 +389,28 @@ void ProtectionInfoKVOC<T>::UpdateC(ColumnFamilyId old_column_family_id,
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVOS<T> ProtectionInfoKVO<T>::ProtectS(
|
||||
ProtectionInfoKVOTS<T> ProtectionInfoKVOT<T>::ProtectS(
|
||||
SequenceNumber sequence_number) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
|
||||
sizeof(sequence_number),
|
||||
ProtectionInfo<T>::kSeedS));
|
||||
return ProtectionInfoKVOS<T>(val);
|
||||
return ProtectionInfoKVOTS<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ProtectionInfoKVO<T> ProtectionInfoKVOS<T>::StripS(
|
||||
ProtectionInfoKVOT<T> ProtectionInfoKVOTS<T>::StripS(
|
||||
SequenceNumber sequence_number) const {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
|
||||
sizeof(sequence_number),
|
||||
ProtectionInfo<T>::kSeedS));
|
||||
return ProtectionInfoKVO<T>(val);
|
||||
return ProtectionInfoKVOT<T>(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ProtectionInfoKVOS<T>::UpdateS(SequenceNumber old_sequence_number,
|
||||
SequenceNumber new_sequence_number) {
|
||||
void ProtectionInfoKVOTS<T>::UpdateS(SequenceNumber old_sequence_number,
|
||||
SequenceNumber new_sequence_number) {
|
||||
T val = GetVal();
|
||||
val = val ^ static_cast<T>(NPHash64(
|
||||
reinterpret_cast<char*>(&old_sequence_number),
|
||||
|
||||
+9
-411
@@ -10,6 +10,7 @@
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "file/filename.h"
|
||||
#include "memtable/hash_linklist_rep.h"
|
||||
#include "monitoring/statistics.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
@@ -528,8 +529,8 @@ TEST_F(EventListenerTest, CompactionReasonLevel) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.create_if_missing = true;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(
|
||||
DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
|
||||
TestCompactionReasonListener* listener = new TestCompactionReasonListener();
|
||||
options.listeners.emplace_back(listener);
|
||||
@@ -594,8 +595,8 @@ TEST_F(EventListenerTest, CompactionReasonUniversal) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.create_if_missing = true;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(
|
||||
DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
|
||||
TestCompactionReasonListener* listener = new TestCompactionReasonListener();
|
||||
options.listeners.emplace_back(listener);
|
||||
@@ -656,8 +657,8 @@ TEST_F(EventListenerTest, CompactionReasonFIFO) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.create_if_missing = true;
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(
|
||||
DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
|
||||
TestCompactionReasonListener* listener = new TestCompactionReasonListener();
|
||||
options.listeners.emplace_back(listener);
|
||||
@@ -924,7 +925,7 @@ TEST_F(EventListenerTest, BackgroundErrorListenerFailedFlushTest) {
|
||||
options.create_if_missing = true;
|
||||
options.env = env_;
|
||||
options.listeners.push_back(listener);
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(1));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(1));
|
||||
options.paranoid_checks = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
@@ -955,7 +956,7 @@ TEST_F(EventListenerTest, BackgroundErrorListenerFailedCompactionTest) {
|
||||
options.env = env_;
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.listeners.push_back(listener);
|
||||
options.memtable_factory.reset(test::NewSpecialSkipListFactory(2));
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(2));
|
||||
options.paranoid_checks = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
@@ -1000,12 +1001,6 @@ class TestFileOperationListener : public EventListener {
|
||||
file_syncs_success_.store(0);
|
||||
file_truncates_.store(0);
|
||||
file_truncates_success_.store(0);
|
||||
blob_file_reads_.store(0);
|
||||
blob_file_writes_.store(0);
|
||||
blob_file_flushes_.store(0);
|
||||
blob_file_closes_.store(0);
|
||||
blob_file_syncs_.store(0);
|
||||
blob_file_truncates_.store(0);
|
||||
}
|
||||
|
||||
void OnFileReadFinish(const FileOperationInfo& info) override {
|
||||
@@ -1013,9 +1008,6 @@ class TestFileOperationListener : public EventListener {
|
||||
if (info.status.ok()) {
|
||||
++file_reads_success_;
|
||||
}
|
||||
if (EndsWith(info.path, ".blob")) {
|
||||
++blob_file_reads_;
|
||||
}
|
||||
ReportDuration(info);
|
||||
}
|
||||
|
||||
@@ -1024,9 +1016,6 @@ class TestFileOperationListener : public EventListener {
|
||||
if (info.status.ok()) {
|
||||
++file_writes_success_;
|
||||
}
|
||||
if (EndsWith(info.path, ".blob")) {
|
||||
++blob_file_writes_;
|
||||
}
|
||||
ReportDuration(info);
|
||||
}
|
||||
|
||||
@@ -1035,9 +1024,6 @@ class TestFileOperationListener : public EventListener {
|
||||
if (info.status.ok()) {
|
||||
++file_flushes_success_;
|
||||
}
|
||||
if (EndsWith(info.path, ".blob")) {
|
||||
++blob_file_flushes_;
|
||||
}
|
||||
ReportDuration(info);
|
||||
}
|
||||
|
||||
@@ -1046,9 +1032,6 @@ class TestFileOperationListener : public EventListener {
|
||||
if (info.status.ok()) {
|
||||
++file_closes_success_;
|
||||
}
|
||||
if (EndsWith(info.path, ".blob")) {
|
||||
++blob_file_closes_;
|
||||
}
|
||||
ReportDuration(info);
|
||||
}
|
||||
|
||||
@@ -1057,9 +1040,6 @@ class TestFileOperationListener : public EventListener {
|
||||
if (info.status.ok()) {
|
||||
++file_syncs_success_;
|
||||
}
|
||||
if (EndsWith(info.path, ".blob")) {
|
||||
++blob_file_syncs_;
|
||||
}
|
||||
ReportDuration(info);
|
||||
}
|
||||
|
||||
@@ -1068,9 +1048,6 @@ class TestFileOperationListener : public EventListener {
|
||||
if (info.status.ok()) {
|
||||
++file_truncates_success_;
|
||||
}
|
||||
if (EndsWith(info.path, ".blob")) {
|
||||
++blob_file_truncates_;
|
||||
}
|
||||
ReportDuration(info);
|
||||
}
|
||||
|
||||
@@ -1088,12 +1065,6 @@ class TestFileOperationListener : public EventListener {
|
||||
std::atomic<size_t> file_syncs_success_;
|
||||
std::atomic<size_t> file_truncates_;
|
||||
std::atomic<size_t> file_truncates_success_;
|
||||
std::atomic<size_t> blob_file_reads_;
|
||||
std::atomic<size_t> blob_file_writes_;
|
||||
std::atomic<size_t> blob_file_flushes_;
|
||||
std::atomic<size_t> blob_file_closes_;
|
||||
std::atomic<size_t> blob_file_syncs_;
|
||||
std::atomic<size_t> blob_file_truncates_;
|
||||
|
||||
private:
|
||||
void ReportDuration(const FileOperationInfo& info) const {
|
||||
@@ -1143,379 +1114,6 @@ TEST_F(EventListenerTest, OnFileOperationTest) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EventListenerTest, OnBlobFileOperationTest) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.create_if_missing = true;
|
||||
TestFileOperationListener* listener = new TestFileOperationListener();
|
||||
options.listeners.emplace_back(listener);
|
||||
options.disable_auto_compactions = true;
|
||||
options.enable_blob_files = true;
|
||||
options.min_blob_size = 0;
|
||||
options.enable_blob_garbage_collection = true;
|
||||
options.blob_garbage_collection_age_cutoff = 0.5;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("Key1", "blob_value1"));
|
||||
ASSERT_OK(Put("Key2", "blob_value2"));
|
||||
ASSERT_OK(Put("Key3", "blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key3", "new_blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "new_blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key5", "blob_value5"));
|
||||
ASSERT_OK(Put("Key6", "blob_value6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_GT(listener->blob_file_writes_.load(), 0U);
|
||||
ASSERT_GT(listener->blob_file_flushes_.load(), 0U);
|
||||
Close();
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_GT(listener->blob_file_closes_.load(), 0U);
|
||||
ASSERT_GT(listener->blob_file_syncs_.load(), 0U);
|
||||
if (true == options.use_direct_io_for_flush_and_compaction) {
|
||||
ASSERT_GT(listener->blob_file_truncates_.load(), 0U);
|
||||
}
|
||||
}
|
||||
|
||||
class BlobDBJobLevelEventListenerTest : public EventListener {
|
||||
public:
|
||||
explicit BlobDBJobLevelEventListenerTest(EventListenerTest* test)
|
||||
: test_(test), call_count_(0) {}
|
||||
|
||||
std::shared_ptr<BlobFileMetaData> GetBlobFileMetaData(
|
||||
const VersionStorageInfo::BlobFiles& blob_files,
|
||||
uint64_t blob_file_number) {
|
||||
const auto it = blob_files.find(blob_file_number);
|
||||
|
||||
if (it == blob_files.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto& meta = it->second;
|
||||
assert(meta);
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
const VersionStorageInfo::BlobFiles& GetBlobFiles() {
|
||||
VersionSet* const versions = test_->dbfull()->TEST_GetVersionSet();
|
||||
assert(versions);
|
||||
|
||||
ColumnFamilyData* const cfd = versions->GetColumnFamilySet()->GetDefault();
|
||||
EXPECT_NE(cfd, nullptr);
|
||||
|
||||
Version* const current = cfd->current();
|
||||
EXPECT_NE(current, nullptr);
|
||||
|
||||
const VersionStorageInfo* const storage_info = current->storage_info();
|
||||
EXPECT_NE(storage_info, nullptr);
|
||||
|
||||
const auto& blob_files = storage_info->GetBlobFiles();
|
||||
return blob_files;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetFlushedFiles() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<std::string> result;
|
||||
for (const auto& fname : flushed_files_) {
|
||||
result.push_back(fname);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override {
|
||||
call_count_++;
|
||||
EXPECT_FALSE(info.blob_file_addition_infos.empty());
|
||||
const auto& blob_files = GetBlobFiles();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
flushed_files_.push_back(info.file_path);
|
||||
}
|
||||
EXPECT_EQ(info.blob_compression_type, kNoCompression);
|
||||
|
||||
for (const auto& blob_file_addition_info : info.blob_file_addition_infos) {
|
||||
const auto meta = GetBlobFileMetaData(
|
||||
blob_files, blob_file_addition_info.blob_file_number);
|
||||
EXPECT_EQ(meta->GetBlobFileNumber(),
|
||||
blob_file_addition_info.blob_file_number);
|
||||
EXPECT_EQ(meta->GetTotalBlobBytes(),
|
||||
blob_file_addition_info.total_blob_bytes);
|
||||
EXPECT_EQ(meta->GetTotalBlobCount(),
|
||||
blob_file_addition_info.total_blob_count);
|
||||
EXPECT_FALSE(blob_file_addition_info.blob_file_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
void OnCompactionCompleted(DB* /*db*/, const CompactionJobInfo& ci) override {
|
||||
call_count_++;
|
||||
EXPECT_FALSE(ci.blob_file_garbage_infos.empty());
|
||||
const auto& blob_files = GetBlobFiles();
|
||||
EXPECT_EQ(ci.blob_compression_type, kNoCompression);
|
||||
|
||||
for (const auto& blob_file_addition_info : ci.blob_file_addition_infos) {
|
||||
const auto meta = GetBlobFileMetaData(
|
||||
blob_files, blob_file_addition_info.blob_file_number);
|
||||
EXPECT_EQ(meta->GetBlobFileNumber(),
|
||||
blob_file_addition_info.blob_file_number);
|
||||
EXPECT_EQ(meta->GetTotalBlobBytes(),
|
||||
blob_file_addition_info.total_blob_bytes);
|
||||
EXPECT_EQ(meta->GetTotalBlobCount(),
|
||||
blob_file_addition_info.total_blob_count);
|
||||
EXPECT_FALSE(blob_file_addition_info.blob_file_path.empty());
|
||||
}
|
||||
|
||||
for (const auto& blob_file_garbage_info : ci.blob_file_garbage_infos) {
|
||||
EXPECT_GT(blob_file_garbage_info.blob_file_number, 0U);
|
||||
EXPECT_GT(blob_file_garbage_info.garbage_blob_count, 0U);
|
||||
EXPECT_GT(blob_file_garbage_info.garbage_blob_bytes, 0U);
|
||||
EXPECT_FALSE(blob_file_garbage_info.blob_file_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
EventListenerTest* test_;
|
||||
uint32_t call_count_;
|
||||
|
||||
private:
|
||||
std::vector<std::string> flushed_files_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
// Test OnFlushCompleted EventListener called for blob files
|
||||
TEST_F(EventListenerTest, BlobDBOnFlushCompleted) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.enable_blob_files = true;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
|
||||
options.min_blob_size = 0;
|
||||
BlobDBJobLevelEventListenerTest* blob_event_listener =
|
||||
new BlobDBJobLevelEventListenerTest(this);
|
||||
options.listeners.emplace_back(blob_event_listener);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("Key1", "blob_value1"));
|
||||
ASSERT_OK(Put("Key2", "blob_value2"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key3", "blob_value3"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_EQ(Get("Key1"), "blob_value1");
|
||||
ASSERT_EQ(Get("Key2"), "blob_value2");
|
||||
ASSERT_EQ(Get("Key3"), "blob_value3");
|
||||
|
||||
ASSERT_GT(blob_event_listener->call_count_, 0U);
|
||||
}
|
||||
|
||||
// Test OnCompactionCompleted EventListener called for blob files
|
||||
TEST_F(EventListenerTest, BlobDBOnCompactionCompleted) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.enable_blob_files = true;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.min_blob_size = 0;
|
||||
BlobDBJobLevelEventListenerTest* blob_event_listener =
|
||||
new BlobDBJobLevelEventListenerTest(this);
|
||||
options.listeners.emplace_back(blob_event_listener);
|
||||
|
||||
options.enable_blob_garbage_collection = true;
|
||||
options.blob_garbage_collection_age_cutoff = 0.5;
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("Key1", "blob_value1"));
|
||||
ASSERT_OK(Put("Key2", "blob_value2"));
|
||||
ASSERT_OK(Put("Key3", "blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key3", "new_blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "new_blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key5", "blob_value5"));
|
||||
ASSERT_OK(Put("Key6", "blob_value6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
blob_event_listener->call_count_ = 0;
|
||||
constexpr Slice* begin = nullptr;
|
||||
constexpr Slice* end = nullptr;
|
||||
|
||||
// On compaction, because of blob_garbage_collection_age_cutoff, it will
|
||||
// delete the oldest blob file and create new blob file during compaction.
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), begin, end));
|
||||
|
||||
// Make sure, OnCompactionCompleted is called.
|
||||
ASSERT_GT(blob_event_listener->call_count_, 0U);
|
||||
}
|
||||
|
||||
// Test CompactFiles calls OnCompactionCompleted EventListener for blob files
|
||||
// and populate the blob files info.
|
||||
TEST_F(EventListenerTest, BlobDBCompactFiles) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.enable_blob_files = true;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.min_blob_size = 0;
|
||||
options.enable_blob_garbage_collection = true;
|
||||
options.blob_garbage_collection_age_cutoff = 0.5;
|
||||
|
||||
BlobDBJobLevelEventListenerTest* blob_event_listener =
|
||||
new BlobDBJobLevelEventListenerTest(this);
|
||||
options.listeners.emplace_back(blob_event_listener);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("Key1", "blob_value1"));
|
||||
ASSERT_OK(Put("Key2", "blob_value2"));
|
||||
ASSERT_OK(Put("Key3", "blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key3", "new_blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "new_blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key5", "blob_value5"));
|
||||
ASSERT_OK(Put("Key6", "blob_value6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::vector<std::string> output_file_names;
|
||||
CompactionJobInfo compaction_job_info;
|
||||
|
||||
// On compaction, because of blob_garbage_collection_age_cutoff, it will
|
||||
// delete the oldest blob file and create new blob file during compaction
|
||||
// which will be populated in output_files_names.
|
||||
ASSERT_OK(dbfull()->CompactFiles(
|
||||
CompactionOptions(), blob_event_listener->GetFlushedFiles(), 1, -1,
|
||||
&output_file_names, &compaction_job_info));
|
||||
|
||||
bool is_blob_in_output = false;
|
||||
for (const auto& file : output_file_names) {
|
||||
if (EndsWith(file, ".blob")) {
|
||||
is_blob_in_output = true;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(is_blob_in_output);
|
||||
|
||||
for (const auto& blob_file_addition_info :
|
||||
compaction_job_info.blob_file_addition_infos) {
|
||||
EXPECT_GT(blob_file_addition_info.blob_file_number, 0U);
|
||||
EXPECT_GT(blob_file_addition_info.total_blob_bytes, 0U);
|
||||
EXPECT_GT(blob_file_addition_info.total_blob_count, 0U);
|
||||
EXPECT_FALSE(blob_file_addition_info.blob_file_path.empty());
|
||||
}
|
||||
|
||||
for (const auto& blob_file_garbage_info :
|
||||
compaction_job_info.blob_file_garbage_infos) {
|
||||
EXPECT_GT(blob_file_garbage_info.blob_file_number, 0U);
|
||||
EXPECT_GT(blob_file_garbage_info.garbage_blob_count, 0U);
|
||||
EXPECT_GT(blob_file_garbage_info.garbage_blob_bytes, 0U);
|
||||
EXPECT_FALSE(blob_file_garbage_info.blob_file_path.empty());
|
||||
}
|
||||
}
|
||||
|
||||
class BlobDBFileLevelEventListener : public EventListener {
|
||||
public:
|
||||
BlobDBFileLevelEventListener() {
|
||||
files_started_.store(0);
|
||||
files_created_.store(0);
|
||||
files_deleted_.store(0);
|
||||
}
|
||||
|
||||
void OnBlobFileCreationStarted(
|
||||
const BlobFileCreationBriefInfo& info) override {
|
||||
files_started_++;
|
||||
EXPECT_FALSE(info.db_name.empty());
|
||||
EXPECT_FALSE(info.cf_name.empty());
|
||||
EXPECT_FALSE(info.file_path.empty());
|
||||
EXPECT_GT(info.job_id, 0);
|
||||
}
|
||||
|
||||
void OnBlobFileCreated(const BlobFileCreationInfo& info) override {
|
||||
files_created_++;
|
||||
EXPECT_FALSE(info.db_name.empty());
|
||||
EXPECT_FALSE(info.cf_name.empty());
|
||||
EXPECT_FALSE(info.file_path.empty());
|
||||
EXPECT_GT(info.job_id, 0);
|
||||
EXPECT_GT(info.total_blob_count, 0U);
|
||||
EXPECT_GT(info.total_blob_bytes, 0U);
|
||||
EXPECT_EQ(info.file_checksum, kUnknownFileChecksum);
|
||||
EXPECT_EQ(info.file_checksum_func_name, kUnknownFileChecksumFuncName);
|
||||
EXPECT_TRUE(info.status.ok());
|
||||
}
|
||||
|
||||
void OnBlobFileDeleted(const BlobFileDeletionInfo& info) override {
|
||||
files_deleted_++;
|
||||
EXPECT_FALSE(info.db_name.empty());
|
||||
EXPECT_FALSE(info.file_path.empty());
|
||||
EXPECT_GT(info.job_id, 0);
|
||||
EXPECT_TRUE(info.status.ok());
|
||||
}
|
||||
|
||||
void CheckCounters() {
|
||||
EXPECT_EQ(files_started_, files_created_);
|
||||
EXPECT_GT(files_started_, 0U);
|
||||
EXPECT_GT(files_deleted_, 0U);
|
||||
EXPECT_LT(files_deleted_, files_created_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<uint32_t> files_started_;
|
||||
std::atomic<uint32_t> files_created_;
|
||||
std::atomic<uint32_t> files_deleted_;
|
||||
};
|
||||
|
||||
TEST_F(EventListenerTest, BlobDBFileTest) {
|
||||
Options options;
|
||||
options.env = CurrentOptions().env;
|
||||
options.enable_blob_files = true;
|
||||
options.create_if_missing = true;
|
||||
options.disable_auto_compactions = true;
|
||||
options.min_blob_size = 0;
|
||||
options.enable_blob_garbage_collection = true;
|
||||
options.blob_garbage_collection_age_cutoff = 0.5;
|
||||
|
||||
BlobDBFileLevelEventListener* blob_event_listener =
|
||||
new BlobDBFileLevelEventListener();
|
||||
options.listeners.emplace_back(blob_event_listener);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("Key1", "blob_value1"));
|
||||
ASSERT_OK(Put("Key2", "blob_value2"));
|
||||
ASSERT_OK(Put("Key3", "blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key3", "new_blob_value3"));
|
||||
ASSERT_OK(Put("Key4", "new_blob_value4"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("Key5", "blob_value5"));
|
||||
ASSERT_OK(Put("Key6", "blob_value6"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
constexpr Slice* begin = nullptr;
|
||||
constexpr Slice* end = nullptr;
|
||||
|
||||
// On compaction, because of blob_garbage_collection_age_cutoff, it will
|
||||
// delete the oldest blob file and create new blob file during compaction.
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), begin, end));
|
||||
|
||||
blob_event_listener->CheckCounters();
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
+2
-2
@@ -19,10 +19,10 @@ namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
#ifdef ROCKSDB_JEMALLOC
|
||||
|
||||
struct MallocStatus {
|
||||
typedef struct {
|
||||
char* cur;
|
||||
char* end;
|
||||
};
|
||||
} MallocStatus;
|
||||
|
||||
static void GetJemallocStatus(void* mstat_arg, const char* status) {
|
||||
MallocStatus* mstat = reinterpret_cast<MallocStatus*>(mstat_arg);
|
||||
|
||||
+14
-11
@@ -487,7 +487,7 @@ MemTable::MemTableStats MemTable::ApproximateStats(const Slice& start_ikey,
|
||||
}
|
||||
|
||||
Status MemTable::VerifyEncodedEntry(Slice encoded,
|
||||
const ProtectionInfoKVOS64& kv_prot_info) {
|
||||
const ProtectionInfoKVOTS64& kv_prot_info) {
|
||||
uint32_t ikey_len = 0;
|
||||
if (!GetVarint32(&encoded, &ikey_len)) {
|
||||
return Status::Corruption("Unable to parse internal key length");
|
||||
@@ -500,9 +500,12 @@ Status MemTable::VerifyEncodedEntry(Slice encoded,
|
||||
return Status::Corruption("Internal key length too long");
|
||||
}
|
||||
uint32_t value_len = 0;
|
||||
const size_t user_key_len = ikey_len - 8;
|
||||
Slice key(encoded.data(), user_key_len);
|
||||
encoded.remove_prefix(user_key_len);
|
||||
const size_t key_without_ts_len = ikey_len - ts_sz - 8;
|
||||
Slice key(encoded.data(), key_without_ts_len);
|
||||
encoded.remove_prefix(key_without_ts_len);
|
||||
|
||||
Slice timestamp(encoded.data(), ts_sz);
|
||||
encoded.remove_prefix(ts_sz);
|
||||
|
||||
uint64_t packed = DecodeFixed64(encoded.data());
|
||||
ValueType value_type = kMaxValue;
|
||||
@@ -522,14 +525,14 @@ Status MemTable::VerifyEncodedEntry(Slice encoded,
|
||||
Slice value(encoded.data(), value_len);
|
||||
|
||||
return kv_prot_info.StripS(sequence_number)
|
||||
.StripKVO(key, value, value_type)
|
||||
.StripKVOT(key, value, value_type, timestamp)
|
||||
.GetStatus();
|
||||
}
|
||||
|
||||
Status MemTable::Add(SequenceNumber s, ValueType type,
|
||||
const Slice& key, /* user key */
|
||||
const Slice& value,
|
||||
const ProtectionInfoKVOS64* kv_prot_info,
|
||||
const ProtectionInfoKVOTS64* kv_prot_info,
|
||||
bool allow_concurrent,
|
||||
MemTablePostProcessInfo* post_process_info, void** hint) {
|
||||
// Format of an entry is concatenation of:
|
||||
@@ -1033,7 +1036,7 @@ void MemTable::MultiGet(const ReadOptions& read_options, MultiGetRange* range,
|
||||
|
||||
Status MemTable::Update(SequenceNumber seq, const Slice& key,
|
||||
const Slice& value,
|
||||
const ProtectionInfoKVOS64* kv_prot_info) {
|
||||
const ProtectionInfoKVOTS64* kv_prot_info) {
|
||||
LookupKey lkey(key, seq);
|
||||
Slice mem_key = lkey.memtable_key();
|
||||
|
||||
@@ -1078,7 +1081,7 @@ Status MemTable::Update(SequenceNumber seq, const Slice& key,
|
||||
VarintLength(value.size()) + value.size()));
|
||||
RecordTick(moptions_.statistics, NUMBER_KEYS_UPDATED);
|
||||
if (kv_prot_info != nullptr) {
|
||||
ProtectionInfoKVOS64 updated_kv_prot_info(*kv_prot_info);
|
||||
ProtectionInfoKVOTS64 updated_kv_prot_info(*kv_prot_info);
|
||||
// `seq` is swallowed and `existing_seq` prevails.
|
||||
updated_kv_prot_info.UpdateS(seq, existing_seq);
|
||||
Slice encoded(entry, p + value.size() - entry);
|
||||
@@ -1096,7 +1099,7 @@ Status MemTable::Update(SequenceNumber seq, const Slice& key,
|
||||
|
||||
Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
const Slice& delta,
|
||||
const ProtectionInfoKVOS64* kv_prot_info) {
|
||||
const ProtectionInfoKVOTS64* kv_prot_info) {
|
||||
LookupKey lkey(key, seq);
|
||||
Slice memkey = lkey.memtable_key();
|
||||
|
||||
@@ -1151,7 +1154,7 @@ Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
RecordTick(moptions_.statistics, NUMBER_KEYS_UPDATED);
|
||||
UpdateFlushState();
|
||||
if (kv_prot_info != nullptr) {
|
||||
ProtectionInfoKVOS64 updated_kv_prot_info(*kv_prot_info);
|
||||
ProtectionInfoKVOTS64 updated_kv_prot_info(*kv_prot_info);
|
||||
// `seq` is swallowed and `existing_seq` prevails.
|
||||
updated_kv_prot_info.UpdateS(seq, existing_seq);
|
||||
updated_kv_prot_info.UpdateV(delta,
|
||||
@@ -1163,7 +1166,7 @@ Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
} else if (status == UpdateStatus::UPDATED) {
|
||||
Status s;
|
||||
if (kv_prot_info != nullptr) {
|
||||
ProtectionInfoKVOS64 updated_kv_prot_info(*kv_prot_info);
|
||||
ProtectionInfoKVOTS64 updated_kv_prot_info(*kv_prot_info);
|
||||
updated_kv_prot_info.UpdateV(delta, str_value);
|
||||
s = Add(seq, kTypeValue, key, Slice(str_value),
|
||||
&updated_kv_prot_info);
|
||||
|
||||
+4
-4
@@ -199,7 +199,7 @@ class MemTable {
|
||||
const ReadOptions& read_options, SequenceNumber read_seq);
|
||||
|
||||
Status VerifyEncodedEntry(Slice encoded,
|
||||
const ProtectionInfoKVOS64& kv_prot_info);
|
||||
const ProtectionInfoKVOTS64& kv_prot_info);
|
||||
|
||||
// Add an entry into memtable that maps key to value at the
|
||||
// specified sequence number and with the specified type.
|
||||
@@ -212,7 +212,7 @@ class MemTable {
|
||||
// in the memtable and `MemTableRepFactory::CanHandleDuplicatedKey()` is true.
|
||||
// The next attempt should try a larger value for `seq`.
|
||||
Status Add(SequenceNumber seq, ValueType type, const Slice& key,
|
||||
const Slice& value, const ProtectionInfoKVOS64* kv_prot_info,
|
||||
const Slice& value, const ProtectionInfoKVOTS64* kv_prot_info,
|
||||
bool allow_concurrent = false,
|
||||
MemTablePostProcessInfo* post_process_info = nullptr,
|
||||
void** hint = nullptr);
|
||||
@@ -278,7 +278,7 @@ class MemTable {
|
||||
// REQUIRES: external synchronization to prevent simultaneous
|
||||
// operations on the same MemTable.
|
||||
Status Update(SequenceNumber seq, const Slice& key, const Slice& value,
|
||||
const ProtectionInfoKVOS64* kv_prot_info);
|
||||
const ProtectionInfoKVOTS64* kv_prot_info);
|
||||
|
||||
// If `key` exists in current memtable with type `kTypeValue` and the existing
|
||||
// value is at least as large as the new value, updates it in-place. Otherwise
|
||||
@@ -296,7 +296,7 @@ class MemTable {
|
||||
// operations on the same MemTable.
|
||||
Status UpdateCallback(SequenceNumber seq, const Slice& key,
|
||||
const Slice& delta,
|
||||
const ProtectionInfoKVOS64* kv_prot_info);
|
||||
const ProtectionInfoKVOTS64* kv_prot_info);
|
||||
|
||||
// Returns the number of successive merge entries starting from the newest
|
||||
// entry for the key up to the last non-merge entry or last entry for the
|
||||
|
||||
@@ -117,9 +117,6 @@ std::shared_ptr<DB> OpenDb(const std::string& dbname, const bool ttl = false,
|
||||
#endif // !ROCKSDB_LITE
|
||||
EXPECT_OK(s);
|
||||
assert(s.ok());
|
||||
// Allowed to call NowNanos during DB creation (in GenerateRawUniqueId() for
|
||||
// session ID)
|
||||
EnvMergeTest::now_nanos_count_ = 0;
|
||||
return std::shared_ptr<DB>(db);
|
||||
}
|
||||
|
||||
@@ -466,8 +463,6 @@ void testPartialMerge(Counters* counters, DB* db, size_t max_merge,
|
||||
ASSERT_OK(db->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(tmp_sum, counters->assert_get("c"));
|
||||
ASSERT_EQ(num_partial_merge_calls, 0U);
|
||||
// NowNanos was previously called in MergeHelper::FilterMerge(), which
|
||||
// harmed performance.
|
||||
ASSERT_EQ(EnvMergeTest::now_nanos_count_, 0U);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class PinnedIteratorsManager : public Cleanable {
|
||||
}
|
||||
}
|
||||
|
||||
using ReleaseFunction = void (*)(void* arg1);
|
||||
typedef void (*ReleaseFunction)(void* arg1);
|
||||
void PinPtr(void* ptr, ReleaseFunction release_func) {
|
||||
assert(pinning_enabled);
|
||||
if (ptr == nullptr) {
|
||||
|
||||
@@ -220,8 +220,8 @@ class PlainTableDBTest : public testing::Test,
|
||||
|
||||
int NumTableFilesAtLevel(int level) {
|
||||
std::string property;
|
||||
EXPECT_TRUE(db_->GetProperty("rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.num-files-at-level" + NumberToString(level), &property));
|
||||
return atoi(property.c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/types.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
class DB;
|
||||
|
||||
class PreReleaseCallback {
|
||||
public:
|
||||
virtual ~PreReleaseCallback() {}
|
||||
|
||||
Loaded 100 of 312 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user