mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-06 02:52:35 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66559b4087 | ||
|
|
d8e835549b | ||
|
|
f2f26b1559 | ||
|
|
710592283f | ||
|
|
f38f5570d5 | ||
|
|
3620e69404 | ||
|
|
34681a1a2a | ||
|
|
5898845c87 | ||
|
|
1ef888f9b8 | ||
|
|
14fb86d1ba | ||
|
|
65a3e21af4 | ||
|
|
b3c68d8de9 |
No files matched your search
+68
-72
@@ -111,12 +111,6 @@ commands:
|
||||
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_GTEST_TESTS=0
|
||||
ninja && sudo ninja install
|
||||
|
||||
install-valgrind:
|
||||
steps:
|
||||
- run:
|
||||
name: Install valgrind
|
||||
command: sudo apt-get update -y && sudo apt-get install -y valgrind
|
||||
|
||||
upgrade-cmake:
|
||||
steps:
|
||||
- run:
|
||||
@@ -152,8 +146,8 @@ commands:
|
||||
- run:
|
||||
name: Install libprotobuf-mutator libs
|
||||
command: |
|
||||
git clone -b v1.0 git@github.com:google/libprotobuf-mutator.git ~/libprotobuf-mutator
|
||||
cd ~/libprotobuf-mutator && git checkout ffd86a32874e5c08a143019aad1aaf0907294c9f && mkdir build && cd build
|
||||
git clone --single-branch --branch master --depth 1 git@github.com:google/libprotobuf-mutator.git ~/libprotobuf-mutator
|
||||
cd ~/libprotobuf-mutator && mkdir build && cd build
|
||||
cmake .. -GNinja -DCMAKE_C_COMPILER=clang-13 -DCMAKE_CXX_COMPILER=clang++-13 -DCMAKE_BUILD_TYPE=Release -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON
|
||||
ninja && sudo ninja install
|
||||
- run:
|
||||
@@ -180,7 +174,7 @@ jobs:
|
||||
- increase-max-open-files-on-macos
|
||||
- install-gflags-on-macos
|
||||
- pre-steps-macos
|
||||
- run: ulimit -S -n `ulimit -H -n` && OPT=-DCIRCLECI make V=1 J=32 -j32 all
|
||||
- run: ulimit -S -n 1048576 && OPT=-DCIRCLECI make V=1 J=32 -j32 all
|
||||
- post-steps
|
||||
|
||||
build-macos-cmake:
|
||||
@@ -199,7 +193,7 @@ jobs:
|
||||
- pre-steps-macos
|
||||
- run:
|
||||
name: "cmake generate project file"
|
||||
command: ulimit -S -n `ulimit -H -n` && mkdir build && cd build && cmake -DWITH_GFLAGS=1 ..
|
||||
command: ulimit -S -n 1048576 && mkdir build && cd build && cmake -DWITH_GFLAGS=1 ..
|
||||
- run:
|
||||
name: "Build tests"
|
||||
command: cd build && make V=1 -j32
|
||||
@@ -208,14 +202,14 @@ jobs:
|
||||
steps:
|
||||
- run:
|
||||
name: "Run even tests"
|
||||
command: ulimit -S -n `ulimit -H -n` && cd build && ctest -j32 -I 0,,2
|
||||
command: ulimit -S -n 1048576 && cd build && ctest -j32 -I 0,,2
|
||||
- when:
|
||||
condition:
|
||||
not: << parameters.run_even_tests >>
|
||||
steps:
|
||||
- run:
|
||||
name: "Run odd tests"
|
||||
command: ulimit -S -n `ulimit -H -n` && cd build && ctest -j32 -I 1,,2
|
||||
command: ulimit -S -n 1048576 && cd build && ctest -j32 -I 1,,2
|
||||
- post-steps
|
||||
|
||||
build-linux:
|
||||
@@ -228,16 +222,14 @@ jobs:
|
||||
- run: make V=1 J=32 -j32 check
|
||||
- post-steps
|
||||
|
||||
build-linux-encrypted_env-no_compression:
|
||||
build-linux-encrypted-env:
|
||||
machine:
|
||||
image: ubuntu-2004:202111-02
|
||||
resource_class: 2xlarge
|
||||
steps:
|
||||
- pre-steps
|
||||
- install-gflags
|
||||
- run: ENCRYPTED_ENV=1 ROCKSDB_DISABLE_SNAPPY=1 ROCKSDB_DISABLE_ZLIB=1 ROCKSDB_DISABLE_BZIP=1 ROCKSDB_DISABLE_LZ4=1 ROCKSDB_DISABLE_ZSTD=1 make V=1 J=32 -j32 check
|
||||
- run: |
|
||||
./sst_dump --help | egrep -q 'Supported compression types: kNoCompression$' # Verify no compiled in compression
|
||||
- run: ENCRYPTED_ENV=1 make V=1 J=32 -j32 check
|
||||
- post-steps
|
||||
|
||||
build-linux-shared_lib-alt_namespace-status_checked:
|
||||
@@ -318,7 +310,7 @@ jobs:
|
||||
- pre-steps
|
||||
- install-gflags
|
||||
- install-clang-10
|
||||
- run: COMPILE_WITH_ASAN=1 CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check # aligned new doesn't work for reason we haven't figured out
|
||||
- run: ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 check # aligned new doesn't work for reason we haven't figured out
|
||||
- post-steps
|
||||
|
||||
build-linux-clang10-mini-tsan:
|
||||
@@ -362,17 +354,6 @@ jobs:
|
||||
- run: COMPILE_WITH_UBSAN=1 OPT="-fsanitize-blacklist=.circleci/ubsan_suppression_list.txt" CC=clang-10 CXX=clang++-10 ROCKSDB_DISABLE_ALIGNED_NEW=1 USE_CLANG=1 make V=1 -j32 ubsan_check # aligned new doesn't work for reason we haven't figured out
|
||||
- post-steps
|
||||
|
||||
build-linux-valgrind:
|
||||
machine:
|
||||
image: ubuntu-2004:202111-02
|
||||
resource_class: 2xlarge
|
||||
steps:
|
||||
- pre-steps
|
||||
- install-gflags
|
||||
- install-valgrind
|
||||
- run: PORTABLE=1 make V=1 -j32 valgrind_test
|
||||
- post-steps
|
||||
|
||||
build-linux-clang10-clang-analyze:
|
||||
machine:
|
||||
image: ubuntu-2004:202111-02
|
||||
@@ -411,13 +392,11 @@ jobs:
|
||||
build-linux-unity-and-headers:
|
||||
docker: # executor type
|
||||
- image: gcc:latest
|
||||
environment:
|
||||
EXTRA_CXXFLAGS: -mno-avx512f # Warnings-as-error in avx512fintrin.h, would be used on newer hardware
|
||||
resource_class: large
|
||||
steps:
|
||||
- checkout # check out the code in the project directory
|
||||
- run: apt-get update -y && apt-get install -y libgflags-dev
|
||||
- run: make V=1 -j8 unity_test
|
||||
- run: TEST_TMPDIR=/dev/shm && make V=1 -j8 unity_test
|
||||
- run: make V=1 -j8 -k check-headers # could be moved to a different build
|
||||
- post-steps
|
||||
|
||||
@@ -474,19 +453,6 @@ jobs:
|
||||
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 make -j16 all microbench
|
||||
- post-steps
|
||||
|
||||
# Ensure ASAN+UBSAN with folly, and full testsuite with clang 13
|
||||
build-linux-clang-13-asan-ubsan-with-folly:
|
||||
machine:
|
||||
image: ubuntu-2004:202111-02
|
||||
resource_class: 2xlarge
|
||||
steps:
|
||||
- pre-steps
|
||||
- install-clang-13
|
||||
- install-gflags
|
||||
- run: make checkout_folly
|
||||
- run: CC=clang-13 CXX=clang++-13 USE_CLANG=1 USE_FOLLY=1 COMPILE_WITH_UBSAN=1 COMPILE_WITH_ASAN=1 make -j32 check
|
||||
- post-steps
|
||||
|
||||
# This job is only to make sure the microbench tests are able to run, the benchmark result is not meaningful as the CI host is changing.
|
||||
build-linux-run-microbench:
|
||||
machine:
|
||||
@@ -506,7 +472,7 @@ jobs:
|
||||
- pre-steps
|
||||
- install-gflags
|
||||
- install-compression-libs
|
||||
- run: ulimit -S -n `ulimit -H -n` && make V=1 -j8 CRASH_TEST_EXT_ARGS=--duration=960 blackbox_crash_test_with_atomic_flush
|
||||
- run: make V=1 -j8 CRASH_TEST_EXT_ARGS=--duration=960 blackbox_crash_test_with_atomic_flush
|
||||
- post-steps
|
||||
|
||||
build-windows:
|
||||
@@ -828,76 +794,108 @@ jobs:
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
jobs-linux-run-tests:
|
||||
build-linux:
|
||||
jobs:
|
||||
- build-linux
|
||||
build-linux-cmake:
|
||||
jobs:
|
||||
- build-linux-cmake-with-folly
|
||||
- build-linux-gcc-7-with-folly
|
||||
- build-linux-cmake-with-benchmark
|
||||
- build-linux-encrypted_env-no_compression
|
||||
build-linux-encrypted-env:
|
||||
jobs:
|
||||
- build-linux-encrypted-env
|
||||
build-linux-shared_lib-alt_namespace-status_checked:
|
||||
jobs:
|
||||
- build-linux-shared_lib-alt_namespace-status_checked
|
||||
build-linux-lite:
|
||||
jobs:
|
||||
- build-linux-lite
|
||||
jobs-linux-run-tests-san:
|
||||
build-linux-release:
|
||||
jobs:
|
||||
- build-linux-release
|
||||
build-linux-release-rtti:
|
||||
jobs:
|
||||
- build-linux-release-rtti
|
||||
build-linux-lite-release:
|
||||
jobs:
|
||||
- build-linux-lite-release
|
||||
build-linux-clang10-asan:
|
||||
jobs:
|
||||
- build-linux-clang10-asan
|
||||
- build-linux-clang10-ubsan
|
||||
build-linux-clang10-mini-tsan:
|
||||
jobs:
|
||||
- build-linux-clang10-mini-tsan:
|
||||
start_test: ""
|
||||
end_test: "env_test"
|
||||
- build-linux-clang10-mini-tsan:
|
||||
start_test: "env_test"
|
||||
end_test: ""
|
||||
- build-linux-shared_lib-alt_namespace-status_checked
|
||||
jobs-linux-no-test-run:
|
||||
build-linux-clang10-ubsan:
|
||||
jobs:
|
||||
- build-linux-release
|
||||
- build-linux-release-rtti
|
||||
- build-linux-lite-release
|
||||
- build-examples
|
||||
- build-fuzzers
|
||||
- build-linux-clang-no_test_run
|
||||
- build-linux-clang-13-no_test_run
|
||||
- build-linux-gcc-8-no_test_run
|
||||
- build-linux-gcc-10-cxx20-no_test_run
|
||||
- build-linux-gcc-11-no_test_run
|
||||
- build-linux-arm-cmake-no_test_run
|
||||
jobs-linux-other-checks:
|
||||
- build-linux-clang10-ubsan
|
||||
build-linux-clang10-clang-analyze:
|
||||
jobs:
|
||||
- build-linux-clang10-clang-analyze
|
||||
build-linux-unity-and-headers:
|
||||
jobs:
|
||||
- build-linux-unity-and-headers
|
||||
build-linux-mini-crashtest:
|
||||
jobs:
|
||||
- build-linux-mini-crashtest
|
||||
jobs-windows:
|
||||
build-windows-vs2019:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2019"
|
||||
build-windows-vs2019-cxx20:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2019-cxx20"
|
||||
extra_cmake_opt: -DCMAKE_CXX_STANDARD=20
|
||||
build-windows-vs2017:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2017"
|
||||
vs_year: "2017"
|
||||
cmake_generator: "Visual Studio 15 Win64"
|
||||
- build-cmake-mingw
|
||||
jobs-java:
|
||||
build-java:
|
||||
jobs:
|
||||
- build-linux-java
|
||||
- build-linux-java-static
|
||||
- build-macos-java
|
||||
- build-macos-java-static
|
||||
- build-macos-java-static-universal
|
||||
jobs-macos:
|
||||
build-examples:
|
||||
jobs:
|
||||
- build-examples
|
||||
build-linux-compilers-no_test_run:
|
||||
jobs:
|
||||
- build-linux-clang-no_test_run
|
||||
- build-linux-clang-13-no_test_run
|
||||
- build-linux-gcc-7-with-folly
|
||||
- build-linux-gcc-8-no_test_run
|
||||
- build-linux-gcc-10-cxx20-no_test_run
|
||||
- build-linux-gcc-11-no_test_run
|
||||
- build-linux-arm-cmake-no_test_run
|
||||
build-macos:
|
||||
jobs:
|
||||
- build-macos
|
||||
- build-macos-cmake:
|
||||
run_even_tests: true
|
||||
- build-macos-cmake:
|
||||
run_even_tests: false
|
||||
jobs-linux-arm:
|
||||
build-cmake-mingw:
|
||||
jobs:
|
||||
- build-cmake-mingw
|
||||
build-linux-arm:
|
||||
jobs:
|
||||
- build-linux-arm
|
||||
build-fuzzers:
|
||||
jobs:
|
||||
- build-fuzzers
|
||||
nightly:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 9 * * *"
|
||||
cron: "0 0 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
@@ -907,5 +905,3 @@ workflows:
|
||||
- build-linux-arm-test-full
|
||||
- build-linux-run-microbench
|
||||
- build-linux-non-shm
|
||||
- build-linux-clang-13-asan-ubsan-with-folly
|
||||
- build-linux-valgrind
|
||||
@@ -36,7 +36,6 @@ manifest_dump
|
||||
sst_dump
|
||||
blob_dump
|
||||
block_cache_trace_analyzer
|
||||
db_readonly_with_timestamp_test
|
||||
db_with_timestamp_basic_test
|
||||
tools/block_cache_analyzer/*.pyc
|
||||
column_aware_encoding_exp
|
||||
|
||||
+3
-26
@@ -40,8 +40,6 @@ include(GoogleTest)
|
||||
get_rocksdb_version(rocksdb_VERSION)
|
||||
project(rocksdb
|
||||
VERSION ${rocksdb_VERSION}
|
||||
DESCRIPTION "An embeddable persistent key-value store for fast storage"
|
||||
HOMEPAGE_URL https://rocksdb.org/
|
||||
LANGUAGES CXX C ASM)
|
||||
|
||||
if(POLICY CMP0042)
|
||||
@@ -337,6 +335,9 @@ endif()
|
||||
# Reset the required flags
|
||||
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
|
||||
|
||||
# thread_local is part of C++11 and later (TODO: clean up this define)
|
||||
add_definitions(-DROCKSDB_SUPPORT_THREAD_LOCAL)
|
||||
|
||||
option(WITH_IOSTATS_CONTEXT "Enable IO stats context" ON)
|
||||
if (NOT WITH_IOSTATS_CONTEXT)
|
||||
add_definitions(-DNIOSTATS_CONTEXT)
|
||||
@@ -595,7 +596,6 @@ set(SOURCES
|
||||
cache/cache_reservation_manager.cc
|
||||
cache/clock_cache.cc
|
||||
cache/compressed_secondary_cache.cc
|
||||
cache/fast_lru_cache.cc
|
||||
cache/lru_cache.cc
|
||||
cache/sharded_cache.cc
|
||||
db/arena_wrapped_db_iter.cc
|
||||
@@ -796,8 +796,6 @@ set(SOURCES
|
||||
trace_replay/trace_record_result.cc
|
||||
trace_replay/trace_record.cc
|
||||
trace_replay/trace_replay.cc
|
||||
util/async_file_reader.cc
|
||||
util/cleanable.cc
|
||||
util/coding.cc
|
||||
util/compaction_job_stats_impl.cc
|
||||
util/comparator.cc
|
||||
@@ -1121,20 +1119,8 @@ if(NOT WIN32 OR ROCKSDB_INSTALL_ON_WINDOWS)
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(DIRECTORY include/rocksdb COMPONENT devel DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
foreach (plugin ${PLUGINS})
|
||||
foreach (header ${${plugin}_HEADERS})
|
||||
install(FILES plugin/${plugin}/${header} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/rocksdb/plugin/${plugin})
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
install(DIRECTORY "${PROJECT_SOURCE_DIR}/cmake/modules" COMPONENT devel DESTINATION ${package_config_destination})
|
||||
|
||||
install(
|
||||
@@ -1171,13 +1157,6 @@ if(NOT WIN32 OR ROCKSDB_INSTALL_ON_WINDOWS)
|
||||
COMPONENT devel
|
||||
DESTINATION ${package_config_destination}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
||||
COMPONENT devel
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
endif()
|
||||
|
||||
option(WITH_ALL_TESTS "Build all test, rather than a small subset" ON)
|
||||
@@ -1223,7 +1202,6 @@ if(WITH_TESTS)
|
||||
db/comparator_db_test.cc
|
||||
db/corruption_test.cc
|
||||
db/cuckoo_table_db_test.cc
|
||||
db/db_readonly_with_timestamp_test.cc
|
||||
db/db_with_timestamp_basic_test.cc
|
||||
db/db_block_cache_test.cc
|
||||
db/db_bloom_filter_test.cc
|
||||
@@ -1392,7 +1370,6 @@ if(WITH_TESTS)
|
||||
|
||||
set(TESTUTIL_SOURCE
|
||||
db/db_test_util.cc
|
||||
db/db_with_timestamp_test_util.cc
|
||||
monitoring/thread_status_updater_debug.cc
|
||||
table/mock_table.cc
|
||||
utilities/agg_merge/test_agg_merge.cc
|
||||
|
||||
+3
-51
@@ -1,60 +1,12 @@
|
||||
# Rocksdb Change Log
|
||||
## 7.3.2 (07/13/2022)
|
||||
## 7.2.2 (04/28/2022)
|
||||
### Bug Fixes
|
||||
* Avoid a crash if the IDENTITY file is accidentally truncated to empty. A new DB ID will be written and generated on Open.
|
||||
* Fixed a possible corruption for users of `manual_wal_flush` and/or `FlushWAL(true /* sync */)`, together with `track_and_verify_wals_in_manifest == true`. For those users, losing unsynced data (e.g., due to power loss) could make future DB opens fail with a `Status::Corruption` complaining about missing WAL data.
|
||||
|
||||
### Behavior Change
|
||||
* Add an extra sanity check in `GetSortedWalFiles()` (also used by `GetLiveFilesStorageInfo()`, `BackupEngine`, and `Checkpoint`) to reduce risk of successfully created backup or checkpoint failing to open because of missing WAL file.
|
||||
* For track_and_verify_wals_in_manifest, revert to the original behavior before #10087: syncing of live WAL file is not tracked, and we track only the synced sizes of **closed** WALs. (PR #10330).
|
||||
|
||||
## 7.3.1 (06/08/2022)
|
||||
### Bug Fixes
|
||||
* Fix a bug in WAL tracking. Before this PR (#10087), calling `SyncWAL()` on the only WAL file of the db will not log the event in MANIFEST, thus allowing a subsequent `DB::Open` even if the WAL file is missing or corrupted.
|
||||
* Fixed a bug for non-TransactionDB with avoid_flush_during_recovery = true and TransactionDB where in case of crash, min_log_number_to_keep may not change on recovery and persisting a new MANIFEST with advanced log_numbers for some column families, results in "column family inconsistency" error on second recovery. As a solution, RocksDB will persist the new MANIFEST after successfully syncing the new WAL. If a future recovery starts from the new MANIFEST, then it means the new WAL is successfully synced. Due to the sentinel empty write batch at the beginning, kPointInTimeRecovery of WAL is guaranteed to go after this point. If future recovery starts from the old MANIFEST, it means the writing the new MANIFEST failed. We won't have the "SST ahead of WAL" error.
|
||||
* Fixed a bug where RocksDB DB::Open() may creates and writes to two new MANIFEST files even before recovery succeeds. Now writes to MANIFEST are persisted only after recovery is successful.
|
||||
|
||||
## 7.3.0 (05/20/2022)
|
||||
### Bug Fixes
|
||||
* Fixed a bug where manual flush would block forever even though flush options had wait=false.
|
||||
* Fixed a bug where RocksDB could corrupt DBs with `avoid_flush_during_recovery == true` by removing valid WALs, leading to `Status::Corruption` with message like "SST file is ahead of WALs" when attempting to reopen.
|
||||
* Fixed a bug in async_io path where incorrect length of data is read by FilePrefetchBuffer if data is consumed from two populated buffers and request for more data is sent.
|
||||
* Fixed a CompactionFilter bug. Compaction filter used to use `Delete` to remove keys, even if the keys should be removed with `SingleDelete`. Mixing `Delete` and `SingleDelete` may cause undefined behavior.
|
||||
* Fixed a bug in `WritableFileWriter::WriteDirect` and `WritableFileWriter::WriteDirectWithChecksum`. The rate_limiter_priority specified in ReadOptions was not passed to the RateLimiter when requesting a token.
|
||||
* Fixed a bug which might cause process crash when I/O error happens when reading an index block in MultiGet().
|
||||
|
||||
### New Features
|
||||
* DB::GetLiveFilesStorageInfo is ready for production use.
|
||||
* Add new stats PREFETCHED_BYTES_DISCARDED which records number of prefetched bytes discarded by RocksDB FilePrefetchBuffer on destruction and POLL_WAIT_MICROS records wait time for FS::Poll API completion.
|
||||
* RemoteCompaction supports table_properties_collector_factories override on compaction worker.
|
||||
* Start tracking SST unique id in MANIFEST, which will be used to verify with SST properties during DB open to make sure the SST file is not overwritten or misplaced. A db option `verify_sst_unique_id_in_manifest` is introduced to enable/disable the verification, if enabled all SST files will be opened during DB-open to verify the unique id (default is false), so it's recommended to use it with `max_open_files = -1` to pre-open the files.
|
||||
* Added the ability to concurrently read data blocks from multiple files in a level in batched MultiGet. This can be enabled by setting the async_io option in ReadOptions. Using this feature requires a FileSystem that supports ReadAsync (PosixFileSystem is not supported yet for this), and for RocksDB to be compiled with folly and c++20.
|
||||
* Add FileSystem::ReadAsync API in io_tracing.
|
||||
|
||||
### Public API changes
|
||||
* Add rollback_deletion_type_callback to TransactionDBOptions so that write-prepared transactions know whether to issue a Delete or SingleDelete to cancel a previous key written during prior prepare phase. The PR aims to prevent mixing SingleDeletes and Deletes for the same key that can lead to undefined behaviors for write-prepared transactions.
|
||||
* EXPERIMENTAL: Add new API AbortIO in file_system to abort the read requests submitted asynchronously.
|
||||
* CompactionFilter::Decision has a new value: kRemoveWithSingleDelete. If CompactionFilter returns this decision, then CompactionIterator will use `SingleDelete` to mark a key as removed.
|
||||
* Renamed CompactionFilter::Decision::kRemoveWithSingleDelete to kPurge since the latter sounds more general and hides the implementation details of how compaction iterator handles keys.
|
||||
* Added ability to specify functions for Prepare and Validate to OptionsTypeInfo. Added methods to OptionTypeInfo to set the functions via an API. These methods are intended for RocksDB plugin developers for configuration management.
|
||||
* Added a new immutable db options, enforce_single_del_contracts. If set to false (default is true), compaction will NOT fail due to a single delete followed by a delete for the same key. The purpose of this temporay option is to help existing use cases migrate.
|
||||
* Introduce `BlockBasedTableOptions::cache_usage_options` and use that to replace `BlockBasedTableOptions::reserve_table_builder_memory` and `BlockBasedTableOptions::reserve_table_reader_memory`.
|
||||
* Changed `GetUniqueIdFromTableProperties` to return a 128-bit unique identifier, which will be the standard size now. The old functionality (192-bit) is available from `GetExtendedUniqueIdFromTableProperties`. Both functions are no longer "experimental" and are ready for production use.
|
||||
* In IOOptions, mark `prio` as deprecated for future removal.
|
||||
* In `file_system.h`, mark `IOPriority` as deprecated for future removal.
|
||||
* Add an option, `CompressionOptions::use_zstd_dict_trainer`, to indicate whether zstd dictionary trainer should be used for generating zstd compression dictionaries. The default value of this option is true for backward compatibility. When this option is set to false, zstd API `ZDICT_finalizeDictionary` is used to generate compression dictionaries.
|
||||
* Seek API which positions itself every LevelIterator on the correct data block in the correct SST file which can be parallelized if ReadOptions.async_io option is enabled.
|
||||
* Add new stat number_async_seek in PerfContext that indicates number of async calls made by seek to prefetch data.
|
||||
|
||||
## 7.2.1 (04/26/2022)
|
||||
### Bug Fixes
|
||||
* Fixed a bug where RocksDB could corrupt DBs with `avoid_flush_during_recovery == true` by removing valid WALs, leading to `Status::Corruption` with message like "SST file is ahead of WALs" when attempting to reopen.
|
||||
* RocksDB calls FileSystem::Poll API during FilePrefetchBuffer destruction which impacts performance as it waits for read requets completion which is not needed anymore. Calling FileSystem::AbortIO to abort those requests instead fixes that performance issue.
|
||||
* Fixed unnecessary block cache contention when queries within a MultiGet batch and across parallel batches access the same data block, which previously could cause severely degraded performance in this unusual case. (In more typical MultiGet cases, this fix is expected to yield a small or negligible performance improvement.)
|
||||
|
||||
### Behavior changes
|
||||
* Enforce the existing contract of SingleDelete so that SingleDelete cannot be mixed with Delete because it leads to undefined behavior. Fix a number of unit tests that violate the contract but happen to pass.
|
||||
* ldb `--try_load_options` default to true if `--db` is specified and not creating a new DB, the user can still explicitly disable that by `--try_load_options=false` (or explicitly enable that by `--try_load_options`).
|
||||
* During Flush write or Compaction write/read, the WriteController is used to determine whether DB writes are stalled or slowed down. The priority (Env::IOPriority) can then be determined accordingly and be passed in IOOptions to the file system.
|
||||
|
||||
|
||||
## 7.2.0 (04/15/2022)
|
||||
### Bug Fixes
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
BASH_EXISTS := $(shell which bash)
|
||||
SHELL := $(shell which bash)
|
||||
include common.mk
|
||||
include python.mk
|
||||
|
||||
CLEAN_FILES = # deliberately empty, so we can append below.
|
||||
CFLAGS += ${EXTRA_CFLAGS}
|
||||
@@ -136,13 +136,6 @@ CXXFLAGS += $(PLATFORM_SHARED_CFLAGS) -DROCKSDB_DLL
|
||||
CFLAGS += $(PLATFORM_SHARED_CFLAGS) -DROCKSDB_DLL
|
||||
endif
|
||||
|
||||
ifeq ($(USE_COROUTINES), 1)
|
||||
USE_FOLLY = 1
|
||||
OPT += -DUSE_COROUTINES
|
||||
ROCKSDB_CXX_STANDARD = c++2a
|
||||
USE_RTTI = 1
|
||||
endif
|
||||
|
||||
# if we're compiling for release, compile without debug code (-DNDEBUG)
|
||||
ifeq ($(DEBUG_LEVEL),0)
|
||||
OPT += -DNDEBUG
|
||||
@@ -233,7 +226,6 @@ dummy := $(shell (export ROCKSDB_ROOT="$(CURDIR)"; \
|
||||
export ROCKSDB_NO_FBCODE="$(ROCKSDB_NO_FBCODE)"; \
|
||||
export USE_CLANG="$(USE_CLANG)"; \
|
||||
export LIB_MODE="$(LIB_MODE)"; \
|
||||
export ROCKSDB_CXX_STANDARD="$(ROCKSDB_CXX_STANDARD)"; \
|
||||
"$(CURDIR)/build_tools/build_detect_platform" "$(CURDIR)/make_config.mk"))
|
||||
# this file is generated by the previous line to set build flags and sources
|
||||
include make_config.mk
|
||||
@@ -348,8 +340,6 @@ endif
|
||||
# ASAN doesn't work well with jemalloc. If we're compiling with ASAN, we should use regular malloc.
|
||||
ifdef COMPILE_WITH_ASAN
|
||||
DISABLE_JEMALLOC=1
|
||||
ASAN_OPTIONS?=detect_stack_use_after_return=1
|
||||
export ASAN_OPTIONS
|
||||
EXEC_LDFLAGS += -fsanitize=address
|
||||
PLATFORM_CCFLAGS += -fsanitize=address
|
||||
PLATFORM_CXXFLAGS += -fsanitize=address
|
||||
@@ -606,6 +596,9 @@ am__v_CCH_1 =
|
||||
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')
|
||||
endif
|
||||
ifdef ASSERT_STATUS_CHECKED
|
||||
# TODO: finish fixing all tests to pass this check
|
||||
TESTS_FAILING_ASC = \
|
||||
@@ -640,6 +633,7 @@ TESTS_PLATFORM_DEPENDENT := \
|
||||
db_basic_test \
|
||||
db_blob_basic_test \
|
||||
db_encryption_test \
|
||||
db_test2 \
|
||||
external_sst_file_basic_test \
|
||||
auto_roll_logger_test \
|
||||
bloom_test \
|
||||
@@ -661,6 +655,7 @@ TESTS_PLATFORM_DEPENDENT := \
|
||||
rate_limiter_test \
|
||||
perf_context_test \
|
||||
iostats_context_test \
|
||||
db_wal_test \
|
||||
|
||||
# Sort ROCKSDBTESTS_SUBSET for filtering, except db_test is special (expensive)
|
||||
# so is placed first (out-of-order)
|
||||
@@ -801,10 +796,17 @@ $(SHARED4): $(LIB_OBJECTS)
|
||||
$(AM_V_CCLD) $(CXX) $(PLATFORM_SHARED_LDFLAGS)$(SHARED3) $(LIB_OBJECTS) $(LDFLAGS) -o $@
|
||||
endif # PLATFORM_SHARED_EXT
|
||||
|
||||
.PHONY: check clean coverage ldb_tests package dbg gen-pc build_size \
|
||||
release tags tags0 valgrind_check format static_lib shared_lib all \
|
||||
rocksdbjavastatic rocksdbjava install install-static install-shared \
|
||||
uninstall analyze tools tools_lib check-headers checkout_folly
|
||||
.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 checkout_folly \
|
||||
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 \
|
||||
blackbox_crash_test_with_ts whitebox_crash_test_with_ts \
|
||||
blackbox_crash_test_with_multiops_wc_txn \
|
||||
blackbox_crash_test_with_multiops_wp_txn
|
||||
|
||||
|
||||
all: $(LIBRARY) $(BENCHMARKS) tools tools_lib test_libs $(TESTS)
|
||||
|
||||
@@ -841,6 +843,18 @@ coverage: clean
|
||||
# Delete intermediate files
|
||||
$(FIND) . -type f \( -name "*.gcda" -o -name "*.gcno" \) -exec rm -f {} \;
|
||||
|
||||
ifneq (,$(filter check parallel_check,$(MAKECMDGOALS)),)
|
||||
# Use /dev/shm if it has the sticky bit set (otherwise, /tmp),
|
||||
# and create a randomly-named rocksdb.XXXX directory therein.
|
||||
# We'll use that directory in the "make check" rules.
|
||||
ifeq ($(TMPD),)
|
||||
TMPDIR := $(shell echo $${TMPDIR:-/tmp})
|
||||
TMPD := $(shell f=/dev/shm; test -k $$f || f=$(TMPDIR); \
|
||||
perl -le 'use File::Temp "tempdir";' \
|
||||
-e 'print tempdir("'$$f'/rocksdb.XXXX", CLEANUP => 0)')
|
||||
endif
|
||||
endif
|
||||
|
||||
# Run all tests in parallel, accumulating per-test logs in t/log-*.
|
||||
#
|
||||
# Each t/run-* file is a tiny generated bourne shell script that invokes one of
|
||||
@@ -880,7 +894,7 @@ $(parallel_tests):
|
||||
TEST_SCRIPT=t/run-$$TEST_BINARY-$${TEST_NAME//\//-}; \
|
||||
printf '%s\n' \
|
||||
'#!/bin/sh' \
|
||||
"d=\$(TEST_TMPDIR)$$TEST_SCRIPT" \
|
||||
"d=\$(TMPD)$$TEST_SCRIPT" \
|
||||
'mkdir -p $$d' \
|
||||
"TEST_TMPDIR=\$$d $(DRIVER) ./$$TEST_BINARY --gtest_filter=$$TEST_NAME" \
|
||||
> $$TEST_SCRIPT; \
|
||||
@@ -940,6 +954,7 @@ endif
|
||||
|
||||
.PHONY: check_0
|
||||
check_0:
|
||||
$(AM_V_GEN)export TEST_TMPDIR=$(TMPD); \
|
||||
printf '%s\n' '' \
|
||||
'To monitor subtest <duration,pass/fail,name>,' \
|
||||
' run "make watch-log" in a separate window' ''; \
|
||||
@@ -950,8 +965,7 @@ check_0:
|
||||
| $(prioritize_long_running_tests) \
|
||||
| grep -E '$(tests-regexp)' \
|
||||
| grep -E -v '$(EXCLUDE_TESTS_REGEX)' \
|
||||
| build_tools/gnu_parallel -j$(J) --plain --joblog=LOG --eta --gnu \
|
||||
--tmpdir=$(TEST_TMPDIR) '{} $(parallel_redir)' ; \
|
||||
| build_tools/gnu_parallel -j$(J) --plain --joblog=LOG --eta --gnu '{} $(parallel_redir)' ; \
|
||||
parallel_retcode=$$? ; \
|
||||
awk '{ if ($$7 != 0 || $$8 != 0) { if ($$7 == "Exitval") { h = $$0; } else { if (!f) print h; print; f = 1 } } } END { if(f) exit 1; }' < LOG ; \
|
||||
awk_retcode=$$?; \
|
||||
@@ -962,6 +976,7 @@ valgrind-exclude-regexp = InlineSkipTest.ConcurrentInsert|TransactionStressTest.
|
||||
.PHONY: valgrind_check_0
|
||||
valgrind_check_0: test_log_prefix := valgrind_
|
||||
valgrind_check_0:
|
||||
$(AM_V_GEN)export TEST_TMPDIR=$(TMPD); \
|
||||
printf '%s\n' '' \
|
||||
'To monitor subtest <duration,pass/fail,name>,' \
|
||||
' run "make watch-log" in a separate window' ''; \
|
||||
@@ -973,11 +988,10 @@ valgrind_check_0:
|
||||
| grep -E '$(tests-regexp)' \
|
||||
| grep -E -v '$(valgrind-exclude-regexp)' \
|
||||
| build_tools/gnu_parallel -j$(J) --plain --joblog=LOG --eta --gnu \
|
||||
--tmpdir=$(TEST_TMPDIR) \
|
||||
'(if [[ "{}" == "./"* ]] ; then $(DRIVER) {}; else {}; fi) \
|
||||
'(if [[ "{}" == "./"* ]] ; then $(DRIVER) {}; else {}; fi) \
|
||||
$(parallel_redir)' \
|
||||
|
||||
CLEAN_FILES += t LOG $(TEST_TMPDIR)
|
||||
CLEAN_FILES += t LOG $(TMPD)
|
||||
|
||||
# When running parallel "make check", you can monitor its progress
|
||||
# from another window.
|
||||
@@ -1000,12 +1014,12 @@ check: all
|
||||
&& (build_tools/gnu_parallel --gnu --help 2>/dev/null) | \
|
||||
grep -q 'GNU Parallel'; \
|
||||
then \
|
||||
$(MAKE) T="$$t" check_0; \
|
||||
$(MAKE) T="$$t" TMPD=$(TMPD) check_0; \
|
||||
else \
|
||||
for t in $(TESTS); do \
|
||||
echo "===== Running $$t (`date`)"; ./$$t || exit 1; done; \
|
||||
fi
|
||||
rm -rf $(TEST_TMPDIR)
|
||||
rm -rf $(TMPD)
|
||||
ifneq ($(PLATFORM), OS_AIX)
|
||||
$(PYTHON) tools/check_all_python.py
|
||||
ifeq ($(filter -DROCKSDB_LITE,$(OPT)),)
|
||||
@@ -1032,31 +1046,31 @@ ldb_tests: ldb
|
||||
include crash_test.mk
|
||||
|
||||
asan_check: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) check -j32
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) check -j32
|
||||
$(MAKE) clean
|
||||
|
||||
asan_crash_test: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) crash_test
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) crash_test
|
||||
$(MAKE) clean
|
||||
|
||||
whitebox_asan_crash_test: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) whitebox_crash_test
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) whitebox_crash_test
|
||||
$(MAKE) clean
|
||||
|
||||
blackbox_asan_crash_test: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) blackbox_crash_test
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) blackbox_crash_test
|
||||
$(MAKE) clean
|
||||
|
||||
asan_crash_test_with_atomic_flush: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_atomic_flush
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_atomic_flush
|
||||
$(MAKE) clean
|
||||
|
||||
asan_crash_test_with_txn: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_txn
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_txn
|
||||
$(MAKE) clean
|
||||
|
||||
asan_crash_test_with_best_efforts_recovery: clean
|
||||
COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_best_efforts_recovery
|
||||
ASAN_OPTIONS=detect_stack_use_after_return=1 COMPILE_WITH_ASAN=1 $(MAKE) crash_test_with_best_efforts_recovery
|
||||
$(MAKE) clean
|
||||
|
||||
ubsan_check: clean
|
||||
@@ -1102,11 +1116,11 @@ valgrind_test_some:
|
||||
valgrind_check: $(TESTS)
|
||||
$(MAKE) DRIVER="$(VALGRIND_VER) $(VALGRIND_OPTS)" gen_parallel_tests
|
||||
$(AM_V_GEN)if test "$(J)" != 1 \
|
||||
&& (build_tools/gnu_parallel --gnu --help 2>/dev/null) | \
|
||||
&& (build_tools/gnu_parallel --gnu --help 2>/dev/null) | \
|
||||
grep -q 'GNU Parallel'; \
|
||||
then \
|
||||
$(MAKE) \
|
||||
DRIVER="$(VALGRIND_VER) $(VALGRIND_OPTS)" valgrind_check_0; \
|
||||
$(MAKE) TMPD=$(TMPD) \
|
||||
DRIVER="$(VALGRIND_VER) $(VALGRIND_OPTS)" valgrind_check_0; \
|
||||
else \
|
||||
for t in $(filter-out %skiplist_test options_settable_test,$(TESTS)); do \
|
||||
$(VALGRIND_VER) $(VALGRIND_OPTS) ./$$t; \
|
||||
@@ -1126,6 +1140,27 @@ valgrind_check_some: $(ROCKSDBTESTS_SUBSET)
|
||||
fi; \
|
||||
done
|
||||
|
||||
ifneq ($(PAR_TEST),)
|
||||
parloop:
|
||||
ret_bad=0; \
|
||||
for t in $(PAR_TEST); do \
|
||||
echo "===== Running $$t in parallel $(NUM_PAR) (`date`)";\
|
||||
if [ $(db_test) -eq 1 ]; then \
|
||||
seq $(J) | v="$$t" build_tools/gnu_parallel --gnu --plain 's=$(TMPD)/rdb-{}; export TEST_TMPDIR=$$s;' \
|
||||
'timeout 2m ./db_test --gtest_filter=$$v >> $$s/log-{} 2>1'; \
|
||||
else\
|
||||
seq $(J) | v="./$$t" build_tools/gnu_parallel --gnu --plain 's=$(TMPD)/rdb-{};' \
|
||||
'export TEST_TMPDIR=$$s; timeout 10m $$v >> $$s/log-{} 2>1'; \
|
||||
fi; \
|
||||
ret_code=$$?; \
|
||||
if [ $$ret_code -ne 0 ]; then \
|
||||
ret_bad=$$ret_code; \
|
||||
echo $$t exited with $$ret_code; \
|
||||
fi; \
|
||||
done; \
|
||||
exit $$ret_bad;
|
||||
endif
|
||||
|
||||
test_names = \
|
||||
./db_test --gtest_list_tests \
|
||||
| perl -n \
|
||||
@@ -1133,6 +1168,24 @@ test_names = \
|
||||
-e '/^(\s*)(\S+)/; !$$1 and do {$$p=$$2; break};' \
|
||||
-e 'print qq! $$p$$2!'
|
||||
|
||||
parallel_check: $(TESTS)
|
||||
$(AM_V_GEN)if test "$(J)" > 1 \
|
||||
&& (build_tools/gnu_parallel --gnu --help 2>/dev/null) | \
|
||||
grep -q 'GNU Parallel'; \
|
||||
then \
|
||||
echo Running in parallel $(J); \
|
||||
else \
|
||||
echo "Need to have GNU Parallel and J > 1"; exit 1; \
|
||||
fi; \
|
||||
ret_bad=0; \
|
||||
echo $(J);\
|
||||
echo Test Dir: $(TMPD); \
|
||||
seq $(J) | build_tools/gnu_parallel --gnu --plain 's=$(TMPD)/rdb-{}; rm -rf $$s; mkdir $$s'; \
|
||||
$(MAKE) PAR_TEST="$(shell $(test_names))" TMPD=$(TMPD) \
|
||||
J=$(J) db_test=1 parloop; \
|
||||
$(MAKE) PAR_TEST="$(filter-out db_test, $(TESTS))" \
|
||||
TMPD=$(TMPD) J=$(J) db_test=0 parloop;
|
||||
|
||||
analyze: clean
|
||||
USE_CLANG=1 $(MAKE) analyze_incremental
|
||||
|
||||
@@ -1378,9 +1431,6 @@ db_blob_basic_test: $(OBJ_DIR)/db/blob/db_blob_basic_test.o $(TEST_LIBRARY) $(LI
|
||||
db_blob_compaction_test: $(OBJ_DIR)/db/blob/db_blob_compaction_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_readonly_with_timestamp_test: $(OBJ_DIR)/db/db_readonly_with_timestamp_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
db_with_timestamp_basic_test: $(OBJ_DIR)/db/db_with_timestamp_basic_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -1876,7 +1926,7 @@ testutil_test: $(OBJ_DIR)/test_util/testutil_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
io_tracer_test: $(OBJ_DIR)/trace_replay/io_tracer_test.o $(OBJ_DIR)/trace_replay/io_tracer.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
prefetch_test: $(OBJ_DIR)/file/prefetch_test.o $(OBJ_DIR)/tools/io_tracer_parser_tool.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
prefetch_test: $(OBJ_DIR)/file/prefetch_test.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
$(AM_LINK)
|
||||
|
||||
io_tracer_parser_test: $(OBJ_DIR)/tools/io_tracer_parser_test.o $(OBJ_DIR)/tools/io_tracer_parser_tool.o $(TEST_LIBRARY) $(LIBRARY)
|
||||
@@ -2064,7 +2114,6 @@ ifeq ($(PLATFORM), OS_OPENBSD)
|
||||
ROCKSDBJNILIB = librocksdbjni-openbsd$(ARCH).so
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_JAVA_VERSION)-openbsd$(ARCH).jar
|
||||
endif
|
||||
export SHA256_CMD
|
||||
|
||||
zlib-$(ZLIB_VER).tar.gz:
|
||||
curl --fail --output zlib-$(ZLIB_VER).tar.gz --location ${ZLIB_DOWNLOAD_BASE}/zlib-$(ZLIB_VER).tar.gz
|
||||
@@ -2197,7 +2246,7 @@ JAR_CMD := jar
|
||||
endif
|
||||
endif
|
||||
rocksdbjavastatic_javalib:
|
||||
cd java; $(MAKE) javalib
|
||||
cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) javalib
|
||||
rm -f java/target/$(ROCKSDBJNILIB)
|
||||
$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC \
|
||||
-o ./java/target/$(ROCKSDBJNILIB) $(ALL_JNI_NATIVE_SOURCES) \
|
||||
@@ -2311,7 +2360,7 @@ rocksdbjava: $(LIB_OBJECTS)
|
||||
ifeq ($(JAVA_HOME),)
|
||||
$(error JAVA_HOME is not set)
|
||||
endif
|
||||
$(AM_V_GEN)cd java; $(MAKE) javalib;
|
||||
$(AM_V_GEN)cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) javalib;
|
||||
$(AM_V_at)rm -f ./java/target/$(ROCKSDBJNILIB)
|
||||
$(AM_V_at)$(CXX) $(CXXFLAGS) -I./java/. -I./java/rocksjni $(JAVA_INCLUDE) $(ROCKSDB_PLUGIN_JNI_CXX_INCLUDEFLAGS) -shared -fPIC -o ./java/target/$(ROCKSDBJNILIB) $(ALL_JNI_NATIVE_SOURCES) $(LIB_OBJECTS) $(JAVA_LDFLAGS) $(COVERAGEFLAGS)
|
||||
$(AM_V_at)cd java; $(JAR_CMD) -cf target/$(ROCKSDB_JAR) HISTORY*.md
|
||||
@@ -2323,13 +2372,14 @@ jclean:
|
||||
cd java;$(MAKE) clean;
|
||||
|
||||
jtest_compile: rocksdbjava
|
||||
cd java;$(MAKE) java_test
|
||||
cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) java_test
|
||||
|
||||
jtest_run:
|
||||
cd java;$(MAKE) run_test
|
||||
|
||||
jtest: rocksdbjava
|
||||
cd java;$(MAKE) sample test
|
||||
cd java;$(MAKE) sample; SHA256_CMD='$(SHA256_CMD)' $(MAKE) test;
|
||||
$(PYTHON) tools/check_all_python.py # TODO peterd: find a better place for this check in CI targets
|
||||
|
||||
jdb_bench:
|
||||
cd java;$(MAKE) db_bench;
|
||||
@@ -2355,38 +2405,6 @@ checkout_folly:
|
||||
@# NOTE: this hack is not needed if using FBCODE compiler config
|
||||
perl -pi -e 's/^(#include <boost)/\/\/$$1/' third-party/folly/folly/functional/Invoke.h
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build size testing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
REPORT_BUILD_STATISTIC?=echo STATISTIC:
|
||||
|
||||
build_size:
|
||||
# === normal build, static ===
|
||||
$(MAKE) clean
|
||||
$(MAKE) static_lib
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.static_lib $$(stat --printf="%s" librocksdb.a)
|
||||
strip librocksdb.a
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.static_lib_stripped $$(stat --printf="%s" librocksdb.a)
|
||||
# === normal build, shared ===
|
||||
$(MAKE) clean
|
||||
$(MAKE) shared_lib
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.shared_lib $$(stat --printf="%s" `readlink -f librocksdb.so`)
|
||||
strip `readlink -f librocksdb.so`
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.shared_lib_stripped $$(stat --printf="%s" `readlink -f librocksdb.so`)
|
||||
# === lite build, static ===
|
||||
$(MAKE) clean
|
||||
$(MAKE) LITE=1 static_lib
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.static_lib_lite $$(stat --printf="%s" librocksdb.a)
|
||||
strip librocksdb.a
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.static_lib_lite_stripped $$(stat --printf="%s" librocksdb.a)
|
||||
# === lite build, shared ===
|
||||
$(MAKE) clean
|
||||
$(MAKE) LITE=1 shared_lib
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.shared_lib_lite $$(stat --printf="%s" `readlink -f librocksdb.so`)
|
||||
strip `readlink -f librocksdb.so`
|
||||
$(REPORT_BUILD_STATISTIC) rocksdb.build_size.shared_lib_lite_stripped $$(stat --printf="%s" `readlink -f librocksdb.so`)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Platform-specific compilation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -4,4 +4,3 @@ This is the list of all known third-party plugins for RocksDB. If something is m
|
||||
* [HDFS](https://github.com/riversand963/rocksdb-hdfs-env): an Env used for interacting with HDFS. Migrated from main RocksDB repo
|
||||
* [ZenFS](https://github.com/westerndigitalcorporation/zenfs): a file system for zoned block devices
|
||||
* [RADOS](https://github.com/riversand963/rocksdb-rados-env): an Env used for interacting with RADOS. Migrated from RocksDB main repo.
|
||||
* [PMEM](https://github.com/pmem/pmem-rocksdb-plugin): a collection of plugins to enable Persistent Memory on RocksDB.
|
||||
@@ -15,7 +15,6 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"cache/cache_reservation_manager.cc",
|
||||
"cache/clock_cache.cc",
|
||||
"cache/compressed_secondary_cache.cc",
|
||||
"cache/fast_lru_cache.cc",
|
||||
"cache/lru_cache.cc",
|
||||
"cache/sharded_cache.cc",
|
||||
"db/arena_wrapped_db_iter.cc",
|
||||
@@ -224,9 +223,7 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"trace_replay/trace_record_handler.cc",
|
||||
"trace_replay/trace_record_result.cc",
|
||||
"trace_replay/trace_replay.cc",
|
||||
"util/async_file_reader.cc",
|
||||
"util/build_version.cc",
|
||||
"util/cleanable.cc",
|
||||
"util/coding.cc",
|
||||
"util/compaction_job_stats_impl.cc",
|
||||
"util/comparator.cc",
|
||||
@@ -328,13 +325,7 @@ cpp_library_wrapper(name="rocksdb_lib", srcs=[
|
||||
"utilities/wal_filter.cc",
|
||||
"utilities/write_batch_with_index/write_batch_with_index.cc",
|
||||
"utilities/write_batch_with_index/write_batch_with_index_internal.cc",
|
||||
], deps=[
|
||||
"//folly/container:f14_hash",
|
||||
"//folly/experimental/coro:blocking_wait",
|
||||
"//folly/experimental/coro:collect",
|
||||
"//folly/experimental/coro:coroutine",
|
||||
"//folly/experimental/coro:task",
|
||||
], headers=None, link_whole=False, extra_test_libs=False)
|
||||
], deps=["//folly/container:f14_hash"], headers=None, link_whole=False, extra_test_libs=False)
|
||||
|
||||
cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[
|
||||
"cache/cache.cc",
|
||||
@@ -343,7 +334,6 @@ cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[
|
||||
"cache/cache_reservation_manager.cc",
|
||||
"cache/clock_cache.cc",
|
||||
"cache/compressed_secondary_cache.cc",
|
||||
"cache/fast_lru_cache.cc",
|
||||
"cache/lru_cache.cc",
|
||||
"cache/sharded_cache.cc",
|
||||
"db/arena_wrapped_db_iter.cc",
|
||||
@@ -552,9 +542,7 @@ cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[
|
||||
"trace_replay/trace_record_handler.cc",
|
||||
"trace_replay/trace_record_result.cc",
|
||||
"trace_replay/trace_replay.cc",
|
||||
"util/async_file_reader.cc",
|
||||
"util/build_version.cc",
|
||||
"util/cleanable.cc",
|
||||
"util/coding.cc",
|
||||
"util/compaction_job_stats_impl.cc",
|
||||
"util/comparator.cc",
|
||||
@@ -656,17 +644,10 @@ cpp_library_wrapper(name="rocksdb_whole_archive_lib", srcs=[
|
||||
"utilities/wal_filter.cc",
|
||||
"utilities/write_batch_with_index/write_batch_with_index.cc",
|
||||
"utilities/write_batch_with_index/write_batch_with_index_internal.cc",
|
||||
], deps=[
|
||||
"//folly/container:f14_hash",
|
||||
"//folly/experimental/coro:blocking_wait",
|
||||
"//folly/experimental/coro:collect",
|
||||
"//folly/experimental/coro:coroutine",
|
||||
"//folly/experimental/coro:task",
|
||||
], headers=None, link_whole=True, extra_test_libs=False)
|
||||
], deps=["//folly/container:f14_hash"], headers=None, link_whole=True, extra_test_libs=False)
|
||||
|
||||
cpp_library_wrapper(name="rocksdb_test_lib", srcs=[
|
||||
"db/db_test_util.cc",
|
||||
"db/db_with_timestamp_test_util.cc",
|
||||
"table/mock_table.cc",
|
||||
"test_util/mock_time_env.cc",
|
||||
"test_util/testharness.cc",
|
||||
@@ -5176,12 +5157,6 @@ cpp_unittest_wrapper(name="db_rate_limiter_test",
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="db_readonly_with_timestamp_test",
|
||||
srcs=["db/db_readonly_with_timestamp_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
extra_compiler_flags=[])
|
||||
|
||||
|
||||
cpp_unittest_wrapper(name="db_secondary_test",
|
||||
srcs=["db/db_secondary_test.cc"],
|
||||
deps=[":rocksdb_test_lib"],
|
||||
|
||||
@@ -145,12 +145,7 @@ def generate_targets(repo_path, deps_map):
|
||||
# always add range_tree, it's only excluded on ppc64, which we don't use internally
|
||||
src_mk["RANGE_TREE_SOURCES"] +
|
||||
src_mk["TOOL_LIB_SOURCES"],
|
||||
deps=[
|
||||
"//folly/container:f14_hash",
|
||||
"//folly/experimental/coro:blocking_wait",
|
||||
"//folly/experimental/coro:collect",
|
||||
"//folly/experimental/coro:coroutine",
|
||||
"//folly/experimental/coro:task"])
|
||||
deps=["//folly/container:f14_hash"])
|
||||
# rocksdb_whole_archive_lib
|
||||
TARGETS.add_library(
|
||||
"rocksdb_whole_archive_lib",
|
||||
@@ -158,12 +153,7 @@ def generate_targets(repo_path, deps_map):
|
||||
# always add range_tree, it's only excluded on ppc64, which we don't use internally
|
||||
src_mk["RANGE_TREE_SOURCES"] +
|
||||
src_mk["TOOL_LIB_SOURCES"],
|
||||
deps=[
|
||||
"//folly/container:f14_hash",
|
||||
"//folly/experimental/coro:blocking_wait",
|
||||
"//folly/experimental/coro:collect",
|
||||
"//folly/experimental/coro:coroutine",
|
||||
"//folly/experimental/coro:task"],
|
||||
deps=["//folly/container:f14_hash"],
|
||||
headers=None,
|
||||
extra_external_deps="",
|
||||
link_whole=True)
|
||||
|
||||
@@ -469,7 +469,7 @@ EOF
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_MEMKIND; then
|
||||
# Test whether memkind library is installed
|
||||
$CXX $PLATFORM_CXXFLAGS $LDFLAGS -x c++ - -o test.o -lmemkind 2>/dev/null <<EOF
|
||||
$CXX $PLATFORM_CXXFLAGS $COMMON_FLAGS -lmemkind -x c++ - -o test.o 2>/dev/null <<EOF
|
||||
#include <memkind.h>
|
||||
int main() {
|
||||
memkind_malloc(MEMKIND_DAX_KMEM, 1024);
|
||||
@@ -800,6 +800,9 @@ if [ "$?" = 0 ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DHAVE_UINT128_EXTENSION"
|
||||
fi
|
||||
|
||||
# thread_local is part of C++11 and later (TODO: clean up this define)
|
||||
COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_SUPPORT_THREAD_LOCAL"
|
||||
|
||||
if [ "$FBCODE_BUILD" != "true" -a "$PLATFORM" = OS_LINUX ]; then
|
||||
$CXX $COMMON_FLAGS $PLATFORM_SHARED_CFLAGS -x c++ -c - -o test_dl.o 2>/dev/null <<EOF
|
||||
void dummy_func() {}
|
||||
|
||||
@@ -20,7 +20,3 @@ VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/6ae525939ad02e5e676855082fbbc7828d
|
||||
LUA_BASE=/mnt/gvfs/third-party2/lua/162efd9561a3d21f6869f4814011e9cf1b3ff4dc/5.3.4/platform009/a6271c4
|
||||
BENCHMARK_BASE=/mnt/gvfs/third-party2/benchmark/30bf49ad6414325e17f3425b0edcb64239427ae3/1.6.1/platform009/7f3b187
|
||||
BOOST_BASE=/mnt/gvfs/third-party2/boost/201b7d74941e54b436dfa364a063aa6d2cd7de4c/1.69.0/platform009/8a7ffdf
|
||||
GLOG_BASE=/mnt/gvfs/third-party2/glog/32d751bd5673375b438158717ab6a57c1cc57e3d/0.3.2_fb/platform009/10a364d/
|
||||
FMT_BASE=/mnt/gvfs/third-party2/fmt/ce0c25f67165f4d2c22a29b8ef50f5600d7873ca/6.1.1/platform009/7f3b187/
|
||||
DBL_CONV_BASE=/mnt/gvfs/third-party2/double_conversion/109b3d9696d71f1048678cd7da1e22505470543d/20141126/platform009/7f3b187/
|
||||
LIBEVENT_BASE=/mnt/gvfs/third-party2/libevent/4a4d3a79a76c2439b6bd471bf3586b3481dde75e/1.4.14b_hphp/platform009/7f3b187/
|
||||
@@ -21,48 +21,38 @@ LIBGCC_LIBS=" -L $LIBGCC_BASE/lib"
|
||||
GLIBC_INCLUDE="$GLIBC_BASE/include"
|
||||
GLIBC_LIBS=" -L $GLIBC_BASE/lib"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_SNAPPY; then
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy.a"
|
||||
else
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy.a"
|
||||
else
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
|
||||
if test -z $PIC_BUILD; then
|
||||
if ! test $ROCKSDB_DISABLE_ZLIB; then
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
fi
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_BZIP; then
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
fi
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_LZ4; then
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
fi
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZSTD; then
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd.a"
|
||||
else
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DZSTD -DZSTD_STATIC_LINKING_ONLY"
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd.a"
|
||||
else
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DZSTD -DZSTD_STATIC_LINKING_ONLY"
|
||||
|
||||
# location of gflags headers and libraries
|
||||
GFLAGS_INCLUDE=" -I $GFLAGS_BASE/include/"
|
||||
@@ -147,7 +137,7 @@ else
|
||||
fi
|
||||
|
||||
CFLAGS+=" $DEPS_INCLUDE"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DHAVE_SSE42"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_SUPPORT_THREAD_LOCAL -DHAVE_SSE42"
|
||||
CXXFLAGS+=" $CFLAGS"
|
||||
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS"
|
||||
|
||||
@@ -14,7 +14,7 @@ source "$BASEDIR/dependencies_platform009.sh"
|
||||
CFLAGS=""
|
||||
|
||||
# libgcc
|
||||
LIBGCC_INCLUDE="$LIBGCC_BASE/include/c++/9.3.0 -I $LIBGCC_BASE/include/c++/9.3.0/backward"
|
||||
LIBGCC_INCLUDE="$LIBGCC_BASE/include/c++/9.3.0"
|
||||
LIBGCC_LIBS=" -L $LIBGCC_BASE/lib"
|
||||
|
||||
# glibc
|
||||
@@ -27,38 +27,28 @@ else
|
||||
MAYBE_PIC=_pic
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_SNAPPY; then
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
fi
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZLIB; then
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
fi
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_BZIP; then
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
fi
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_LZ4; then
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
fi
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZSTD; then
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZSTD"
|
||||
fi
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZSTD"
|
||||
|
||||
# location of gflags headers and libraries
|
||||
GFLAGS_INCLUDE=" -I $GFLAGS_BASE/include/"
|
||||
@@ -70,18 +60,6 @@ BENCHMARK_LIBS=" $BENCHMARK_BASE/lib/libbenchmark${MAYBE_PIC}.a"
|
||||
|
||||
BOOST_INCLUDE=" -I $BOOST_BASE/include/"
|
||||
|
||||
GLOG_INCLUDE=" -I $GLOG_BASE/include/"
|
||||
GLOG_LIBS=" $GLOG_BASE/lib/libglog${MAYBE_PIC}.a"
|
||||
|
||||
FMT_INCLUDE=" -I $FMT_BASE/include/"
|
||||
FMT_LIBS=" $FMT_BASE/lib/libfmt${MAYBE_PIC}.a"
|
||||
|
||||
DBL_CONV_INCLUDE=" -I $DBL_CONV_BASE/include/"
|
||||
DBL_CONV_LIBS=" $DBL_CONV_BASE/lib/libdouble-conversion${MAYBE_PIC}.a"
|
||||
|
||||
LIBEVENT_INCLUDE=" -I $LIBEVENT_BASE/include/"
|
||||
LIBEVENT_LIBS=" $LIBEVENT_BASE/lib/libevent${MAYBE_PIC}.a"
|
||||
|
||||
# location of jemalloc
|
||||
JEMALLOC_INCLUDE=" -I $JEMALLOC_BASE/include/"
|
||||
JEMALLOC_LIB=" $JEMALLOC_BASE/lib/libjemalloc${MAYBE_PIC}.a"
|
||||
@@ -113,7 +91,7 @@ BINUTILS="$BINUTILS_BASE/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
AS="$BINUTILS/as"
|
||||
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE $LIBURING_INCLUDE $BENCHMARK_INCLUDE $BOOST_INCLUDE $GLOG_INCLUDE $FMT_INCLUDE $DBL_CONV_INCLUDE $LIBEVENT_INCLUDE"
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE $LIBURING_INCLUDE $BENCHMARK_INCLUDE $BOOST_INCLUDE"
|
||||
|
||||
STDLIBS="-L $GCC_BASE/lib64"
|
||||
|
||||
@@ -156,7 +134,7 @@ else
|
||||
fi
|
||||
|
||||
CFLAGS+=" $DEPS_INCLUDE"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DHAVE_SSE42 -DROCKSDB_IOURING_PRESENT"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_SUPPORT_THREAD_LOCAL -DHAVE_SSE42 -DROCKSDB_IOURING_PRESENT"
|
||||
CXXFLAGS+=" $CFLAGS"
|
||||
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS $LIBURING_LIBS $BENCHMARK_LIBS"
|
||||
|
||||
@@ -29,38 +29,28 @@ else
|
||||
MAYBE_PIC=_pic
|
||||
fi
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_SNAPPY; then
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
fi
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZLIB; then
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
fi
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_BZIP; then
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
fi
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_LZ4; then
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
fi
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
|
||||
if ! test $ROCKSDB_DISABLE_ZSTD; then
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZSTD"
|
||||
fi
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd${MAYBE_PIC}.a"
|
||||
CFLAGS+=" -DZSTD"
|
||||
|
||||
# location of gflags headers and libraries
|
||||
GFLAGS_INCLUDE=" -I $GFLAGS_BASE/include/"
|
||||
@@ -118,19 +108,10 @@ if [ -z "$USE_CLANG" ]; then
|
||||
CXX="$GCC_BASE/bin/g++"
|
||||
AR="$GCC_BASE/bin/gcc-ar"
|
||||
|
||||
CFLAGS+=" -B$BINUTILS -nostdinc -nostdlib"
|
||||
CFLAGS+=" -I$GCC_BASE/include"
|
||||
CFLAGS+=" -isystem $GCC_BASE/lib/gcc/x86_64-redhat-linux-gnu/11.2.1/include"
|
||||
CFLAGS+=" -isystem $GCC_BASE/lib/gcc/x86_64-redhat-linux-gnu/11.2.1/install-tools/include"
|
||||
CFLAGS+=" -isystem $GCC_BASE/lib/gcc/x86_64-redhat-linux-gnu/11.2.1/include-fixed/"
|
||||
|
||||
CFLAGS+=" -B$BINUTILS"
|
||||
CFLAGS+=" -isystem $LIBGCC_INCLUDE"
|
||||
CFLAGS+=" -isystem $GLIBC_INCLUDE"
|
||||
CFLAGS+=" -I$GLIBC_INCLUDE"
|
||||
CFLAGS+=" -I$LIBGCC_BASE/include"
|
||||
CFLAGS+=" -I$LIBGCC_BASE/include/c++/11.x/"
|
||||
CFLAGS+=" -I$LIBGCC_BASE/include/c++/11.x/x86_64-facebook-linux/"
|
||||
CFLAGS+=" -I$LIBGCC_BASE/include/c++/11.x/backward"
|
||||
CFLAGS+=" -isystem $GLIBC_INCLUDE -I$GLIBC_INCLUDE"
|
||||
JEMALLOC=1
|
||||
else
|
||||
# clang
|
||||
@@ -154,7 +135,7 @@ CFLAGS+=" -isystem $KERNEL_HEADERS_INCLUDE/linux "
|
||||
CFLAGS+=" -isystem $KERNEL_HEADERS_INCLUDE "
|
||||
|
||||
CFLAGS+=" $DEPS_INCLUDE"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DHAVE_SSE42 -DROCKSDB_IOURING_PRESENT"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_SUPPORT_THREAD_LOCAL -DHAVE_SSE42 -DROCKSDB_IOURING_PRESENT"
|
||||
CXXFLAGS+=" $CFLAGS"
|
||||
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS $LIBURING_LIBS $BENCHMARK_LIBS"
|
||||
|
||||
Vendored
+17
-29
@@ -14,9 +14,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cache/clock_cache.h"
|
||||
#include "cache/fast_lru_cache.h"
|
||||
#include "cache/lru_cache.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/coding.h"
|
||||
@@ -41,7 +39,6 @@ static int DecodeValue(void* v) {
|
||||
|
||||
const std::string kLRU = "lru";
|
||||
const std::string kClock = "clock";
|
||||
const std::string kFast = "fast";
|
||||
|
||||
void dumbDeleter(const Slice& /*key*/, void* /*value*/) {}
|
||||
|
||||
@@ -86,9 +83,6 @@ class CacheTest : public testing::TestWithParam<std::string> {
|
||||
if (type == kClock) {
|
||||
return NewClockCache(capacity);
|
||||
}
|
||||
if (type == kFast) {
|
||||
return NewFastLRUCache(capacity);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -109,10 +103,6 @@ class CacheTest : public testing::TestWithParam<std::string> {
|
||||
return NewClockCache(capacity, num_shard_bits, strict_capacity_limit,
|
||||
charge_policy);
|
||||
}
|
||||
if (type == kFast) {
|
||||
return NewFastLRUCache(capacity, num_shard_bits, strict_capacity_limit,
|
||||
charge_policy);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -193,7 +183,7 @@ TEST_P(CacheTest, UsageTest) {
|
||||
|
||||
// make sure the cache will be overloaded
|
||||
for (uint64_t i = 1; i < kCapacity; ++i) {
|
||||
auto key = std::to_string(i);
|
||||
auto key = ToString(i);
|
||||
ASSERT_OK(cache->Insert(key, reinterpret_cast<void*>(value), key.size() + 5,
|
||||
dumbDeleter));
|
||||
ASSERT_OK(precise_cache->Insert(key, reinterpret_cast<void*>(value),
|
||||
@@ -265,7 +255,7 @@ TEST_P(CacheTest, PinnedUsageTest) {
|
||||
|
||||
// check that overloading the cache does not change the pinned usage
|
||||
for (uint64_t i = 1; i < 2 * kCapacity; ++i) {
|
||||
auto key = std::to_string(i);
|
||||
auto key = ToString(i);
|
||||
ASSERT_OK(cache->Insert(key, reinterpret_cast<void*>(value), key.size() + 5,
|
||||
dumbDeleter));
|
||||
ASSERT_OK(precise_cache->Insert(key, reinterpret_cast<void*>(value),
|
||||
@@ -585,7 +575,7 @@ TEST_P(CacheTest, SetCapacity) {
|
||||
std::vector<Cache::Handle*> handles(10);
|
||||
// Insert 5 entries, but not releasing.
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i+1);
|
||||
Status s = cache->Insert(key, new Value(i + 1), 1, &deleter, &handles[i]);
|
||||
ASSERT_TRUE(s.ok());
|
||||
}
|
||||
@@ -600,7 +590,7 @@ TEST_P(CacheTest, SetCapacity) {
|
||||
// then decrease capacity to 7, final capacity should be 7
|
||||
// and usage should be 7
|
||||
for (size_t i = 5; i < 10; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i+1);
|
||||
Status s = cache->Insert(key, new Value(i + 1), 1, &deleter, &handles[i]);
|
||||
ASSERT_TRUE(s.ok());
|
||||
}
|
||||
@@ -631,7 +621,7 @@ TEST_P(LRUCacheTest, SetStrictCapacityLimit) {
|
||||
std::vector<Cache::Handle*> handles(10);
|
||||
Status s;
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i + 1);
|
||||
s = cache->Insert(key, new Value(i + 1), 1, &deleter, &handles[i]);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_NE(nullptr, handles[i]);
|
||||
@@ -655,7 +645,7 @@ TEST_P(LRUCacheTest, SetStrictCapacityLimit) {
|
||||
// test3: init with flag being true.
|
||||
std::shared_ptr<Cache> cache2 = NewCache(5, 0, true);
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i + 1);
|
||||
s = cache2->Insert(key, new Value(i + 1), 1, &deleter, &handles[i]);
|
||||
ASSERT_OK(s);
|
||||
ASSERT_NE(nullptr, handles[i]);
|
||||
@@ -685,14 +675,14 @@ TEST_P(CacheTest, OverCapacity) {
|
||||
|
||||
// Insert n+1 entries, but not releasing.
|
||||
for (size_t i = 0; i < n + 1; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i+1);
|
||||
Status s = cache->Insert(key, new Value(i + 1), 1, &deleter, &handles[i]);
|
||||
ASSERT_TRUE(s.ok());
|
||||
}
|
||||
|
||||
// Guess what's in the cache now?
|
||||
for (size_t i = 0; i < n + 1; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i+1);
|
||||
auto h = cache->Lookup(key);
|
||||
ASSERT_TRUE(h != nullptr);
|
||||
if (h) cache->Release(h);
|
||||
@@ -713,7 +703,7 @@ TEST_P(CacheTest, OverCapacity) {
|
||||
// This is consistent with the LRU policy since the element 0
|
||||
// was released first
|
||||
for (size_t i = 0; i < n + 1; i++) {
|
||||
std::string key = std::to_string(i + 1);
|
||||
std::string key = ToString(i+1);
|
||||
auto h = cache->Lookup(key);
|
||||
if (h) {
|
||||
ASSERT_NE(i, 0U);
|
||||
@@ -754,9 +744,9 @@ TEST_P(CacheTest, ApplyToAllEntriesTest) {
|
||||
std::vector<std::string> callback_state;
|
||||
const auto callback = [&](const Slice& key, void* value, size_t charge,
|
||||
Cache::DeleterFn deleter) {
|
||||
callback_state.push_back(std::to_string(DecodeKey(key)) + "," +
|
||||
std::to_string(DecodeValue(value)) + "," +
|
||||
std::to_string(charge));
|
||||
callback_state.push_back(ToString(DecodeKey(key)) + "," +
|
||||
ToString(DecodeValue(value)) + "," +
|
||||
ToString(charge));
|
||||
assert(deleter == &CacheTest::Deleter);
|
||||
};
|
||||
|
||||
@@ -765,8 +755,8 @@ TEST_P(CacheTest, ApplyToAllEntriesTest) {
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Insert(i, i * 2, i + 1);
|
||||
inserted.push_back(std::to_string(i) + "," + std::to_string(i * 2) + "," +
|
||||
std::to_string(i + 1));
|
||||
inserted.push_back(ToString(i) + "," + ToString(i * 2) + "," +
|
||||
ToString(i + 1));
|
||||
}
|
||||
cache_->ApplyToAllEntries(callback, /*opts*/ {});
|
||||
|
||||
@@ -848,13 +838,11 @@ TEST_P(CacheTest, GetChargeAndDeleter) {
|
||||
std::shared_ptr<Cache> (*new_clock_cache_func)(
|
||||
size_t, int, bool, CacheMetadataChargePolicy) = NewClockCache;
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, CacheTest,
|
||||
testing::Values(kLRU, kClock, kFast));
|
||||
testing::Values(kLRU, kClock));
|
||||
#else
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, CacheTest,
|
||||
testing::Values(kLRU, kFast));
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, CacheTest, testing::Values(kLRU));
|
||||
#endif // SUPPORT_CLOCK_CACHE
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, LRUCacheTest,
|
||||
testing::Values(kLRU, kFast));
|
||||
INSTANTIATE_TEST_CASE_P(CacheTestInstance, LRUCacheTest, testing::Values(kLRU));
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
|
||||
Vendored
-511
@@ -1,511 +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/fast_lru_cache.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#include "monitoring/perf_context_imp.h"
|
||||
#include "monitoring/statistics.h"
|
||||
#include "port/lang.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
namespace fast_lru_cache {
|
||||
|
||||
LRUHandleTable::LRUHandleTable(int max_upper_hash_bits)
|
||||
: length_bits_(/* historical starting size*/ 4),
|
||||
list_(new LRUHandle* [size_t{1} << length_bits_] {}),
|
||||
elems_(0),
|
||||
max_length_bits_(max_upper_hash_bits) {}
|
||||
|
||||
LRUHandleTable::~LRUHandleTable() {
|
||||
ApplyToEntriesRange(
|
||||
[](LRUHandle* h) {
|
||||
if (!h->HasRefs()) {
|
||||
h->Free();
|
||||
}
|
||||
},
|
||||
0, uint32_t{1} << length_bits_);
|
||||
}
|
||||
|
||||
LRUHandle* LRUHandleTable::Lookup(const Slice& key, uint32_t hash) {
|
||||
return *FindPointer(key, hash);
|
||||
}
|
||||
|
||||
LRUHandle* LRUHandleTable::Insert(LRUHandle* h) {
|
||||
LRUHandle** ptr = FindPointer(h->key(), h->hash);
|
||||
LRUHandle* old = *ptr;
|
||||
h->next_hash = (old == nullptr ? nullptr : old->next_hash);
|
||||
*ptr = h;
|
||||
if (old == nullptr) {
|
||||
++elems_;
|
||||
if ((elems_ >> length_bits_) > 0) { // elems_ >= length
|
||||
// Since each cache entry is fairly large, we aim for a small
|
||||
// average linked list length (<= 1).
|
||||
Resize();
|
||||
}
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
LRUHandle* LRUHandleTable::Remove(const Slice& key, uint32_t hash) {
|
||||
LRUHandle** ptr = FindPointer(key, hash);
|
||||
LRUHandle* result = *ptr;
|
||||
if (result != nullptr) {
|
||||
*ptr = result->next_hash;
|
||||
--elems_;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LRUHandle** LRUHandleTable::FindPointer(const Slice& key, uint32_t hash) {
|
||||
LRUHandle** ptr = &list_[hash >> (32 - length_bits_)];
|
||||
while (*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key())) {
|
||||
ptr = &(*ptr)->next_hash;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void LRUHandleTable::Resize() {
|
||||
if (length_bits_ >= max_length_bits_) {
|
||||
// Due to reaching limit of hash information, if we made the table bigger,
|
||||
// we would allocate more addresses but only the same number would be used.
|
||||
return;
|
||||
}
|
||||
if (length_bits_ >= 31) {
|
||||
// Avoid undefined behavior shifting uint32_t by 32.
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t old_length = uint32_t{1} << length_bits_;
|
||||
int new_length_bits = length_bits_ + 1;
|
||||
std::unique_ptr<LRUHandle* []> new_list {
|
||||
new LRUHandle* [size_t{1} << new_length_bits] {}
|
||||
};
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < old_length; i++) {
|
||||
LRUHandle* h = list_[i];
|
||||
while (h != nullptr) {
|
||||
LRUHandle* next = h->next_hash;
|
||||
uint32_t hash = h->hash;
|
||||
LRUHandle** ptr = &new_list[hash >> (32 - new_length_bits)];
|
||||
h->next_hash = *ptr;
|
||||
*ptr = h;
|
||||
h = next;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
assert(elems_ == count);
|
||||
list_ = std::move(new_list);
|
||||
length_bits_ = new_length_bits;
|
||||
}
|
||||
|
||||
LRUCacheShard::LRUCacheShard(size_t capacity, bool strict_capacity_limit,
|
||||
CacheMetadataChargePolicy metadata_charge_policy,
|
||||
int max_upper_hash_bits)
|
||||
: capacity_(0),
|
||||
strict_capacity_limit_(strict_capacity_limit),
|
||||
table_(max_upper_hash_bits),
|
||||
usage_(0),
|
||||
lru_usage_(0) {
|
||||
set_metadata_charge_policy(metadata_charge_policy);
|
||||
// Make empty circular linked list.
|
||||
lru_.next = &lru_;
|
||||
lru_.prev = &lru_;
|
||||
lru_low_pri_ = &lru_;
|
||||
SetCapacity(capacity);
|
||||
}
|
||||
|
||||
void LRUCacheShard::EraseUnRefEntries() {
|
||||
autovector<LRUHandle*> last_reference_list;
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
while (lru_.next != &lru_) {
|
||||
LRUHandle* old = lru_.next;
|
||||
// LRU list contains only elements which can be evicted.
|
||||
assert(old->InCache() && !old->HasRefs());
|
||||
LRU_Remove(old);
|
||||
table_.Remove(old->key(), old->hash);
|
||||
old->SetInCache(false);
|
||||
size_t total_charge = old->CalcTotalCharge(metadata_charge_policy_);
|
||||
assert(usage_ >= total_charge);
|
||||
usage_ -= total_charge;
|
||||
last_reference_list.push_back(old);
|
||||
}
|
||||
}
|
||||
|
||||
// Free the entries here outside of mutex for performance reasons.
|
||||
for (auto entry : last_reference_list) {
|
||||
entry->Free();
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCacheShard::ApplyToSomeEntries(
|
||||
const std::function<void(const Slice& key, void* value, size_t charge,
|
||||
DeleterFn deleter)>& callback,
|
||||
uint32_t average_entries_per_lock, uint32_t* state) {
|
||||
// The state is essentially going to be the starting hash, which works
|
||||
// nicely even if we resize between calls because we use upper-most
|
||||
// hash bits for table indexes.
|
||||
MutexLock l(&mutex_);
|
||||
uint32_t length_bits = table_.GetLengthBits();
|
||||
uint32_t length = uint32_t{1} << length_bits;
|
||||
|
||||
assert(average_entries_per_lock > 0);
|
||||
// Assuming we are called with same average_entries_per_lock repeatedly,
|
||||
// this simplifies some logic (index_end will not overflow).
|
||||
assert(average_entries_per_lock < length || *state == 0);
|
||||
|
||||
uint32_t index_begin = *state >> (32 - length_bits);
|
||||
uint32_t index_end = index_begin + average_entries_per_lock;
|
||||
if (index_end >= length) {
|
||||
// Going to end
|
||||
index_end = length;
|
||||
*state = UINT32_MAX;
|
||||
} else {
|
||||
*state = index_end << (32 - length_bits);
|
||||
}
|
||||
|
||||
table_.ApplyToEntriesRange(
|
||||
[callback](LRUHandle* h) {
|
||||
callback(h->key(), h->value, h->charge, h->deleter);
|
||||
},
|
||||
index_begin, index_end);
|
||||
}
|
||||
|
||||
void LRUCacheShard::LRU_Remove(LRUHandle* e) {
|
||||
assert(e->next != nullptr);
|
||||
assert(e->prev != nullptr);
|
||||
e->next->prev = e->prev;
|
||||
e->prev->next = e->next;
|
||||
e->prev = e->next = nullptr;
|
||||
size_t total_charge = e->CalcTotalCharge(metadata_charge_policy_);
|
||||
assert(lru_usage_ >= total_charge);
|
||||
lru_usage_ -= total_charge;
|
||||
}
|
||||
|
||||
void LRUCacheShard::LRU_Insert(LRUHandle* e) {
|
||||
assert(e->next == nullptr);
|
||||
assert(e->prev == nullptr);
|
||||
size_t total_charge = e->CalcTotalCharge(metadata_charge_policy_);
|
||||
// Inset "e" to head of LRU list.
|
||||
e->next = &lru_;
|
||||
e->prev = lru_.prev;
|
||||
e->prev->next = e;
|
||||
e->next->prev = e;
|
||||
lru_usage_ += total_charge;
|
||||
}
|
||||
|
||||
void LRUCacheShard::EvictFromLRU(size_t charge,
|
||||
autovector<LRUHandle*>* deleted) {
|
||||
while ((usage_ + charge) > capacity_ && lru_.next != &lru_) {
|
||||
LRUHandle* old = lru_.next;
|
||||
// LRU list contains only elements which can be evicted.
|
||||
assert(old->InCache() && !old->HasRefs());
|
||||
LRU_Remove(old);
|
||||
table_.Remove(old->key(), old->hash);
|
||||
old->SetInCache(false);
|
||||
size_t old_total_charge = old->CalcTotalCharge(metadata_charge_policy_);
|
||||
assert(usage_ >= old_total_charge);
|
||||
usage_ -= old_total_charge;
|
||||
deleted->push_back(old);
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCacheShard::SetCapacity(size_t capacity) {
|
||||
autovector<LRUHandle*> last_reference_list;
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
capacity_ = capacity;
|
||||
EvictFromLRU(0, &last_reference_list);
|
||||
}
|
||||
|
||||
// Free the entries here outside of mutex for performance reasons.
|
||||
for (auto entry : last_reference_list) {
|
||||
entry->Free();
|
||||
}
|
||||
}
|
||||
|
||||
void LRUCacheShard::SetStrictCapacityLimit(bool strict_capacity_limit) {
|
||||
MutexLock l(&mutex_);
|
||||
strict_capacity_limit_ = strict_capacity_limit;
|
||||
}
|
||||
|
||||
Status LRUCacheShard::InsertItem(LRUHandle* e, Cache::Handle** handle,
|
||||
bool free_handle_on_fail) {
|
||||
Status s = Status::OK();
|
||||
autovector<LRUHandle*> last_reference_list;
|
||||
size_t total_charge = e->CalcTotalCharge(metadata_charge_policy_);
|
||||
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
|
||||
// Free the space following strict LRU policy until enough space
|
||||
// is freed or the lru list is empty.
|
||||
EvictFromLRU(total_charge, &last_reference_list);
|
||||
|
||||
if ((usage_ + total_charge) > capacity_ &&
|
||||
(strict_capacity_limit_ || handle == nullptr)) {
|
||||
e->SetInCache(false);
|
||||
if (handle == nullptr) {
|
||||
// Don't insert the entry but still return ok, as if the entry inserted
|
||||
// into cache and get evicted immediately.
|
||||
last_reference_list.push_back(e);
|
||||
} else {
|
||||
if (free_handle_on_fail) {
|
||||
delete[] reinterpret_cast<char*>(e);
|
||||
*handle = nullptr;
|
||||
}
|
||||
s = Status::Incomplete("Insert failed due to LRU cache being full.");
|
||||
}
|
||||
} else {
|
||||
// Insert into the cache. Note that the cache might get larger than its
|
||||
// capacity if not enough space was freed up.
|
||||
LRUHandle* old = table_.Insert(e);
|
||||
usage_ += total_charge;
|
||||
if (old != nullptr) {
|
||||
s = Status::OkOverwritten();
|
||||
assert(old->InCache());
|
||||
old->SetInCache(false);
|
||||
if (!old->HasRefs()) {
|
||||
// old is on LRU because it's in cache and its reference count is 0.
|
||||
LRU_Remove(old);
|
||||
size_t old_total_charge =
|
||||
old->CalcTotalCharge(metadata_charge_policy_);
|
||||
assert(usage_ >= old_total_charge);
|
||||
usage_ -= old_total_charge;
|
||||
last_reference_list.push_back(old);
|
||||
}
|
||||
}
|
||||
if (handle == nullptr) {
|
||||
LRU_Insert(e);
|
||||
} else {
|
||||
// If caller already holds a ref, no need to take one here.
|
||||
if (!e->HasRefs()) {
|
||||
e->Ref();
|
||||
}
|
||||
*handle = reinterpret_cast<Cache::Handle*>(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free the entries here outside of mutex for performance reasons.
|
||||
for (auto entry : last_reference_list) {
|
||||
entry->Free();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Cache::Handle* LRUCacheShard::Lookup(const Slice& key, uint32_t hash) {
|
||||
LRUHandle* e = nullptr;
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
e = table_.Lookup(key, hash);
|
||||
if (e != nullptr) {
|
||||
assert(e->InCache());
|
||||
if (!e->HasRefs()) {
|
||||
// The entry is in LRU since it's in hash and has no external references
|
||||
LRU_Remove(e);
|
||||
}
|
||||
e->Ref();
|
||||
}
|
||||
}
|
||||
return reinterpret_cast<Cache::Handle*>(e);
|
||||
}
|
||||
|
||||
bool LRUCacheShard::Ref(Cache::Handle* h) {
|
||||
LRUHandle* e = reinterpret_cast<LRUHandle*>(h);
|
||||
MutexLock l(&mutex_);
|
||||
// To create another reference - entry must be already externally referenced.
|
||||
assert(e->HasRefs());
|
||||
e->Ref();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LRUCacheShard::Release(Cache::Handle* handle, bool erase_if_last_ref) {
|
||||
if (handle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
LRUHandle* e = reinterpret_cast<LRUHandle*>(handle);
|
||||
bool last_reference = false;
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
last_reference = e->Unref();
|
||||
if (last_reference && e->InCache()) {
|
||||
// The item is still in cache, and nobody else holds a reference to it.
|
||||
if (usage_ > capacity_ || erase_if_last_ref) {
|
||||
// The LRU list must be empty since the cache is full.
|
||||
assert(lru_.next == &lru_ || erase_if_last_ref);
|
||||
// Take this opportunity and remove the item.
|
||||
table_.Remove(e->key(), e->hash);
|
||||
e->SetInCache(false);
|
||||
} else {
|
||||
// Put the item back on the LRU list, and don't free it.
|
||||
LRU_Insert(e);
|
||||
last_reference = false;
|
||||
}
|
||||
}
|
||||
// If it was the last reference, then decrement the cache usage.
|
||||
if (last_reference) {
|
||||
size_t total_charge = e->CalcTotalCharge(metadata_charge_policy_);
|
||||
assert(usage_ >= total_charge);
|
||||
usage_ -= total_charge;
|
||||
}
|
||||
}
|
||||
|
||||
// Free the entry here outside of mutex for performance reasons.
|
||||
if (last_reference) {
|
||||
e->Free();
|
||||
}
|
||||
return last_reference;
|
||||
}
|
||||
|
||||
Status LRUCacheShard::Insert(const Slice& key, uint32_t hash, void* value,
|
||||
size_t charge, Cache::DeleterFn deleter,
|
||||
Cache::Handle** handle,
|
||||
Cache::Priority /*priority*/) {
|
||||
// Allocate the memory here outside of the mutex.
|
||||
// If the cache is full, we'll have to release it.
|
||||
// It shouldn't happen very often though.
|
||||
LRUHandle* e = reinterpret_cast<LRUHandle*>(
|
||||
new char[sizeof(LRUHandle) - 1 + key.size()]);
|
||||
|
||||
e->value = value;
|
||||
e->flags = 0;
|
||||
e->deleter = deleter;
|
||||
e->charge = charge;
|
||||
e->key_length = key.size();
|
||||
e->hash = hash;
|
||||
e->refs = 0;
|
||||
e->next = e->prev = nullptr;
|
||||
e->SetInCache(true);
|
||||
memcpy(e->key_data, key.data(), key.size());
|
||||
|
||||
return InsertItem(e, handle, /* free_handle_on_fail */ true);
|
||||
}
|
||||
|
||||
void LRUCacheShard::Erase(const Slice& key, uint32_t hash) {
|
||||
LRUHandle* e;
|
||||
bool last_reference = false;
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
e = table_.Remove(key, hash);
|
||||
if (e != nullptr) {
|
||||
assert(e->InCache());
|
||||
e->SetInCache(false);
|
||||
if (!e->HasRefs()) {
|
||||
// The entry is in LRU since it's in hash and has no external references
|
||||
LRU_Remove(e);
|
||||
size_t total_charge = e->CalcTotalCharge(metadata_charge_policy_);
|
||||
assert(usage_ >= total_charge);
|
||||
usage_ -= total_charge;
|
||||
last_reference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free the entry here outside of mutex for performance reasons.
|
||||
// last_reference will only be true if e != nullptr.
|
||||
if (last_reference) {
|
||||
e->Free();
|
||||
}
|
||||
}
|
||||
|
||||
size_t LRUCacheShard::GetUsage() const {
|
||||
MutexLock l(&mutex_);
|
||||
return usage_;
|
||||
}
|
||||
|
||||
size_t LRUCacheShard::GetPinnedUsage() const {
|
||||
MutexLock l(&mutex_);
|
||||
assert(usage_ >= lru_usage_);
|
||||
return usage_ - lru_usage_;
|
||||
}
|
||||
|
||||
std::string LRUCacheShard::GetPrintableOptions() const { return std::string{}; }
|
||||
|
||||
LRUCache::LRUCache(size_t capacity, int num_shard_bits,
|
||||
bool strict_capacity_limit,
|
||||
CacheMetadataChargePolicy metadata_charge_policy)
|
||||
: ShardedCache(capacity, num_shard_bits, strict_capacity_limit) {
|
||||
num_shards_ = 1 << num_shard_bits;
|
||||
shards_ = reinterpret_cast<LRUCacheShard*>(
|
||||
port::cacheline_aligned_alloc(sizeof(LRUCacheShard) * num_shards_));
|
||||
size_t per_shard = (capacity + (num_shards_ - 1)) / num_shards_;
|
||||
for (int i = 0; i < num_shards_; i++) {
|
||||
new (&shards_[i])
|
||||
LRUCacheShard(per_shard, strict_capacity_limit, metadata_charge_policy,
|
||||
/* max_upper_hash_bits */ 32 - num_shard_bits);
|
||||
}
|
||||
}
|
||||
|
||||
LRUCache::~LRUCache() {
|
||||
if (shards_ != nullptr) {
|
||||
assert(num_shards_ > 0);
|
||||
for (int i = 0; i < num_shards_; i++) {
|
||||
shards_[i].~LRUCacheShard();
|
||||
}
|
||||
port::cacheline_aligned_free(shards_);
|
||||
}
|
||||
}
|
||||
|
||||
CacheShard* LRUCache::GetShard(uint32_t shard) {
|
||||
return reinterpret_cast<CacheShard*>(&shards_[shard]);
|
||||
}
|
||||
|
||||
const CacheShard* LRUCache::GetShard(uint32_t shard) const {
|
||||
return reinterpret_cast<CacheShard*>(&shards_[shard]);
|
||||
}
|
||||
|
||||
void* LRUCache::Value(Handle* handle) {
|
||||
return reinterpret_cast<const LRUHandle*>(handle)->value;
|
||||
}
|
||||
|
||||
size_t LRUCache::GetCharge(Handle* handle) const {
|
||||
return reinterpret_cast<const LRUHandle*>(handle)->charge;
|
||||
}
|
||||
|
||||
Cache::DeleterFn LRUCache::GetDeleter(Handle* handle) const {
|
||||
auto h = reinterpret_cast<const LRUHandle*>(handle);
|
||||
return h->deleter;
|
||||
}
|
||||
|
||||
uint32_t LRUCache::GetHash(Handle* handle) const {
|
||||
return reinterpret_cast<const LRUHandle*>(handle)->hash;
|
||||
}
|
||||
|
||||
void LRUCache::DisownData() {
|
||||
// Leak data only if that won't generate an ASAN/valgrind warning.
|
||||
if (!kMustFreeHeapAllocations) {
|
||||
shards_ = nullptr;
|
||||
num_shards_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fast_lru_cache
|
||||
|
||||
std::shared_ptr<Cache> NewFastLRUCache(
|
||||
size_t capacity, int num_shard_bits, bool strict_capacity_limit,
|
||||
CacheMetadataChargePolicy metadata_charge_policy) {
|
||||
if (num_shard_bits >= 20) {
|
||||
return nullptr; // The cache cannot be sharded into too many fine pieces.
|
||||
}
|
||||
if (num_shard_bits < 0) {
|
||||
num_shard_bits = GetDefaultCacheShardBits(capacity);
|
||||
}
|
||||
return std::make_shared<fast_lru_cache::LRUCache>(
|
||||
capacity, num_shard_bits, strict_capacity_limit, metadata_charge_policy);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
-299
@@ -1,299 +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 <memory>
|
||||
#include <string>
|
||||
|
||||
#include "cache/sharded_cache.h"
|
||||
#include "port/lang.h"
|
||||
#include "port/malloc.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/secondary_cache.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace fast_lru_cache {
|
||||
|
||||
// An experimental (under development!) alternative to LRUCache
|
||||
|
||||
struct LRUHandle {
|
||||
void* value;
|
||||
Cache::DeleterFn deleter;
|
||||
LRUHandle* next_hash;
|
||||
LRUHandle* next;
|
||||
LRUHandle* prev;
|
||||
size_t charge; // TODO(opt): Only allow uint32_t?
|
||||
size_t key_length;
|
||||
// The hash of key(). Used for fast sharding and comparisons.
|
||||
uint32_t hash;
|
||||
// The number of external refs to this entry. The cache itself is not counted.
|
||||
uint32_t refs;
|
||||
|
||||
enum Flags : uint8_t {
|
||||
// Whether this entry is referenced by the hash table.
|
||||
IN_CACHE = (1 << 0),
|
||||
};
|
||||
uint8_t flags;
|
||||
|
||||
// Beginning of the key (MUST BE THE LAST FIELD IN THIS STRUCT!)
|
||||
char key_data[1];
|
||||
|
||||
Slice key() const { return Slice(key_data, key_length); }
|
||||
|
||||
// Increase the reference count by 1.
|
||||
void Ref() { refs++; }
|
||||
|
||||
// Just reduce the reference count by 1. Return true if it was last reference.
|
||||
bool Unref() {
|
||||
assert(refs > 0);
|
||||
refs--;
|
||||
return refs == 0;
|
||||
}
|
||||
|
||||
// Return true if there are external refs, false otherwise.
|
||||
bool HasRefs() const { return refs > 0; }
|
||||
|
||||
bool InCache() const { return flags & IN_CACHE; }
|
||||
|
||||
void SetInCache(bool in_cache) {
|
||||
if (in_cache) {
|
||||
flags |= IN_CACHE;
|
||||
} else {
|
||||
flags &= ~IN_CACHE;
|
||||
}
|
||||
}
|
||||
|
||||
void Free() {
|
||||
assert(refs == 0);
|
||||
if (deleter) {
|
||||
(*deleter)(key(), value);
|
||||
}
|
||||
delete[] reinterpret_cast<char*>(this);
|
||||
}
|
||||
|
||||
// Calculate the memory usage by metadata.
|
||||
inline size_t CalcTotalCharge(
|
||||
CacheMetadataChargePolicy metadata_charge_policy) {
|
||||
size_t meta_charge = 0;
|
||||
if (metadata_charge_policy == kFullChargeCacheMetadata) {
|
||||
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
|
||||
meta_charge += malloc_usable_size(static_cast<void*>(this));
|
||||
#else
|
||||
// This is the size that is used when a new handle is created.
|
||||
meta_charge += sizeof(LRUHandle) - 1 + key_length;
|
||||
#endif
|
||||
}
|
||||
return charge + meta_charge;
|
||||
}
|
||||
};
|
||||
|
||||
// We provide our own simple hash table since it removes a whole bunch
|
||||
// of porting hacks and is also faster than some of the built-in hash
|
||||
// table implementations in some of the compiler/runtime combinations
|
||||
// we have tested. E.g., readrandom speeds up by ~5% over the g++
|
||||
// 4.4.3's builtin hashtable.
|
||||
class LRUHandleTable {
|
||||
public:
|
||||
// If the table uses more hash bits than `max_upper_hash_bits`,
|
||||
// it will eat into the bits used for sharding, which are constant
|
||||
// for a given LRUHandleTable.
|
||||
explicit LRUHandleTable(int max_upper_hash_bits);
|
||||
~LRUHandleTable();
|
||||
|
||||
LRUHandle* Lookup(const Slice& key, uint32_t hash);
|
||||
LRUHandle* Insert(LRUHandle* h);
|
||||
LRUHandle* Remove(const Slice& key, uint32_t hash);
|
||||
|
||||
template <typename T>
|
||||
void ApplyToEntriesRange(T func, uint32_t index_begin, uint32_t index_end) {
|
||||
for (uint32_t i = index_begin; i < index_end; i++) {
|
||||
LRUHandle* h = list_[i];
|
||||
while (h != nullptr) {
|
||||
auto n = h->next_hash;
|
||||
assert(h->InCache());
|
||||
func(h);
|
||||
h = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int GetLengthBits() const { return length_bits_; }
|
||||
|
||||
private:
|
||||
// Return a pointer to slot that points to a cache entry that
|
||||
// matches key/hash. If there is no such cache entry, return a
|
||||
// pointer to the trailing slot in the corresponding linked list.
|
||||
LRUHandle** FindPointer(const Slice& key, uint32_t hash);
|
||||
|
||||
void Resize();
|
||||
|
||||
// Number of hash bits (upper because lower bits used for sharding)
|
||||
// used for table index. Length == 1 << length_bits_
|
||||
int length_bits_;
|
||||
|
||||
// The table consists of an array of buckets where each bucket is
|
||||
// a linked list of cache entries that hash into the bucket.
|
||||
std::unique_ptr<LRUHandle*[]> list_;
|
||||
|
||||
// Number of elements currently in the table.
|
||||
uint32_t elems_;
|
||||
|
||||
// Set from max_upper_hash_bits (see constructor).
|
||||
const int max_length_bits_;
|
||||
};
|
||||
|
||||
// A single shard of sharded cache.
|
||||
class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard final : public CacheShard {
|
||||
public:
|
||||
LRUCacheShard(size_t capacity, bool strict_capacity_limit,
|
||||
CacheMetadataChargePolicy metadata_charge_policy,
|
||||
int max_upper_hash_bits);
|
||||
~LRUCacheShard() override = default;
|
||||
|
||||
// Separate from constructor so caller can easily make an array of LRUCache
|
||||
// if current usage is more than new capacity, the function will attempt to
|
||||
// free the needed space.
|
||||
void SetCapacity(size_t capacity) override;
|
||||
|
||||
// Set the flag to reject insertion if cache if full.
|
||||
void SetStrictCapacityLimit(bool strict_capacity_limit) override;
|
||||
|
||||
// Like Cache methods, but with an extra "hash" parameter.
|
||||
Status Insert(const Slice& key, uint32_t hash, void* value, size_t charge,
|
||||
Cache::DeleterFn deleter, Cache::Handle** handle,
|
||||
Cache::Priority priority) override;
|
||||
|
||||
Status Insert(const Slice& key, uint32_t hash, void* value,
|
||||
const Cache::CacheItemHelper* helper, size_t charge,
|
||||
Cache::Handle** handle, Cache::Priority priority) override {
|
||||
return Insert(key, hash, value, charge, helper->del_cb, handle, priority);
|
||||
}
|
||||
|
||||
Cache::Handle* Lookup(const Slice& key, uint32_t hash,
|
||||
const Cache::CacheItemHelper* /*helper*/,
|
||||
const Cache::CreateCallback& /*create_cb*/,
|
||||
Cache::Priority /*priority*/, bool /*wait*/,
|
||||
Statistics* /*stats*/) override {
|
||||
return Lookup(key, hash);
|
||||
}
|
||||
Cache::Handle* Lookup(const Slice& key, uint32_t hash) override;
|
||||
|
||||
bool Release(Cache::Handle* handle, bool /*useful*/,
|
||||
bool erase_if_last_ref) override {
|
||||
return Release(handle, erase_if_last_ref);
|
||||
}
|
||||
bool IsReady(Cache::Handle* /*handle*/) override { return true; }
|
||||
void Wait(Cache::Handle* /*handle*/) override {}
|
||||
|
||||
bool Ref(Cache::Handle* handle) override;
|
||||
bool Release(Cache::Handle* handle, bool erase_if_last_ref = false) override;
|
||||
void Erase(const Slice& key, uint32_t hash) override;
|
||||
|
||||
size_t GetUsage() const override;
|
||||
size_t GetPinnedUsage() const override;
|
||||
|
||||
void ApplyToSomeEntries(
|
||||
const std::function<void(const Slice& key, void* value, size_t charge,
|
||||
DeleterFn deleter)>& callback,
|
||||
uint32_t average_entries_per_lock, uint32_t* state) override;
|
||||
|
||||
void EraseUnRefEntries() override;
|
||||
|
||||
std::string GetPrintableOptions() const override;
|
||||
|
||||
private:
|
||||
friend class LRUCache;
|
||||
// Insert an item into the hash table and, if handle is null, insert into
|
||||
// the LRU list. Older items are evicted as necessary. If the cache is full
|
||||
// and free_handle_on_fail is true, the item is deleted and handle is set to
|
||||
// nullptr.
|
||||
Status InsertItem(LRUHandle* item, Cache::Handle** handle,
|
||||
bool free_handle_on_fail);
|
||||
|
||||
void LRU_Remove(LRUHandle* e);
|
||||
void LRU_Insert(LRUHandle* e);
|
||||
|
||||
// Free some space following strict LRU policy until enough space
|
||||
// to hold (usage_ + charge) is freed or the lru list is empty
|
||||
// This function is not thread safe - it needs to be executed while
|
||||
// holding the mutex_.
|
||||
void EvictFromLRU(size_t charge, autovector<LRUHandle*>* deleted);
|
||||
|
||||
// Initialized before use.
|
||||
size_t capacity_;
|
||||
|
||||
// Whether to reject insertion if cache reaches its full capacity.
|
||||
bool strict_capacity_limit_;
|
||||
|
||||
// Dummy head of LRU list.
|
||||
// lru.prev is newest entry, lru.next is oldest entry.
|
||||
// LRU contains items which can be evicted, ie reference only by cache
|
||||
LRUHandle lru_;
|
||||
|
||||
// Pointer to head of low-pri pool in LRU list.
|
||||
LRUHandle* lru_low_pri_;
|
||||
|
||||
// ------------^^^^^^^^^^^^^-----------
|
||||
// Not frequently modified data members
|
||||
// ------------------------------------
|
||||
//
|
||||
// We separate data members that are updated frequently from the ones that
|
||||
// are not frequently updated so that they don't share the same cache line
|
||||
// which will lead into false cache sharing
|
||||
//
|
||||
// ------------------------------------
|
||||
// Frequently modified data members
|
||||
// ------------vvvvvvvvvvvvv-----------
|
||||
LRUHandleTable table_;
|
||||
|
||||
// Memory size for entries residing in the cache.
|
||||
size_t usage_;
|
||||
|
||||
// Memory size for entries residing only in the LRU list.
|
||||
size_t lru_usage_;
|
||||
|
||||
// mutex_ protects the following state.
|
||||
// We don't count mutex_ as the cache's internal state so semantically we
|
||||
// don't mind mutex_ invoking the non-const actions.
|
||||
mutable port::Mutex mutex_;
|
||||
};
|
||||
|
||||
class LRUCache
|
||||
#ifdef NDEBUG
|
||||
final
|
||||
#endif
|
||||
: public ShardedCache {
|
||||
public:
|
||||
LRUCache(size_t capacity, int num_shard_bits, bool strict_capacity_limit,
|
||||
CacheMetadataChargePolicy metadata_charge_policy =
|
||||
kDontChargeCacheMetadata);
|
||||
~LRUCache() override;
|
||||
const char* Name() const override { return "LRUCache"; }
|
||||
CacheShard* GetShard(uint32_t shard) override;
|
||||
const CacheShard* GetShard(uint32_t shard) const override;
|
||||
void* Value(Handle* handle) override;
|
||||
size_t GetCharge(Handle* handle) const override;
|
||||
uint32_t GetHash(Handle* handle) const override;
|
||||
DeleterFn GetDeleter(Handle* handle) const override;
|
||||
void DisownData() override;
|
||||
|
||||
private:
|
||||
LRUCacheShard* shards_ = nullptr;
|
||||
int num_shards_ = 0;
|
||||
};
|
||||
} // namespace fast_lru_cache
|
||||
|
||||
std::shared_ptr<Cache> NewFastLRUCache(
|
||||
size_t capacity, int num_shard_bits = -1,
|
||||
bool strict_capacity_limit = false,
|
||||
CacheMetadataChargePolicy metadata_charge_policy =
|
||||
kDefaultCacheMetadataChargePolicy);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
-3
@@ -19,7 +19,6 @@
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace lru_cache {
|
||||
|
||||
LRUHandleTable::LRUHandleTable(int max_upper_hash_bits)
|
||||
: length_bits_(/* historical starting size*/ 4),
|
||||
@@ -760,8 +759,6 @@ void LRUCache::WaitAll(std::vector<Handle*>& handles) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lru_cache
|
||||
|
||||
std::shared_ptr<Cache> NewLRUCache(
|
||||
size_t capacity, int num_shard_bits, bool strict_capacity_limit,
|
||||
double high_pri_pool_ratio,
|
||||
|
||||
Vendored
-7
@@ -19,7 +19,6 @@
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace lru_cache {
|
||||
|
||||
// LRU cache implementation. This class is not thread-safe.
|
||||
|
||||
@@ -480,10 +479,4 @@ class LRUCache
|
||||
std::shared_ptr<SecondaryCache> secondary_cache_;
|
||||
};
|
||||
|
||||
} // namespace lru_cache
|
||||
|
||||
using LRUCache = lru_cache::LRUCache;
|
||||
using LRUHandle = lru_cache::LRUHandle;
|
||||
using LRUCacheShard = lru_cache::LRUCacheShard;
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -1,30 +0,0 @@
|
||||
ifndef PYTHON
|
||||
|
||||
# Default to python3. Some distros like CentOS 8 do not have `python`.
|
||||
ifeq ($(origin PYTHON), undefined)
|
||||
PYTHON := $(shell which python3 || which python || echo python3)
|
||||
endif
|
||||
export PYTHON
|
||||
|
||||
endif
|
||||
|
||||
# To setup tmp directory, first recognize some old variables for setting
|
||||
# test tmp directory or base tmp directory. TEST_TMPDIR is usually read
|
||||
# by RocksDB tools though Env/FileSystem::GetTestDirectory.
|
||||
ifeq ($(TEST_TMPDIR),)
|
||||
TEST_TMPDIR := $(TMPD)
|
||||
endif
|
||||
ifeq ($(TEST_TMPDIR),)
|
||||
ifeq ($(BASE_TMPDIR),)
|
||||
BASE_TMPDIR :=$(TMPDIR)
|
||||
endif
|
||||
ifeq ($(BASE_TMPDIR),)
|
||||
BASE_TMPDIR :=/tmp
|
||||
endif
|
||||
# Use /dev/shm if it has the sticky bit set (otherwise, /tmp or other
|
||||
# base dir), and create a randomly-named rocksdb.XXXX directory therein.
|
||||
TEST_TMPDIR := $(shell f=/dev/shm; test -k $$f || f=$(BASE_TMPDIR); \
|
||||
perl -le 'use File::Temp "tempdir";' \
|
||||
-e 'print tempdir("'$$f'/rocksdb.XXXX", CLEANUP => 0)')
|
||||
endif
|
||||
export TEST_TMPDIR
|
||||
+3
-3
@@ -5,7 +5,7 @@
|
||||
# build DB_STRESS_CMD so it must exist prior.
|
||||
DB_STRESS_CMD?=./db_stress
|
||||
|
||||
include common.mk
|
||||
include python.mk
|
||||
|
||||
CRASHTEST_MAKE=$(MAKE) -f crash_test.mk
|
||||
CRASHTEST_PY=$(PYTHON) -u tools/db_crashtest.py --stress_cmd=$(DB_STRESS_CMD)
|
||||
@@ -65,10 +65,10 @@ blackbox_crash_test_with_ts: $(DB_STRESS_CMD)
|
||||
$(CRASHTEST_PY) --enable_ts blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
blackbox_crash_test_with_multiops_wc_txn: $(DB_STRESS_CMD)
|
||||
$(CRASHTEST_PY) --test_multiops_txn --write_policy write_committed blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
$(PYTHON) -u tools/db_crashtest.py --test_multiops_txn --write_policy write_committed blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
blackbox_crash_test_with_multiops_wp_txn: $(DB_STRESS_CMD)
|
||||
$(CRASHTEST_PY) --test_multiops_txn --write_policy write_prepared blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
$(PYTHON) -u tools/db_crashtest.py --test_multiops_txn --write_policy write_prepared blackbox $(CRASH_TEST_EXT_ARGS)
|
||||
|
||||
ifeq ($(CRASH_TEST_KILL_ODD),)
|
||||
CRASH_TEST_KILL_ODD=888887
|
||||
|
||||
@@ -23,7 +23,7 @@ Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
|
||||
if (prop_name == "rocksdb.iterator.super-version-number") {
|
||||
// First try to pass the value returned from inner iterator.
|
||||
if (!db_iter_->GetProperty(prop_name, prop).ok()) {
|
||||
*prop = std::to_string(sv_number_);
|
||||
*prop = ToString(sv_number_);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -96,9 +96,9 @@ class BlobIndex {
|
||||
assert(slice.size() > 0);
|
||||
type_ = static_cast<Type>(*slice.data());
|
||||
if (type_ >= Type::kUnknown) {
|
||||
return Status::Corruption(kErrorMessage,
|
||||
"Unknown blob index type: " +
|
||||
std::to_string(static_cast<char>(type_)));
|
||||
return Status::Corruption(
|
||||
kErrorMessage,
|
||||
"Unknown blob index type: " + ToString(static_cast<char>(type_)));
|
||||
}
|
||||
slice = Slice(slice.data() + 1, slice.size() - 1);
|
||||
if (HasTTL()) {
|
||||
|
||||
@@ -153,11 +153,11 @@ TEST_F(DBBlobIndexTest, Write) {
|
||||
key_values.reserve(num_key_values);
|
||||
|
||||
for (size_t i = 1; i <= num_key_values; ++i) {
|
||||
std::string key = "key" + std::to_string(i);
|
||||
std::string key = "key" + ToString(i);
|
||||
|
||||
std::string blob_index;
|
||||
BlobIndex::EncodeInlinedTTL(&blob_index, /* expiration */ 9876543210,
|
||||
"blob" + std::to_string(i));
|
||||
"blob" + ToString(i));
|
||||
|
||||
key_values.emplace_back(std::move(key), std::move(blob_index));
|
||||
}
|
||||
@@ -230,7 +230,7 @@ TEST_F(DBBlobIndexTest, Updated) {
|
||||
DestroyAndReopen(GetTestOptions());
|
||||
WriteBatch batch;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(PutBlobIndex(&batch, "key" + std::to_string(i), blob_index));
|
||||
ASSERT_OK(PutBlobIndex(&batch, "key" + ToString(i), blob_index));
|
||||
}
|
||||
ASSERT_OK(Write(&batch));
|
||||
// Avoid blob values from being purged.
|
||||
@@ -248,7 +248,7 @@ TEST_F(DBBlobIndexTest, Updated) {
|
||||
ASSERT_OK(dbfull()->DeleteRange(WriteOptions(), cfh(), "key6", "key9"));
|
||||
MoveDataTo(tier);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_EQ(blob_index, GetBlobIndex("key" + std::to_string(i), snapshot));
|
||||
ASSERT_EQ(blob_index, GetBlobIndex("key" + ToString(i), snapshot));
|
||||
}
|
||||
ASSERT_EQ("new_value", Get("key1"));
|
||||
if (tier <= kImmutableMemtables) {
|
||||
@@ -260,7 +260,7 @@ TEST_F(DBBlobIndexTest, Updated) {
|
||||
ASSERT_EQ("NOT_FOUND", Get("key4"));
|
||||
ASSERT_EQ("a,b,c", GetImpl("key5"));
|
||||
for (int i = 6; i < 9; i++) {
|
||||
ASSERT_EQ("NOT_FOUND", Get("key" + std::to_string(i)));
|
||||
ASSERT_EQ("NOT_FOUND", Get("key" + ToString(i)));
|
||||
}
|
||||
ASSERT_EQ(blob_index, GetBlobIndex("key9"));
|
||||
dbfull()->ReleaseSnapshot(snapshot);
|
||||
@@ -301,7 +301,7 @@ TEST_F(DBBlobIndexTest, Iterate) {
|
||||
};
|
||||
|
||||
auto get_value = [&](int index, int version) {
|
||||
return get_key(index) + "_value" + std::to_string(version);
|
||||
return get_key(index) + "_value" + ToString(version);
|
||||
};
|
||||
|
||||
auto check_iterator = [&](Iterator* iterator, Status::Code expected_status,
|
||||
@@ -501,7 +501,7 @@ TEST_F(DBBlobIndexTest, IntegratedBlobIterate) {
|
||||
auto get_key = [](size_t index) { return ("key" + std::to_string(index)); };
|
||||
|
||||
auto get_value = [&](size_t index, size_t version) {
|
||||
return get_key(index) + "_value" + std::to_string(version);
|
||||
return get_key(index) + "_value" + ToString(version);
|
||||
};
|
||||
|
||||
auto check_iterator = [&](Iterator* iterator, Status expected_status,
|
||||
|
||||
+7
-22
@@ -37,7 +37,6 @@
|
||||
#include "table/block_based/block_based_table_builder.h"
|
||||
#include "table/format.h"
|
||||
#include "table/internal_iterator.h"
|
||||
#include "table/unique_id_impl.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/stop_watch.h"
|
||||
|
||||
@@ -116,7 +115,6 @@ Status BuildTable(
|
||||
assert(fs);
|
||||
|
||||
TableProperties tp;
|
||||
bool table_file_created = false;
|
||||
if (iter->Valid() || !range_del_agg->IsEmpty()) {
|
||||
std::unique_ptr<CompactionFilter> compaction_filter;
|
||||
if (ioptions.compaction_filter_factory != nullptr &&
|
||||
@@ -160,8 +158,6 @@ Status BuildTable(
|
||||
file_checksum_func_name);
|
||||
return s;
|
||||
}
|
||||
|
||||
table_file_created = true;
|
||||
FileTypeSet tmp_set = ioptions.checksum_handoff_file_types;
|
||||
file->SetIOPriority(io_priority);
|
||||
file->SetWriteLifeTimeHint(write_hint);
|
||||
@@ -197,7 +193,6 @@ Status BuildTable(
|
||||
ShouldReportDetailedTime(env, ioptions.stats),
|
||||
true /* internal key corruption is not ok */, range_del_agg.get(),
|
||||
blob_file_builder.get(), ioptions.allow_data_in_errors,
|
||||
ioptions.enforce_single_del_contracts,
|
||||
/*compaction=*/nullptr, compaction_filter.get(),
|
||||
/*shutting_down=*/nullptr,
|
||||
/*manual_compaction_paused=*/nullptr,
|
||||
@@ -311,15 +306,6 @@ Status BuildTable(
|
||||
meta->file_checksum_func_name = file_writer->GetFileChecksumFuncName();
|
||||
file_checksum = meta->file_checksum;
|
||||
file_checksum_func_name = meta->file_checksum_func_name;
|
||||
// Set unique_id only if db_id and db_session_id exist
|
||||
if (!tboptions.db_id.empty() && !tboptions.db_session_id.empty()) {
|
||||
if (!GetSstInternalUniqueId(tboptions.db_id, tboptions.db_session_id,
|
||||
meta->fd.GetNumber(), &(meta->unique_id))
|
||||
.ok()) {
|
||||
// if failed to get unique id, just set it Null
|
||||
meta->unique_id = kNullUniqueId64x2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
@@ -341,9 +327,10 @@ Status BuildTable(
|
||||
if (s.ok() && !empty) {
|
||||
// Verify that the table is usable
|
||||
// We set for_compaction to false and don't OptimizeForCompactionTableRead
|
||||
// here because this is a special case after we finish the table building.
|
||||
// here because this is a special case after we finish the table building
|
||||
// No matter whether use_direct_io_for_flush_and_compaction is true,
|
||||
// the goal is to cache it here for further user reads.
|
||||
// we will regrad this verification as user reads since the goal is
|
||||
// to cache it here for further user reads
|
||||
ReadOptions read_options;
|
||||
std::unique_ptr<InternalIterator> it(table_cache->NewIterator(
|
||||
read_options, file_options, tboptions.internal_comparator, *meta,
|
||||
@@ -384,17 +371,15 @@ Status BuildTable(
|
||||
|
||||
constexpr IODebugContext* dbg = nullptr;
|
||||
|
||||
if (table_file_created) {
|
||||
Status ignored = fs->DeleteFile(fname, IOOptions(), dbg);
|
||||
ignored.PermitUncheckedError();
|
||||
}
|
||||
Status ignored = fs->DeleteFile(fname, IOOptions(), dbg);
|
||||
ignored.PermitUncheckedError();
|
||||
|
||||
assert(blob_file_additions || blob_file_paths.empty());
|
||||
|
||||
if (blob_file_additions) {
|
||||
for (const std::string& blob_file_path : blob_file_paths) {
|
||||
Status ignored = DeleteDBFile(&db_options, blob_file_path, dbname,
|
||||
/*force_bg=*/false, /*force_fg=*/false);
|
||||
ignored = DeleteDBFile(&db_options, blob_file_path, dbname,
|
||||
/*force_bg=*/false, /*force_fg=*/false);
|
||||
ignored.PermitUncheckedError();
|
||||
TEST_SYNC_POINT("BuildTable::AfterDeleteFile");
|
||||
}
|
||||
|
||||
@@ -1163,43 +1163,6 @@ void rocksdb_multi_get_cf(
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_batched_multi_get_cf(rocksdb_t* db,
|
||||
const rocksdb_readoptions_t* options,
|
||||
rocksdb_column_family_handle_t* column_family,
|
||||
size_t num_keys, const char* const* keys_list,
|
||||
const size_t* keys_list_sizes,
|
||||
rocksdb_pinnableslice_t** values, char** errs,
|
||||
const bool sorted_input) {
|
||||
Slice* key_slices = new Slice[num_keys];
|
||||
PinnableSlice* value_slices = new PinnableSlice[num_keys];
|
||||
Status* statuses = new Status[num_keys];
|
||||
for (size_t i = 0; i < num_keys; ++i) {
|
||||
key_slices[i] = Slice(keys_list[i], keys_list_sizes[i]);
|
||||
}
|
||||
|
||||
db->rep->MultiGet(options->rep, column_family->rep, num_keys, key_slices,
|
||||
value_slices, statuses, sorted_input);
|
||||
|
||||
for (size_t i = 0; i < num_keys; ++i) {
|
||||
if (statuses[i].ok()) {
|
||||
values[i] = new (rocksdb_pinnableslice_t);
|
||||
values[i]->rep = std::move(value_slices[i]);
|
||||
errs[i] = nullptr;
|
||||
} else {
|
||||
values[i] = nullptr;
|
||||
if (!statuses[i].IsNotFound()) {
|
||||
errs[i] = strdup(statuses[i].ToString().c_str());
|
||||
} else {
|
||||
errs[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] key_slices;
|
||||
delete[] value_slices;
|
||||
delete[] statuses;
|
||||
}
|
||||
|
||||
unsigned char rocksdb_key_may_exist(rocksdb_t* db,
|
||||
const rocksdb_readoptions_t* options,
|
||||
const char* key, size_t key_len,
|
||||
@@ -2855,20 +2818,6 @@ void rocksdb_options_set_bottommost_compression_options_zstd_max_train_bytes(
|
||||
opt->rep.bottommost_compression_opts.enabled = enabled;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_bottommost_compression_options_use_zstd_dict_trainer(
|
||||
rocksdb_options_t* opt, unsigned char use_zstd_dict_trainer,
|
||||
unsigned char enabled) {
|
||||
opt->rep.bottommost_compression_opts.use_zstd_dict_trainer =
|
||||
use_zstd_dict_trainer;
|
||||
opt->rep.bottommost_compression_opts.enabled = enabled;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
rocksdb_options_get_bottommost_compression_options_use_zstd_dict_trainer(
|
||||
rocksdb_options_t* opt) {
|
||||
return opt->rep.bottommost_compression_opts.use_zstd_dict_trainer;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_bottommost_compression_options_max_dict_buffer_bytes(
|
||||
rocksdb_options_t* opt, uint64_t max_dict_buffer_bytes,
|
||||
unsigned char enabled) {
|
||||
@@ -2896,16 +2845,6 @@ int rocksdb_options_get_compression_options_zstd_max_train_bytes(
|
||||
return opt->rep.compression_opts.zstd_max_train_bytes;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_compression_options_use_zstd_dict_trainer(
|
||||
rocksdb_options_t* opt, unsigned char use_zstd_dict_trainer) {
|
||||
opt->rep.compression_opts.use_zstd_dict_trainer = use_zstd_dict_trainer;
|
||||
}
|
||||
|
||||
unsigned char rocksdb_options_get_compression_options_use_zstd_dict_trainer(
|
||||
rocksdb_options_t* opt) {
|
||||
return opt->rep.compression_opts.use_zstd_dict_trainer;
|
||||
}
|
||||
|
||||
void rocksdb_options_set_compression_options_parallel_threads(
|
||||
rocksdb_options_t* opt, int value) {
|
||||
opt->rep.compression_opts.parallel_threads = value;
|
||||
@@ -3697,8 +3636,6 @@ uint64_t rocksdb_perfcontext_metric(rocksdb_perfcontext_t* context,
|
||||
return rep->env_unlock_file_nanos;
|
||||
case rocksdb_env_new_logger_nanos:
|
||||
return rep->env_new_logger_nanos;
|
||||
case rocksdb_number_async_seek:
|
||||
return rep->number_async_seek;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -4256,14 +4193,6 @@ rocksdb_cache_t* rocksdb_cache_create_lru(size_t capacity) {
|
||||
return c;
|
||||
}
|
||||
|
||||
rocksdb_cache_t* rocksdb_cache_create_lru_with_strict_capacity_limit(
|
||||
size_t capacity) {
|
||||
rocksdb_cache_t* c = new rocksdb_cache_t;
|
||||
c->rep = NewLRUCache(capacity);
|
||||
c->rep->SetStrictCapacityLimit(true);
|
||||
return c;
|
||||
}
|
||||
|
||||
rocksdb_cache_t* rocksdb_cache_create_lru_opts(
|
||||
rocksdb_lru_cache_options_t* opt) {
|
||||
rocksdb_cache_t* c = new rocksdb_cache_t;
|
||||
|
||||
+2
-28
@@ -1260,18 +1260,15 @@ int main(int argc, char** argv) {
|
||||
rocksdb_writebatch_clear(wb);
|
||||
rocksdb_writebatch_put_cf(wb, handles[1], "bar", 3, "b", 1);
|
||||
rocksdb_writebatch_put_cf(wb, handles[1], "box", 3, "c", 1);
|
||||
rocksdb_writebatch_put_cf(wb, handles[1], "buff", 4, "rocksdb", 7);
|
||||
rocksdb_writebatch_delete_cf(wb, handles[1], "bar", 3);
|
||||
rocksdb_write(db, woptions, wb, &err);
|
||||
CheckNoError(err);
|
||||
CheckGetCF(db, roptions, handles[1], "baz", NULL);
|
||||
CheckGetCF(db, roptions, handles[1], "bar", NULL);
|
||||
CheckGetCF(db, roptions, handles[1], "box", "c");
|
||||
CheckGetCF(db, roptions, handles[1], "buff", "rocksdb");
|
||||
CheckPinGetCF(db, roptions, handles[1], "baz", NULL);
|
||||
CheckPinGetCF(db, roptions, handles[1], "bar", NULL);
|
||||
CheckPinGetCF(db, roptions, handles[1], "box", "c");
|
||||
CheckPinGetCF(db, roptions, handles[1], "buff", "rocksdb");
|
||||
rocksdb_writebatch_destroy(wb);
|
||||
|
||||
rocksdb_flush_wal(db, 1, &err);
|
||||
@@ -1302,26 +1299,6 @@ int main(int argc, char** argv) {
|
||||
Free(&vals[i]);
|
||||
}
|
||||
|
||||
{
|
||||
const char* batched_keys[4] = {"box", "buff", "barfooxx", "box"};
|
||||
const size_t batched_keys_sizes[4] = {3, 4, 8, 3};
|
||||
const char* expected_value[4] = {"c", "rocksdb", NULL, "c"};
|
||||
char* batched_errs[4];
|
||||
|
||||
rocksdb_pinnableslice_t* pvals[4];
|
||||
rocksdb_batched_multi_get_cf(db, roptions, handles[1], 4, batched_keys,
|
||||
batched_keys_sizes, pvals, batched_errs,
|
||||
false);
|
||||
const char* val;
|
||||
size_t val_len;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
val = rocksdb_pinnableslice_value(pvals[i], &val_len);
|
||||
CheckNoError(batched_errs[i]);
|
||||
CheckEqual(expected_value[i], val, val_len);
|
||||
rocksdb_pinnableslice_destroy(pvals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char value_found = 0;
|
||||
|
||||
@@ -1353,7 +1330,7 @@ int main(int argc, char** argv) {
|
||||
for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
|
||||
i++;
|
||||
}
|
||||
CheckCondition(i == 4);
|
||||
CheckCondition(i == 3);
|
||||
rocksdb_iter_get_error(iter, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_iter_destroy(iter);
|
||||
@@ -1377,7 +1354,7 @@ int main(int argc, char** argv) {
|
||||
for (i = 0; rocksdb_iter_valid(iter) != 0; rocksdb_iter_next(iter)) {
|
||||
i++;
|
||||
}
|
||||
CheckCondition(i == 4);
|
||||
CheckCondition(i == 3);
|
||||
rocksdb_iter_get_error(iter, &err);
|
||||
CheckNoError(err);
|
||||
rocksdb_iter_destroy(iter);
|
||||
@@ -2539,9 +2516,6 @@ int main(int argc, char** argv) {
|
||||
200 ==
|
||||
rocksdb_options_get_compression_options_max_dict_buffer_bytes(co));
|
||||
|
||||
rocksdb_options_set_compression_options_use_zstd_dict_trainer(co, 0);
|
||||
CheckCondition(
|
||||
0 == rocksdb_options_get_compression_options_use_zstd_dict_trainer(co));
|
||||
rocksdb_options_destroy(co);
|
||||
}
|
||||
|
||||
|
||||
+5
-12
@@ -136,15 +136,9 @@ Status CheckCompressionSupported(const ColumnFamilyOptions& cf_options) {
|
||||
}
|
||||
}
|
||||
if (cf_options.compression_opts.zstd_max_train_bytes > 0) {
|
||||
if (cf_options.compression_opts.use_zstd_dict_trainer) {
|
||||
if (!ZSTD_TrainDictionarySupported()) {
|
||||
return Status::InvalidArgument(
|
||||
"zstd dictionary trainer cannot be used because ZSTD 1.1.3+ "
|
||||
"is not linked with the binary.");
|
||||
}
|
||||
} else if (!ZSTD_FinalizeDictionarySupported()) {
|
||||
if (!ZSTD_TrainDictionarySupported()) {
|
||||
return Status::InvalidArgument(
|
||||
"zstd finalizeDictionary cannot be used because ZSTD 1.4.5+ "
|
||||
"zstd dictionary trainer cannot be used because ZSTD 1.1.3+ "
|
||||
"is not linked with the binary.");
|
||||
}
|
||||
if (cf_options.compression_opts.max_dict_bytes == 0) {
|
||||
@@ -507,8 +501,7 @@ std::vector<std::string> ColumnFamilyData::GetDbPaths() const {
|
||||
return paths;
|
||||
}
|
||||
|
||||
const uint32_t ColumnFamilyData::kDummyColumnFamilyDataId =
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
const uint32_t ColumnFamilyData::kDummyColumnFamilyDataId = port::kMaxUint32;
|
||||
|
||||
ColumnFamilyData::ColumnFamilyData(
|
||||
uint32_t id, const std::string& name, Version* _dummy_versions,
|
||||
@@ -833,8 +826,8 @@ int GetL0ThresholdSpeedupCompaction(int level0_file_num_compaction_trigger,
|
||||
// condition.
|
||||
// Or twice as compaction trigger, if it is smaller.
|
||||
int64_t res = std::min(twice_level0_trigger, one_fourth_trigger_slowdown);
|
||||
if (res >= std::numeric_limits<int32_t>::max()) {
|
||||
return std::numeric_limits<int32_t>::max();
|
||||
if (res >= port::kMaxInt32) {
|
||||
return port::kMaxInt32;
|
||||
} else {
|
||||
// res fits in int
|
||||
return static_cast<int>(res);
|
||||
|
||||
+22
-23
@@ -383,7 +383,7 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
|
||||
int NumTableFilesAtLevel(int level, int cf) {
|
||||
return GetProperty(cf,
|
||||
"rocksdb.num-files-at-level" + std::to_string(level));
|
||||
"rocksdb.num-files-at-level" + ToString(level));
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
@@ -783,7 +783,7 @@ TEST_P(ColumnFamilyTest, BulkAddDrop) {
|
||||
std::vector<std::string> cf_names;
|
||||
std::vector<ColumnFamilyHandle*> cf_handles;
|
||||
for (int i = 1; i <= kNumCF; i++) {
|
||||
cf_names.push_back("cf1-" + std::to_string(i));
|
||||
cf_names.push_back("cf1-" + ToString(i));
|
||||
}
|
||||
ASSERT_OK(db_->CreateColumnFamilies(cf_options, cf_names, &cf_handles));
|
||||
for (int i = 1; i <= kNumCF; i++) {
|
||||
@@ -796,8 +796,7 @@ TEST_P(ColumnFamilyTest, BulkAddDrop) {
|
||||
}
|
||||
cf_handles.clear();
|
||||
for (int i = 1; i <= kNumCF; i++) {
|
||||
cf_descriptors.emplace_back("cf2-" + std::to_string(i),
|
||||
ColumnFamilyOptions());
|
||||
cf_descriptors.emplace_back("cf2-" + ToString(i), ColumnFamilyOptions());
|
||||
}
|
||||
ASSERT_OK(db_->CreateColumnFamilies(cf_descriptors, &cf_handles));
|
||||
for (int i = 1; i <= kNumCF; i++) {
|
||||
@@ -821,7 +820,7 @@ TEST_P(ColumnFamilyTest, DropTest) {
|
||||
Open({"default"});
|
||||
CreateColumnFamiliesAndReopen({"pikachu"});
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
ASSERT_OK(Put(1, std::to_string(i), "bar" + std::to_string(i)));
|
||||
ASSERT_OK(Put(1, ToString(i), "bar" + ToString(i)));
|
||||
}
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
@@ -1345,7 +1344,7 @@ TEST_P(ColumnFamilyTest, DifferentCompactionStyles) {
|
||||
PutRandomData(1, 10, 12000);
|
||||
PutRandomData(1, 1, 10);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
|
||||
// SETUP column family "two" -- level style with 4 levels
|
||||
@@ -1353,7 +1352,7 @@ TEST_P(ColumnFamilyTest, DifferentCompactionStyles) {
|
||||
PutRandomData(2, 10, 12000);
|
||||
PutRandomData(2, 1, 10);
|
||||
WaitForFlush(2);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 2);
|
||||
AssertFilesPerLevel(ToString(i + 1), 2);
|
||||
}
|
||||
|
||||
// TRIGGER compaction "one"
|
||||
@@ -1417,7 +1416,7 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
@@ -1447,7 +1446,7 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
|
||||
PutRandomData(2, 10, 12000);
|
||||
PutRandomData(2, 1, 10);
|
||||
WaitForFlush(2);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 2);
|
||||
AssertFilesPerLevel(ToString(i + 1), 2);
|
||||
}
|
||||
threads.emplace_back([&] {
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::MultiManual:1");
|
||||
@@ -1534,7 +1533,7 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::AutoManual:1");
|
||||
@@ -1544,7 +1543,7 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
|
||||
PutRandomData(2, 10, 12000);
|
||||
PutRandomData(2, 1, 10);
|
||||
WaitForFlush(2);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 2);
|
||||
AssertFilesPerLevel(ToString(i + 1), 2);
|
||||
}
|
||||
ROCKSDB_NAMESPACE::port::Thread threads([&] {
|
||||
CompactRangeOptions compact_options;
|
||||
@@ -1616,7 +1615,7 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
@@ -1651,7 +1650,7 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
|
||||
PutRandomData(2, 10, 12000);
|
||||
PutRandomData(2, 1, 10);
|
||||
WaitForFlush(2);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 2);
|
||||
AssertFilesPerLevel(ToString(i + 1), 2);
|
||||
}
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:5");
|
||||
threads.join();
|
||||
@@ -1710,7 +1709,7 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
@@ -1749,8 +1748,8 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(
|
||||
std::to_string(one.level0_file_num_compaction_trigger + i), 1);
|
||||
AssertFilesPerLevel(ToString(one.level0_file_num_compaction_trigger + i),
|
||||
1);
|
||||
}
|
||||
|
||||
ROCKSDB_NAMESPACE::port::Thread threads1([&] {
|
||||
@@ -1812,7 +1811,7 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
@@ -1850,8 +1849,8 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(
|
||||
std::to_string(one.level0_file_num_compaction_trigger + i), 1);
|
||||
AssertFilesPerLevel(ToString(one.level0_file_num_compaction_trigger + i),
|
||||
1);
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:1");
|
||||
@@ -1905,7 +1904,7 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
bool cf_1_1 = true;
|
||||
bool cf_1_2 = true;
|
||||
@@ -1943,8 +1942,8 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(
|
||||
std::to_string(one.level0_file_num_compaction_trigger + i), 1);
|
||||
AssertFilesPerLevel(ToString(one.level0_file_num_compaction_trigger + i),
|
||||
1);
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::ManualAuto:1");
|
||||
@@ -2025,7 +2024,7 @@ TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
|
||||
PutRandomData(1, 10, 12000, true);
|
||||
PutRandomData(1, 1, 10, true);
|
||||
WaitForFlush(1);
|
||||
AssertFilesPerLevel(std::to_string(i + 1), 1);
|
||||
AssertFilesPerLevel(ToString(i + 1), 1);
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT("ColumnFamilyTest::AutoManual:5");
|
||||
|
||||
+11
-11
@@ -91,8 +91,8 @@ TEST_F(CompactFilesTest, L0ConflictsFiles) {
|
||||
// create couple files
|
||||
// Background compaction starts and waits in BackgroundCallCompaction:0
|
||||
for (int i = 0; i < kLevel0Trigger * 4; ++i) {
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(i), ""));
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(100 - i), ""));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i), ""));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(100 - i), ""));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ TEST_F(CompactFilesTest, MultipleLevel) {
|
||||
// create couple files in L0, L3, L4 and L5
|
||||
for (int i = 5; i > 2; --i) {
|
||||
collector->ClearFlushedFiles();
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(i), ""));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i), ""));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
// Ensure background work is fully finished including listener callbacks
|
||||
// before accessing listener state.
|
||||
@@ -145,11 +145,11 @@ TEST_F(CompactFilesTest, MultipleLevel) {
|
||||
ASSERT_OK(db->CompactFiles(CompactionOptions(), l0_files, i));
|
||||
|
||||
std::string prop;
|
||||
ASSERT_TRUE(db->GetProperty(
|
||||
"rocksdb.num-files-at-level" + std::to_string(i), &prop));
|
||||
ASSERT_TRUE(
|
||||
db->GetProperty("rocksdb.num-files-at-level" + ToString(i), &prop));
|
||||
ASSERT_EQ("1", prop);
|
||||
}
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(0), ""));
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(0), ""));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
|
||||
ColumnFamilyMetaData meta;
|
||||
@@ -218,7 +218,7 @@ TEST_F(CompactFilesTest, ObsoleteFiles) {
|
||||
|
||||
// create couple files
|
||||
for (int i = 1000; i < 2000; ++i) {
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(i),
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(kWriteBufferSize / 10, 'a' + (i % 26))));
|
||||
}
|
||||
|
||||
@@ -257,14 +257,14 @@ TEST_F(CompactFilesTest, NotCutOutputOnLevel0) {
|
||||
|
||||
// create couple files
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(i),
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(1000, 'a' + (i % 26))));
|
||||
}
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable());
|
||||
auto l0_files_1 = collector->GetFlushedFiles();
|
||||
collector->ClearFlushedFiles();
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(i),
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(1000, 'a' + (i % 26))));
|
||||
}
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable());
|
||||
@@ -295,7 +295,7 @@ TEST_F(CompactFilesTest, CapturingPendingFiles) {
|
||||
|
||||
// Create 5 files.
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key" + std::to_string(i), "value"));
|
||||
ASSERT_OK(db->Put(WriteOptions(), "key" + ToString(i), "value"));
|
||||
ASSERT_OK(db->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ TEST_F(CompactFilesTest, GetCompactionJobInfo) {
|
||||
|
||||
// create couple files
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
ASSERT_OK(db->Put(WriteOptions(), std::to_string(i),
|
||||
ASSERT_OK(db->Put(WriteOptions(), ToString(i),
|
||||
std::string(1000, 'a' + (i % 26))));
|
||||
}
|
||||
ASSERT_OK(static_cast_with_check<DBImpl>(db)->TEST_WaitForFlushMemTable());
|
||||
|
||||
@@ -518,7 +518,7 @@ uint64_t Compaction::OutputFilePreallocationSize() const {
|
||||
}
|
||||
}
|
||||
|
||||
if (max_output_file_size_ != std::numeric_limits<uint64_t>::max() &&
|
||||
if (max_output_file_size_ != port::kMaxUint64 &&
|
||||
(immutable_options_.compaction_style == kCompactionStyleLevel ||
|
||||
output_level() > 0)) {
|
||||
preallocation_size = std::min(max_output_file_size_, preallocation_size);
|
||||
@@ -616,7 +616,7 @@ bool Compaction::DoesInputReferenceBlobFiles() const {
|
||||
|
||||
uint64_t Compaction::MinInputFileOldestAncesterTime(
|
||||
const InternalKey* start, const InternalKey* end) const {
|
||||
uint64_t min_oldest_ancester_time = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t min_oldest_ancester_time = port::kMaxUint64;
|
||||
const InternalKeyComparator& icmp =
|
||||
column_family_data()->internal_comparator();
|
||||
for (const auto& level_files : inputs_) {
|
||||
|
||||
@@ -28,8 +28,7 @@ CompactionIterator::CompactionIterator(
|
||||
Env* env, bool report_detailed_time, bool expect_valid_internal_key,
|
||||
CompactionRangeDelAggregator* range_del_agg,
|
||||
BlobFileBuilder* blob_file_builder, bool allow_data_in_errors,
|
||||
bool enforce_single_del_contracts, const Compaction* compaction,
|
||||
const CompactionFilter* compaction_filter,
|
||||
const Compaction* compaction, const CompactionFilter* compaction_filter,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
const std::atomic<int>* manual_compaction_paused,
|
||||
const std::atomic<bool>* manual_compaction_canceled,
|
||||
@@ -39,7 +38,7 @@ CompactionIterator::CompactionIterator(
|
||||
input, cmp, merge_helper, last_sequence, snapshots,
|
||||
earliest_write_conflict_snapshot, job_snapshot, snapshot_checker, env,
|
||||
report_detailed_time, expect_valid_internal_key, range_del_agg,
|
||||
blob_file_builder, allow_data_in_errors, enforce_single_del_contracts,
|
||||
blob_file_builder, allow_data_in_errors,
|
||||
std::unique_ptr<CompactionProxy>(
|
||||
compaction ? new RealCompaction(compaction) : nullptr),
|
||||
compaction_filter, shutting_down, manual_compaction_paused,
|
||||
@@ -53,7 +52,6 @@ CompactionIterator::CompactionIterator(
|
||||
Env* env, bool report_detailed_time, bool expect_valid_internal_key,
|
||||
CompactionRangeDelAggregator* range_del_agg,
|
||||
BlobFileBuilder* blob_file_builder, bool allow_data_in_errors,
|
||||
bool enforce_single_del_contracts,
|
||||
std::unique_ptr<CompactionProxy> compaction,
|
||||
const CompactionFilter* compaction_filter,
|
||||
const std::atomic<bool>* shutting_down,
|
||||
@@ -82,7 +80,6 @@ CompactionIterator::CompactionIterator(
|
||||
manual_compaction_canceled_(manual_compaction_canceled),
|
||||
info_log_(info_log),
|
||||
allow_data_in_errors_(allow_data_in_errors),
|
||||
enforce_single_del_contracts_(enforce_single_del_contracts),
|
||||
timestamp_size_(cmp_ ? cmp_->timestamp_size() : 0),
|
||||
full_history_ts_low_(full_history_ts_low),
|
||||
current_user_key_sequence_(0),
|
||||
@@ -310,14 +307,6 @@ bool CompactionIterator::InvokeFilterIfNeeded(bool* need_skip,
|
||||
// no value associated with delete
|
||||
value_.clear();
|
||||
iter_stats_.num_record_drop_user++;
|
||||
} else if (filter == CompactionFilter::Decision::kPurge) {
|
||||
// convert the current key to a single delete; key_ is pointing into
|
||||
// current_key_ at this point, so updating current_key_ updates key()
|
||||
ikey_.type = kTypeSingleDeletion;
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, kTypeSingleDeletion);
|
||||
// no value associated with single delete
|
||||
value_.clear();
|
||||
iter_stats_.num_record_drop_user++;
|
||||
} else if (filter == CompactionFilter::Decision::kChangeValue) {
|
||||
if (ikey_.type == kTypeBlobIndex) {
|
||||
// value transfer from blob file to inlined data
|
||||
@@ -636,39 +625,24 @@ void CompactionIterator::NextFromInput() {
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"CompactionIterator::NextFromInput:SingleDelete:2", nullptr);
|
||||
if (next_ikey.type == kTypeSingleDeletion) {
|
||||
if (next_ikey.type == kTypeSingleDeletion ||
|
||||
next_ikey.type == kTypeDeletion) {
|
||||
// We encountered two SingleDeletes for same key in a row. This
|
||||
// could be due to unexpected user input. If write-(un)prepared
|
||||
// transaction is used, this could also be due to releasing an old
|
||||
// snapshot between a Put and its matching SingleDelete.
|
||||
// Furthermore, if write-(un)prepared transaction is rolled back
|
||||
// after prepare, we will write a Delete to cancel a prior Put. If
|
||||
// old snapshot is released between a later Put and its matching
|
||||
// SingleDelete, we will end up with a Delete followed by
|
||||
// SingleDelete.
|
||||
// Skip the first SingleDelete and let the next iteration decide
|
||||
// how to handle the second SingleDelete.
|
||||
// how to handle the second SingleDelete or Delete.
|
||||
|
||||
// First SingleDelete has been skipped since we already called
|
||||
// input_.Next().
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
++iter_stats_.num_single_del_mismatch;
|
||||
} else if (next_ikey.type == kTypeDeletion) {
|
||||
std::ostringstream oss;
|
||||
oss << "Found SD and type: " << static_cast<int>(next_ikey.type)
|
||||
<< " on the same key, violating the contract "
|
||||
"of SingleDelete. Check your application to make sure the "
|
||||
"application does not mix SingleDelete and Delete for "
|
||||
"the same key. If you are using "
|
||||
"write-prepared/write-unprepared transactions, and use "
|
||||
"SingleDelete to delete certain keys, then make sure "
|
||||
"TransactionDBOptions::rollback_deletion_type_callback is "
|
||||
"configured properly. Mixing SD and DEL can lead to "
|
||||
"undefined behaviors";
|
||||
++iter_stats_.num_record_drop_obsolete;
|
||||
++iter_stats_.num_single_del_mismatch;
|
||||
if (enforce_single_del_contracts_) {
|
||||
ROCKS_LOG_ERROR(info_log_, "%s", oss.str().c_str());
|
||||
valid_ = false;
|
||||
status_ = Status::Corruption(oss.str());
|
||||
return;
|
||||
}
|
||||
ROCKS_LOG_WARN(info_log_, "%s", oss.str().c_str());
|
||||
} else if (!is_timestamp_eligible_for_gc) {
|
||||
// We cannot drop the SingleDelete as timestamp is enabled, and
|
||||
// timestamp of this key is greater than or equal to
|
||||
|
||||
@@ -176,7 +176,7 @@ class CompactionIterator {
|
||||
Env* env, bool report_detailed_time, bool expect_valid_internal_key,
|
||||
CompactionRangeDelAggregator* range_del_agg,
|
||||
BlobFileBuilder* blob_file_builder, bool allow_data_in_errors,
|
||||
bool enforce_single_del_contracts, const Compaction* compaction = nullptr,
|
||||
const Compaction* compaction = nullptr,
|
||||
const CompactionFilter* compaction_filter = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr,
|
||||
const std::atomic<int>* manual_compaction_paused = nullptr,
|
||||
@@ -193,7 +193,6 @@ class CompactionIterator {
|
||||
Env* env, bool report_detailed_time, bool expect_valid_internal_key,
|
||||
CompactionRangeDelAggregator* range_del_agg,
|
||||
BlobFileBuilder* blob_file_builder, bool allow_data_in_errors,
|
||||
bool enforce_single_del_contracts,
|
||||
std::unique_ptr<CompactionProxy> compaction,
|
||||
const CompactionFilter* compaction_filter = nullptr,
|
||||
const std::atomic<bool>* shutting_down = nullptr,
|
||||
@@ -333,8 +332,6 @@ class CompactionIterator {
|
||||
|
||||
bool allow_data_in_errors_;
|
||||
|
||||
const bool enforce_single_del_contracts_;
|
||||
|
||||
// Comes from comparator.
|
||||
const size_t timestamp_size_;
|
||||
|
||||
|
||||
@@ -279,8 +279,7 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
|
||||
snapshot_checker_.get(), Env::Default(),
|
||||
false /* report_detailed_time */, false, range_del_agg_.get(),
|
||||
nullptr /* blob_file_builder */, true /*allow_data_in_errors*/,
|
||||
true /*enforce_single_del_contracts*/, std::move(compaction), filter,
|
||||
&shutting_down_,
|
||||
std::move(compaction), filter, &shutting_down_,
|
||||
/*manual_compaction_paused=*/nullptr,
|
||||
/*manual_compaction_canceled=*/nullptr, /*info_log=*/nullptr,
|
||||
full_history_ts_low));
|
||||
@@ -314,7 +313,7 @@ class CompactionIteratorTest : public testing::TestWithParam<bool> {
|
||||
key_not_exists_beyond_output_level, full_history_ts_low);
|
||||
c_iter_->SeekToFirst();
|
||||
for (size_t i = 0; i < expected_keys.size(); i++) {
|
||||
std::string info = "i = " + std::to_string(i);
|
||||
std::string info = "i = " + ToString(i);
|
||||
ASSERT_TRUE(c_iter_->Valid()) << info;
|
||||
ASSERT_OK(c_iter_->status()) << info;
|
||||
ASSERT_EQ(expected_keys[i], c_iter_->key().ToString()) << info;
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
#include "table/block_based/block_based_table_factory.h"
|
||||
#include "table/merging_iterator.h"
|
||||
#include "table/table_builder.h"
|
||||
#include "table/unique_id_impl.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/hash.h"
|
||||
@@ -1048,7 +1047,6 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
const Compaction* compaction = sub_compact->compaction;
|
||||
CompactionServiceInput compaction_input;
|
||||
compaction_input.output_level = compaction->output_level();
|
||||
compaction_input.db_id = db_id_;
|
||||
|
||||
const std::vector<CompactionInputFiles>& inputs =
|
||||
*(compact_->compaction->inputs());
|
||||
@@ -1210,7 +1208,6 @@ CompactionJob::ProcessKeyValueCompactionWithCompactionService(
|
||||
meta.oldest_ancester_time = file.oldest_ancester_time;
|
||||
meta.file_creation_time = file.file_creation_time;
|
||||
meta.marked_for_compaction = file.marked_for_compaction;
|
||||
meta.unique_id = file.unique_id;
|
||||
|
||||
auto cfd = compaction->column_family_data();
|
||||
sub_compact->outputs.emplace_back(std::move(meta),
|
||||
@@ -1353,7 +1350,7 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
ReadOptions read_options;
|
||||
read_options.verify_checksums = true;
|
||||
read_options.fill_cache = false;
|
||||
read_options.rate_limiter_priority = GetRateLimiterPriority();
|
||||
read_options.rate_limiter_priority = Env::IO_LOW;
|
||||
// Compaction iterators shouldn't be confined to a single prefix.
|
||||
// Compactions use Seek() for
|
||||
// (a) concurrent compactions,
|
||||
@@ -1482,9 +1479,9 @@ void CompactionJob::ProcessKeyValueCompaction(SubcompactionState* sub_compact) {
|
||||
snapshot_checker_, env_, ShouldReportDetailedTime(env_, stats_),
|
||||
/*expect_valid_internal_key=*/true, &range_del_agg,
|
||||
blob_file_builder.get(), db_options_.allow_data_in_errors,
|
||||
db_options_.enforce_single_del_contracts, sub_compact->compaction,
|
||||
compaction_filter, shutting_down_, manual_compaction_paused_,
|
||||
manual_compaction_canceled_, db_options_.info_log, full_history_ts_low));
|
||||
sub_compact->compaction, compaction_filter, shutting_down_,
|
||||
manual_compaction_paused_, manual_compaction_canceled_,
|
||||
db_options_.info_log, full_history_ts_low));
|
||||
auto c_iter = sub_compact->c_iter.get();
|
||||
c_iter->SeekToFirst();
|
||||
if (c_iter->Valid() && sub_compact->compaction->output_level() != 0) {
|
||||
@@ -1977,8 +1974,7 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
refined_oldest_ancester_time =
|
||||
sub_compact->compaction->MinInputFileOldestAncesterTime(
|
||||
&(meta->smallest), &(meta->largest));
|
||||
if (refined_oldest_ancester_time !=
|
||||
std::numeric_limits<uint64_t>::max()) {
|
||||
if (refined_oldest_ancester_time != port::kMaxUint64) {
|
||||
meta->oldest_ancester_time = refined_oldest_ancester_time;
|
||||
}
|
||||
}
|
||||
@@ -2115,11 +2111,11 @@ Status CompactionJob::InstallCompactionResults(
|
||||
|
||||
{
|
||||
Compaction::InputLevelSummaryBuffer inputs_summary;
|
||||
ROCKS_LOG_BUFFER(log_buffer_,
|
||||
"[%s] [JOB %d] Compacted %s => %" PRIu64 " bytes",
|
||||
compaction->column_family_data()->GetName().c_str(),
|
||||
job_id_, compaction->InputLevelSummary(&inputs_summary),
|
||||
compact_->total_bytes + compact_->total_blob_bytes);
|
||||
ROCKS_LOG_INFO(db_options_.info_log,
|
||||
"[%s] [JOB %d] Compacted %s => %" PRIu64 " bytes",
|
||||
compaction->column_family_data()->GetName().c_str(), job_id_,
|
||||
compaction->InputLevelSummary(&inputs_summary),
|
||||
compact_->total_bytes + compact_->total_blob_bytes);
|
||||
}
|
||||
|
||||
VersionEdit* const edit = compaction->edit();
|
||||
@@ -2268,7 +2264,7 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
sub_compact->compaction->MinInputFileOldestAncesterTime(
|
||||
(sub_compact->start != nullptr) ? &tmp_start : nullptr,
|
||||
(sub_compact->end != nullptr) ? &tmp_end : nullptr);
|
||||
if (oldest_ancester_time == std::numeric_limits<uint64_t>::max()) {
|
||||
if (oldest_ancester_time == port::kMaxUint64) {
|
||||
oldest_ancester_time = current_time;
|
||||
}
|
||||
|
||||
@@ -2280,18 +2276,6 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
meta.oldest_ancester_time = oldest_ancester_time;
|
||||
meta.file_creation_time = current_time;
|
||||
meta.temperature = temperature;
|
||||
assert(!db_id_.empty());
|
||||
assert(!db_session_id_.empty());
|
||||
s = GetSstInternalUniqueId(db_id_, db_session_id_, meta.fd.GetNumber(),
|
||||
&meta.unique_id);
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_ERROR(db_options_.info_log,
|
||||
"[%s] [JOB %d] file #%" PRIu64
|
||||
" failed to generate unique id: %s.",
|
||||
cfd->GetName().c_str(), job_id_, meta.fd.GetNumber(),
|
||||
s.ToString().c_str());
|
||||
return s;
|
||||
}
|
||||
sub_compact->outputs.emplace_back(
|
||||
std::move(meta), cfd->internal_comparator(),
|
||||
/*enable_order_check=*/
|
||||
@@ -2300,7 +2284,7 @@ Status CompactionJob::OpenCompactionOutputFile(
|
||||
/*enable_hash=*/paranoid_file_checks_);
|
||||
}
|
||||
|
||||
writable_file->SetIOPriority(GetRateLimiterPriority());
|
||||
writable_file->SetIOPriority(Env::IOPriority::IO_LOW);
|
||||
writable_file->SetWriteLifeTimeHint(write_hint_);
|
||||
FileTypeSet tmp_set = db_options_.checksum_handoff_file_types;
|
||||
writable_file->SetPreallocationBlockSize(static_cast<size_t>(
|
||||
@@ -2474,7 +2458,7 @@ void CompactionJob::LogCompaction() {
|
||||
<< "compaction_reason"
|
||||
<< GetCompactionReasonString(compaction->compaction_reason());
|
||||
for (size_t i = 0; i < compaction->num_input_levels(); ++i) {
|
||||
stream << ("files_L" + std::to_string(compaction->level(i)));
|
||||
stream << ("files_L" + ToString(compaction->level(i)));
|
||||
stream.StartArray();
|
||||
for (auto f : *compaction->inputs(i)) {
|
||||
stream << f->fd.GetNumber();
|
||||
@@ -2491,19 +2475,6 @@ std::string CompactionJob::GetTableFileName(uint64_t file_number) {
|
||||
file_number, compact_->compaction->output_path_id());
|
||||
}
|
||||
|
||||
Env::IOPriority CompactionJob::GetRateLimiterPriority() {
|
||||
if (versions_ && versions_->GetColumnFamilySet() &&
|
||||
versions_->GetColumnFamilySet()->write_controller()) {
|
||||
WriteController* write_controller =
|
||||
versions_->GetColumnFamilySet()->write_controller();
|
||||
if (write_controller->NeedsDelay() || write_controller->IsStopped()) {
|
||||
return Env::IO_USER;
|
||||
}
|
||||
}
|
||||
|
||||
return Env::IO_LOW;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
std::string CompactionServiceCompactionJob::GetTableFileName(
|
||||
uint64_t file_number) {
|
||||
@@ -2624,7 +2595,7 @@ Status CompactionServiceCompactionJob::Run() {
|
||||
meta.fd.largest_seqno, meta.smallest.Encode().ToString(),
|
||||
meta.largest.Encode().ToString(), meta.oldest_ancester_time,
|
||||
meta.file_creation_time, output_file.validator.GetHash(),
|
||||
meta.marked_for_compaction, meta.unique_id);
|
||||
meta.marked_for_compaction);
|
||||
}
|
||||
compaction_result_->num_output_records = sub_compact->num_output_records;
|
||||
compaction_result_->total_bytes = sub_compact->total_bytes;
|
||||
@@ -2728,9 +2699,6 @@ static std::unordered_map<std::string, OptionTypeInfo> cs_input_type_info = {
|
||||
{"output_level",
|
||||
{offsetof(struct CompactionServiceInput, output_level), OptionType::kInt,
|
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
|
||||
{"db_id",
|
||||
{offsetof(struct CompactionServiceInput, db_id),
|
||||
OptionType::kEncodedString}},
|
||||
{"has_begin",
|
||||
{offsetof(struct CompactionServiceInput, has_begin), OptionType::kBoolean,
|
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
|
||||
@@ -2788,11 +2756,6 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
{offsetof(struct CompactionServiceOutputFile, marked_for_compaction),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal,
|
||||
OptionTypeFlags::kNone}},
|
||||
{"unique_id",
|
||||
OptionTypeInfo::Array<uint64_t, 2>(
|
||||
offsetof(struct CompactionServiceOutputFile, unique_id),
|
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone,
|
||||
{0, OptionType::kUInt64T})},
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo>
|
||||
@@ -2988,7 +2951,6 @@ static std::unordered_map<std::string, OptionTypeInfo> cs_result_type_info = {
|
||||
const void* addr1, const void* addr2, std::string* mismatch) {
|
||||
const auto status1 = static_cast<const Status*>(addr1);
|
||||
const auto status2 = static_cast<const Status*>(addr2);
|
||||
|
||||
StatusSerializationAdapter adatper1(*status1);
|
||||
StatusSerializationAdapter adapter2(*status2);
|
||||
return OptionTypeInfo::TypesAreEqual(opts, status_adapter_type_info,
|
||||
@@ -3046,7 +3008,7 @@ Status CompactionServiceInput::Read(const std::string& data_str,
|
||||
} else {
|
||||
return Status::NotSupported(
|
||||
"Compaction Service Input data version not supported: " +
|
||||
std::to_string(format_version));
|
||||
ToString(format_version));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3075,7 +3037,7 @@ Status CompactionServiceResult::Read(const std::string& data_str,
|
||||
} else {
|
||||
return Status::NotSupported(
|
||||
"Compaction Service Result data version not supported: " +
|
||||
std::to_string(format_version));
|
||||
ToString(format_version));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,8 +137,6 @@ class CompactionJob {
|
||||
IOStatus io_status_;
|
||||
|
||||
private:
|
||||
friend class CompactionJobTestBase;
|
||||
|
||||
// Generates a histogram representing potential divisions of key ranges from
|
||||
// the input. It adds the starting and/or ending keys of certain input files
|
||||
// to the working set and then finds the approximate size of data in between
|
||||
@@ -236,10 +234,6 @@ class CompactionJob {
|
||||
// Get table file name in where it's outputting to, which should also be in
|
||||
// `output_directory_`.
|
||||
virtual std::string GetTableFileName(uint64_t file_number);
|
||||
// The rate limiter priority (io_priority) is determined dynamically here.
|
||||
// The Compaction Read and Write priorities are the same for different
|
||||
// scenarios, such as write stalled.
|
||||
Env::IOPriority GetRateLimiterPriority();
|
||||
};
|
||||
|
||||
// CompactionServiceInput is used the pass compaction information between two
|
||||
@@ -259,9 +253,6 @@ struct CompactionServiceInput {
|
||||
std::vector<std::string> input_files;
|
||||
int output_level;
|
||||
|
||||
// db_id is used to generate unique id of sst on the remote compactor
|
||||
std::string db_id;
|
||||
|
||||
// information for subcompaction
|
||||
bool has_begin = false;
|
||||
std::string begin;
|
||||
@@ -293,15 +284,13 @@ struct CompactionServiceOutputFile {
|
||||
uint64_t file_creation_time;
|
||||
uint64_t paranoid_hash;
|
||||
bool marked_for_compaction;
|
||||
UniqueId64x2 unique_id;
|
||||
|
||||
CompactionServiceOutputFile() = default;
|
||||
CompactionServiceOutputFile(
|
||||
const std::string& name, SequenceNumber smallest, SequenceNumber largest,
|
||||
std::string _smallest_internal_key, std::string _largest_internal_key,
|
||||
uint64_t _oldest_ancester_time, uint64_t _file_creation_time,
|
||||
uint64_t _paranoid_hash, bool _marked_for_compaction,
|
||||
UniqueId64x2 _unique_id)
|
||||
uint64_t _paranoid_hash, bool _marked_for_compaction)
|
||||
: file_name(name),
|
||||
smallest_seqno(smallest),
|
||||
largest_seqno(largest),
|
||||
@@ -310,8 +299,7 @@ struct CompactionServiceOutputFile {
|
||||
oldest_ancester_time(_oldest_ancester_time),
|
||||
file_creation_time(_file_creation_time),
|
||||
paranoid_hash(_paranoid_hash),
|
||||
marked_for_compaction(_marked_for_compaction),
|
||||
unique_id(std::move(_unique_id)) {}
|
||||
marked_for_compaction(_marked_for_compaction) {}
|
||||
};
|
||||
|
||||
// CompactionServiceResult contains the compaction result from a different db
|
||||
|
||||
@@ -268,10 +268,10 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
if (cf == 0) {
|
||||
// default cfd
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.num-files-at-level" + std::to_string(level), &property));
|
||||
"rocksdb.num-files-at-level" + ToString(level), &property));
|
||||
} else {
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
handles_[cf], "rocksdb.num-files-at-level" + std::to_string(level),
|
||||
handles_[cf], "rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
}
|
||||
return atoi(property.c_str());
|
||||
@@ -672,7 +672,7 @@ TEST_P(CompactionJobStatsTest, CompactionJobStatsTest) {
|
||||
snprintf(buf, kBufSize, "%d", ++num_L0_files);
|
||||
ASSERT_EQ(std::string(buf), FilesPerLevel(1));
|
||||
}
|
||||
ASSERT_EQ(std::to_string(num_L0_files), FilesPerLevel(1));
|
||||
ASSERT_EQ(ToString(num_L0_files), FilesPerLevel(1));
|
||||
|
||||
// 2nd Phase: perform L0 -> L1 compaction.
|
||||
int L0_compaction_count = 6;
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/write_buffer_manager.h"
|
||||
#include "table/mock_table.h"
|
||||
#include "table/unique_id_impl.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
@@ -207,7 +206,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
oldest_blob_file_number, kUnknownOldestAncesterTime,
|
||||
kUnknownFileCreationTime, kUnknownFileChecksum,
|
||||
kUnknownFileChecksumFuncName, kDisableUserTimestamp,
|
||||
kDisableUserTimestamp, kNullUniqueId64x2);
|
||||
kDisableUserTimestamp);
|
||||
|
||||
mutex_.Lock();
|
||||
EXPECT_OK(
|
||||
@@ -237,8 +236,8 @@ class CompactionJobTestBase : public testing::Test {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
auto contents = mock::MakeMockFile();
|
||||
for (int k = 0; k < kKeysPerFile; ++k) {
|
||||
auto key = std::to_string(i * kMatchingKeys + k);
|
||||
auto value = std::to_string(i * kKeysPerFile + k);
|
||||
auto key = ToString(i * kMatchingKeys + k);
|
||||
auto value = ToString(i * kKeysPerFile + k);
|
||||
InternalKey internal_key(key, ++sequence_number, kTypeValue);
|
||||
|
||||
// This is how the key will look like once it's written in bottommost
|
||||
@@ -322,8 +321,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
const std::vector<SequenceNumber>& snapshots = {},
|
||||
SequenceNumber earliest_write_conflict_snapshot = kMaxSequenceNumber,
|
||||
int output_level = 1, bool verify = true,
|
||||
uint64_t expected_oldest_blob_file_number = kInvalidBlobFileNumber,
|
||||
bool check_get_priority = false) {
|
||||
uint64_t expected_oldest_blob_file_number = kInvalidBlobFileNumber) {
|
||||
auto cfd = versions_->GetColumnFamilySet()->GetDefault();
|
||||
|
||||
size_t num_input_files = 0;
|
||||
@@ -361,8 +359,8 @@ class CompactionJobTestBase : public testing::Test {
|
||||
table_cache_, &event_logger, false, false, dbname_,
|
||||
&compaction_job_stats_, Env::Priority::USER, nullptr /* IOTracer */,
|
||||
/*manual_compaction_paused=*/nullptr,
|
||||
/*manual_compaction_canceled=*/nullptr, env_->GenerateUniqueId(),
|
||||
DBImpl::GenerateDbSessionId(nullptr), full_history_ts_low_);
|
||||
/*manual_compaction_canceled=*/nullptr, /*db_id=*/"",
|
||||
/*db_session_id=*/"", full_history_ts_low_);
|
||||
VerifyInitializationOfCompactionJobStats(compaction_job_stats_);
|
||||
|
||||
compaction_job.Prepare();
|
||||
@@ -392,32 +390,6 @@ class CompactionJobTestBase : public testing::Test {
|
||||
expected_oldest_blob_file_number);
|
||||
}
|
||||
}
|
||||
|
||||
if (check_get_priority) {
|
||||
CheckGetRateLimiterPriority(compaction_job);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckGetRateLimiterPriority(CompactionJob& compaction_job) {
|
||||
// When the state from WriteController is normal.
|
||||
ASSERT_EQ(compaction_job.GetRateLimiterPriority(), Env::IO_LOW);
|
||||
|
||||
WriteController* write_controller =
|
||||
compaction_job.versions_->GetColumnFamilySet()->write_controller();
|
||||
|
||||
{
|
||||
// When the state from WriteController is Delayed.
|
||||
std::unique_ptr<WriteControllerToken> delay_token =
|
||||
write_controller->GetDelayToken(1000000);
|
||||
ASSERT_EQ(compaction_job.GetRateLimiterPriority(), Env::IO_USER);
|
||||
}
|
||||
|
||||
{
|
||||
// When the state from WriteController is Stopped.
|
||||
std::unique_ptr<WriteControllerToken> stop_token =
|
||||
write_controller->GetStopToken();
|
||||
ASSERT_EQ(compaction_job.GetRateLimiterPriority(), Env::IO_USER);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Env> env_guard_;
|
||||
@@ -918,10 +890,10 @@ TEST_F(CompactionJobTest, MultiSingleDelete) {
|
||||
// -> Snapshot Put
|
||||
// K: SDel SDel Put SDel Put Put Snapshot SDel Put SDel SDel Put SDel
|
||||
// -> Snapshot Put Snapshot SDel
|
||||
// L: SDel Put SDel Put SDel Snapshot SDel Put SDel SDel Put SDel
|
||||
// -> Snapshot SDel Put SDel
|
||||
// M: (Put) SDel Put SDel Put SDel Snapshot Put SDel SDel Put SDel SDel
|
||||
// -> SDel Snapshot Put SDel
|
||||
// L: SDel Put Del Put SDel Snapshot Del Put Del SDel Put SDel
|
||||
// -> Snapshot SDel
|
||||
// M: (Put) SDel Put Del Put SDel Snapshot Put Del SDel Put SDel Del
|
||||
// -> SDel Snapshot Del
|
||||
NewDB();
|
||||
|
||||
auto file1 = mock::MakeMockFile({
|
||||
@@ -952,14 +924,14 @@ TEST_F(CompactionJobTest, MultiSingleDelete) {
|
||||
{KeyStr("L", 16U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 15U, kTypeValue), "val"},
|
||||
{KeyStr("L", 14U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 13U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 13U, kTypeDeletion), ""},
|
||||
{KeyStr("L", 12U, kTypeValue), "val"},
|
||||
{KeyStr("L", 11U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 16U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 11U, kTypeDeletion), ""},
|
||||
{KeyStr("M", 16U, kTypeDeletion), ""},
|
||||
{KeyStr("M", 15U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 14U, kTypeValue), "val"},
|
||||
{KeyStr("M", 13U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 12U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 12U, kTypeDeletion), ""},
|
||||
{KeyStr("M", 11U, kTypeValue), "val"},
|
||||
});
|
||||
AddMockFile(file1);
|
||||
@@ -1000,12 +972,12 @@ TEST_F(CompactionJobTest, MultiSingleDelete) {
|
||||
{KeyStr("K", 1U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 5U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 4U, kTypeValue), "val"},
|
||||
{KeyStr("L", 3U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 3U, kTypeDeletion), ""},
|
||||
{KeyStr("L", 2U, kTypeValue), "val"},
|
||||
{KeyStr("L", 1U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 10U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 7U, kTypeValue), "val"},
|
||||
{KeyStr("M", 5U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 5U, kTypeDeletion), ""},
|
||||
{KeyStr("M", 4U, kTypeValue), "val"},
|
||||
{KeyStr("M", 3U, kTypeSingleDeletion), ""},
|
||||
});
|
||||
@@ -1047,9 +1019,7 @@ TEST_F(CompactionJobTest, MultiSingleDelete) {
|
||||
{KeyStr("K", 8U, kTypeValue), "val3"},
|
||||
{KeyStr("L", 16U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("L", 15U, kTypeValue), ""},
|
||||
{KeyStr("L", 11U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 15U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("M", 14U, kTypeValue), ""},
|
||||
{KeyStr("M", 16U, kTypeDeletion), ""},
|
||||
{KeyStr("M", 3U, kTypeSingleDeletion), ""}});
|
||||
|
||||
SetLastSequence(22U);
|
||||
@@ -1135,21 +1105,6 @@ TEST_F(CompactionJobTest, OldestBlobFileNumber) {
|
||||
/* expected_oldest_blob_file_number */ 19);
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, NoEnforceSingleDeleteContract) {
|
||||
db_options_.enforce_single_del_contracts = false;
|
||||
NewDB();
|
||||
|
||||
auto file =
|
||||
mock::MakeMockFile({{KeyStr("a", 4U, kTypeSingleDeletion), ""},
|
||||
{KeyStr("a", 3U, kTypeDeletion), "dontcare"}});
|
||||
AddMockFile(file);
|
||||
SetLastSequence(4U);
|
||||
|
||||
auto expected_results = mock::MakeMockFile();
|
||||
auto files = cfd_->current()->storage_info()->LevelFiles(0);
|
||||
RunCompaction({files}, expected_results);
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, InputSerialization) {
|
||||
// Setup a random CompactionServiceInput
|
||||
CompactionServiceInput input;
|
||||
@@ -1255,14 +1210,13 @@ TEST_F(CompactionJobTest, ResultSerialization) {
|
||||
result.status =
|
||||
status_list.at(rnd.Uniform(static_cast<int>(status_list.size())));
|
||||
while (!rnd.OneIn(10)) {
|
||||
UniqueId64x2 id{rnd64.Uniform(UINT64_MAX), rnd64.Uniform(UINT64_MAX)};
|
||||
result.output_files.emplace_back(
|
||||
rnd.RandomString(rnd.Uniform(kStrMaxLen)), rnd64.Uniform(UINT64_MAX),
|
||||
rnd64.Uniform(UINT64_MAX),
|
||||
rnd.RandomBinaryString(rnd.Uniform(kStrMaxLen)),
|
||||
rnd.RandomBinaryString(rnd.Uniform(kStrMaxLen)),
|
||||
rnd64.Uniform(UINT64_MAX), rnd64.Uniform(UINT64_MAX),
|
||||
rnd64.Uniform(UINT64_MAX), rnd.OneIn(2), id);
|
||||
rnd64.Uniform(UINT64_MAX), rnd.OneIn(2));
|
||||
}
|
||||
result.output_level = rnd.Uniform(10);
|
||||
result.output_path = rnd.RandomString(rnd.Uniform(kStrMaxLen));
|
||||
@@ -1290,16 +1244,6 @@ TEST_F(CompactionJobTest, ResultSerialization) {
|
||||
ASSERT_FALSE(deserialized1.TEST_Equals(&result, &mismatch));
|
||||
ASSERT_EQ(mismatch, "stats.num_input_files");
|
||||
|
||||
// Test unique id mismatch
|
||||
if (!result.output_files.empty()) {
|
||||
CompactionServiceResult deserialized_tmp;
|
||||
ASSERT_OK(CompactionServiceResult::Read(output, &deserialized_tmp));
|
||||
deserialized_tmp.output_files[0].unique_id[0] += 1;
|
||||
ASSERT_FALSE(deserialized_tmp.TEST_Equals(&result, &mismatch));
|
||||
ASSERT_EQ(mismatch, "output_files.unique_id");
|
||||
deserialized_tmp.status.PermitUncheckedError();
|
||||
}
|
||||
|
||||
// Test unknown field
|
||||
CompactionServiceResult deserialized2;
|
||||
output.clear();
|
||||
@@ -1342,17 +1286,6 @@ TEST_F(CompactionJobTest, ResultSerialization) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionJobTest, GetRateLimiterPriority) {
|
||||
NewDB();
|
||||
|
||||
auto expected_results = CreateTwoFiles(false);
|
||||
auto cfd = versions_->GetColumnFamilySet()->GetDefault();
|
||||
auto files = cfd->current()->storage_info()->LevelFiles(0);
|
||||
ASSERT_EQ(2U, files.size());
|
||||
RunCompaction({files}, expected_results, {}, kMaxSequenceNumber, 1, true,
|
||||
kInvalidBlobFileNumber, true);
|
||||
}
|
||||
|
||||
class CompactionJobTimestampTest : public CompactionJobTestBase {
|
||||
public:
|
||||
CompactionJobTimestampTest()
|
||||
|
||||
@@ -65,7 +65,7 @@ bool FindIntraL0Compaction(const std::vector<FileMetaData*>& level_files,
|
||||
size_t compact_bytes = static_cast<size_t>(level_files[start]->fd.file_size);
|
||||
uint64_t compensated_compact_bytes =
|
||||
level_files[start]->compensated_file_size;
|
||||
size_t compact_bytes_per_del_file = std::numeric_limits<size_t>::max();
|
||||
size_t compact_bytes_per_del_file = port::kMaxSizet;
|
||||
// Compaction range will be [start, limit).
|
||||
size_t limit;
|
||||
// Pull in files until the amount of compaction work per deleted file begins
|
||||
@@ -401,7 +401,7 @@ Status CompactionPicker::GetCompactionInputsFromFileNumbers(
|
||||
"Cannot find matched SST files for the following file numbers:");
|
||||
for (auto fn : *input_set) {
|
||||
message += " ";
|
||||
message += std::to_string(fn);
|
||||
message += ToString(fn);
|
||||
}
|
||||
return Status::InvalidArgument(message);
|
||||
}
|
||||
@@ -717,7 +717,7 @@ Compaction* CompactionPicker::CompactRange(
|
||||
// files that are created during the current compaction.
|
||||
if (compact_range_options.bottommost_level_compaction ==
|
||||
BottommostLevelCompaction::kForceOptimized &&
|
||||
max_file_num_to_ignore != std::numeric_limits<uint64_t>::max()) {
|
||||
max_file_num_to_ignore != port::kMaxUint64) {
|
||||
assert(input_level == output_level);
|
||||
// inputs_shrunk holds a continuous subset of input files which were all
|
||||
// created before the current manual compaction
|
||||
@@ -1004,14 +1004,14 @@ Status CompactionPicker::SanitizeCompactionInputFiles(
|
||||
return Status::InvalidArgument(
|
||||
"Output level for column family " + cf_meta.name +
|
||||
" must between [0, " +
|
||||
std::to_string(cf_meta.levels[cf_meta.levels.size() - 1].level) + "].");
|
||||
ToString(cf_meta.levels[cf_meta.levels.size() - 1].level) + "].");
|
||||
}
|
||||
|
||||
if (output_level > MaxOutputLevel()) {
|
||||
return Status::InvalidArgument(
|
||||
"Exceed the maximum output level defined by "
|
||||
"the current compaction algorithm --- " +
|
||||
std::to_string(MaxOutputLevel()));
|
||||
ToString(MaxOutputLevel()));
|
||||
}
|
||||
|
||||
if (output_level < 0) {
|
||||
@@ -1061,8 +1061,8 @@ Status CompactionPicker::SanitizeCompactionInputFiles(
|
||||
return Status::InvalidArgument(
|
||||
"Cannot compact file to up level, input file: " +
|
||||
MakeTableFileName("", file_num) + " level " +
|
||||
std::to_string(input_file_level) + " > output level " +
|
||||
std::to_string(output_level));
|
||||
ToString(input_file_level) + " > output level " +
|
||||
ToString(output_level));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -504,7 +504,7 @@ bool LevelCompactionBuilder::PickIntraL0Compaction() {
|
||||
return false;
|
||||
}
|
||||
return FindIntraL0Compaction(level_files, kMinFilesForIntraL0Compaction,
|
||||
std::numeric_limits<uint64_t>::max(),
|
||||
port::kMaxUint64,
|
||||
mutable_cf_options_.max_compaction_bytes,
|
||||
&start_level_inputs_, earliest_mem_seqno_);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "db/compaction/compaction_picker_level.h"
|
||||
#include "db/compaction/compaction_picker_universal.h"
|
||||
#include "db/compaction/file_pri.h"
|
||||
#include "table/unique_id_impl.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "test_util/testutil.h"
|
||||
#include "util/string_util.h"
|
||||
@@ -116,7 +115,7 @@ class CompactionPickerTest : public testing::Test {
|
||||
largest_seq, marked_for_compact, temperature, kInvalidBlobFileNumber,
|
||||
kUnknownOldestAncesterTime, kUnknownFileCreationTime,
|
||||
kUnknownFileChecksum, kUnknownFileChecksumFuncName,
|
||||
kDisableUserTimestamp, kDisableUserTimestamp, kNullUniqueId64x2);
|
||||
kDisableUserTimestamp, kDisableUserTimestamp);
|
||||
f->compensated_file_size =
|
||||
(compensated_file_size != 0) ? compensated_file_size : file_size;
|
||||
f->oldest_ancester_time = oldest_ancestor_time;
|
||||
@@ -274,9 +273,9 @@ TEST_F(CompactionPickerTest, NeedsCompactionLevel) {
|
||||
// start a brand new version in each test.
|
||||
NewVersionStorage(kLevels, kCompactionStyleLevel);
|
||||
for (int i = 0; i < file_count; ++i) {
|
||||
Add(level, i, std::to_string((i + 100) * 1000).c_str(),
|
||||
std::to_string((i + 100) * 1000 + 999).c_str(), file_size, 0,
|
||||
i * 100, i * 100 + 99);
|
||||
Add(level, i, ToString((i + 100) * 1000).c_str(),
|
||||
ToString((i + 100) * 1000 + 999).c_str(),
|
||||
file_size, 0, i * 100, i * 100 + 99);
|
||||
}
|
||||
UpdateVersionStorageInfo();
|
||||
ASSERT_EQ(vstorage_->CompactionScoreLevel(0), level);
|
||||
@@ -440,8 +439,8 @@ TEST_F(CompactionPickerTest, NeedsCompactionUniversal) {
|
||||
for (int i = 1;
|
||||
i <= mutable_cf_options_.level0_file_num_compaction_trigger * 2; ++i) {
|
||||
NewVersionStorage(1, kCompactionStyleUniversal);
|
||||
Add(0, i, std::to_string((i + 100) * 1000).c_str(),
|
||||
std::to_string((i + 100) * 1000 + 999).c_str(), 1000000, 0, i * 100,
|
||||
Add(0, i, ToString((i + 100) * 1000).c_str(),
|
||||
ToString((i + 100) * 1000 + 999).c_str(), 1000000, 0, i * 100,
|
||||
i * 100 + 99);
|
||||
UpdateVersionStorageInfo();
|
||||
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
|
||||
@@ -853,17 +852,17 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace4) {
|
||||
// L3: (1101, 1180) (1201, 1280) ... (7901, 7908)
|
||||
// L4: (1130, 1150) (1160, 1210) (1230, 1250) (1260 1310) ... (7960, 8010)
|
||||
for (int i = 11; i < 79; i++) {
|
||||
Add(3, 100 + i * 3, std::to_string(i * 100).c_str(),
|
||||
std::to_string(i * 100 + 80).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(3, 100 + i * 3, ToString(i * 100).c_str(),
|
||||
ToString(i * 100 + 80).c_str(), kFileSize, 0, 200, 251);
|
||||
// Add a tie breaker
|
||||
if (i == 66) {
|
||||
Add(3, 10000U, "6690", "6699", kFileSize, 0, 200, 251);
|
||||
}
|
||||
|
||||
Add(4, 100 + i * 3 + 1, std::to_string(i * 100 + 30).c_str(),
|
||||
std::to_string(i * 100 + 50).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(4, 100 + i * 3 + 2, std::to_string(i * 100 + 60).c_str(),
|
||||
std::to_string(i * 100 + 110).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(4, 100 + i * 3 + 1, ToString(i * 100 + 30).c_str(),
|
||||
ToString(i * 100 + 50).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(4, 100 + i * 3 + 2, ToString(i * 100 + 60).c_str(),
|
||||
ToString(i * 100 + 110).c_str(), kFileSize, 0, 200, 251);
|
||||
}
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
@@ -900,14 +899,14 @@ TEST_F(CompactionPickerTest, UniversalIncrementalSpace5) {
|
||||
// L3: (1101, 1180) (1201, 1280) ... (7901, 7908)
|
||||
// L4: (1130, 1150) (1160, 1210) (1230, 1250) (1260 1310) ... (7960, 8010)
|
||||
for (int i = 11; i < 70; i++) {
|
||||
Add(3, 100 + i * 3, std::to_string(i * 100).c_str(),
|
||||
std::to_string(i * 100 + 80).c_str(),
|
||||
Add(3, 100 + i * 3, ToString(i * 100).c_str(),
|
||||
ToString(i * 100 + 80).c_str(),
|
||||
i % 10 == 9 ? kFileSize * 100 : kFileSize, 0, 200, 251);
|
||||
|
||||
Add(4, 100 + i * 3 + 1, std::to_string(i * 100 + 30).c_str(),
|
||||
std::to_string(i * 100 + 50).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(4, 100 + i * 3 + 2, std::to_string(i * 100 + 60).c_str(),
|
||||
std::to_string(i * 100 + 110).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(4, 100 + i * 3 + 1, ToString(i * 100 + 30).c_str(),
|
||||
ToString(i * 100 + 50).c_str(), kFileSize, 0, 200, 251);
|
||||
Add(4, 100 + i * 3 + 2, ToString(i * 100 + 60).c_str(),
|
||||
ToString(i * 100 + 110).c_str(), kFileSize, 0, 200, 251);
|
||||
}
|
||||
UpdateVersionStorageInfo();
|
||||
|
||||
@@ -942,8 +941,8 @@ TEST_F(CompactionPickerTest, NeedsCompactionFIFO) {
|
||||
// size of L0 files.
|
||||
for (int i = 1; i <= kFileCount; ++i) {
|
||||
NewVersionStorage(1, kCompactionStyleFIFO);
|
||||
Add(0, i, std::to_string((i + 100) * 1000).c_str(),
|
||||
std::to_string((i + 100) * 1000 + 999).c_str(), kFileSize, 0, i * 100,
|
||||
Add(0, i, ToString((i + 100) * 1000).c_str(),
|
||||
ToString((i + 100) * 1000 + 999).c_str(), kFileSize, 0, i * 100,
|
||||
i * 100 + 99);
|
||||
UpdateVersionStorageInfo();
|
||||
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()),
|
||||
@@ -2654,8 +2653,8 @@ TEST_F(CompactionPickerTest, UniversalMarkedManualCompaction) {
|
||||
universal_compaction_picker.CompactRange(
|
||||
cf_name_, mutable_cf_options_, mutable_db_options_, vstorage_.get(),
|
||||
ColumnFamilyData::kCompactAllLevels, 6, CompactRangeOptions(),
|
||||
nullptr, nullptr, &manual_end, &manual_conflict,
|
||||
std::numeric_limits<uint64_t>::max(), ""));
|
||||
nullptr, nullptr, &manual_end, &manual_conflict, port::kMaxUint64,
|
||||
""));
|
||||
|
||||
ASSERT_TRUE(compaction);
|
||||
|
||||
|
||||
@@ -1371,7 +1371,7 @@ Compaction* UniversalCompactionBuilder::PickPeriodicCompaction() {
|
||||
|
||||
uint64_t UniversalCompactionBuilder::GetMaxOverlappingBytes() const {
|
||||
if (!mutable_cf_options_.compaction_options_universal.incremental) {
|
||||
return std::numeric_limits<uint64_t>::max();
|
||||
return port::kMaxUint64;
|
||||
} else {
|
||||
// Try to align cutting boundary with files at the next level if the
|
||||
// file isn't end up with 1/2 of target size, or it would overlap
|
||||
|
||||
@@ -15,17 +15,13 @@ class MyTestCompactionService : public CompactionService {
|
||||
MyTestCompactionService(
|
||||
std::string db_path, Options& options,
|
||||
std::shared_ptr<Statistics>& statistics,
|
||||
std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
std::vector<std::shared_ptr<TablePropertiesCollectorFactory>>
|
||||
table_properties_collector_factories)
|
||||
std::vector<std::shared_ptr<EventListener>>& listeners)
|
||||
: 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),
|
||||
listeners_(listeners),
|
||||
table_properties_collector_factories_(
|
||||
std::move(table_properties_collector_factories)) {}
|
||||
listeners_(listeners) {}
|
||||
|
||||
static const char* kClassName() { return "MyTestCompactionService"; }
|
||||
|
||||
@@ -82,16 +78,12 @@ class MyTestCompactionService : public CompactionService {
|
||||
options_override.listeners = listeners_;
|
||||
}
|
||||
|
||||
if (!table_properties_collector_factories_.empty()) {
|
||||
options_override.table_properties_collector_factories =
|
||||
table_properties_collector_factories_;
|
||||
}
|
||||
|
||||
OpenAndCompactOptions options;
|
||||
options.canceled = &canceled_;
|
||||
|
||||
Status s = DB::OpenAndCompact(
|
||||
options, db_path_, db_path_ + "/" + std::to_string(info.job_id),
|
||||
options, 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_;
|
||||
@@ -150,8 +142,6 @@ class MyTestCompactionService : public CompactionService {
|
||||
bool is_override_wait_result_ = false;
|
||||
std::string override_wait_result_;
|
||||
std::vector<std::shared_ptr<EventListener>> listeners_;
|
||||
std::vector<std::shared_ptr<TablePropertiesCollectorFactory>>
|
||||
table_properties_collector_factories_;
|
||||
std::atomic_bool canceled_{false};
|
||||
};
|
||||
|
||||
@@ -168,8 +158,7 @@ class CompactionServiceTest : public DBTestBase {
|
||||
compactor_statistics_ = CreateDBStatistics();
|
||||
|
||||
compaction_service_ = std::make_shared<MyTestCompactionService>(
|
||||
dbname_, *options, compactor_statistics_, remote_listeners,
|
||||
remote_table_properties_collector_factories);
|
||||
dbname_, *options, compactor_statistics_, remote_listeners);
|
||||
options->compaction_service = compaction_service_;
|
||||
DestroyAndReopen(*options);
|
||||
}
|
||||
@@ -188,7 +177,7 @@ class CompactionServiceTest : public DBTestBase {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -198,7 +187,7 @@ class CompactionServiceTest : public DBTestBase {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -210,16 +199,14 @@ class CompactionServiceTest : public DBTestBase {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
auto result = Get(Key(i));
|
||||
if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<EventListener>> remote_listeners;
|
||||
std::vector<std::shared_ptr<TablePropertiesCollectorFactory>>
|
||||
remote_table_properties_collector_factories;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Statistics> compactor_statistics_;
|
||||
@@ -237,7 +224,7 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -245,7 +232,7 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -255,9 +242,9 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
auto result = Get(Key(i));
|
||||
if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
auto my_cs = GetCompactionService();
|
||||
@@ -288,23 +275,13 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
|
||||
auto s = static_cast<Status*>(status);
|
||||
*s = Status::Aborted("MyTestCompactionService failed to compact!");
|
||||
});
|
||||
|
||||
// tracking success unique id verification
|
||||
std::atomic_int verify_passed{0};
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"Version::VerifySstUniqueIds::Passed", [&](void* arg) {
|
||||
// override job status
|
||||
auto id = static_cast<std::string*>(arg);
|
||||
assert(!id->empty());
|
||||
verify_passed++;
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Status s;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 20 + j * 2;
|
||||
s = Put(Key(key_id), "value_new" + std::to_string(key_id));
|
||||
s = Put(Key(key_id), "value_new" + ToString(key_id));
|
||||
if (s.IsAborted()) {
|
||||
break;
|
||||
}
|
||||
@@ -322,12 +299,6 @@ TEST_F(CompactionServiceTest, BasicCompactions) {
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(s.IsAborted());
|
||||
|
||||
// Test verification
|
||||
ASSERT_EQ(verify_passed, 0);
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
Reopen(options);
|
||||
ASSERT_GT(verify_passed, 0);
|
||||
}
|
||||
|
||||
TEST_F(CompactionServiceTest, ManualCompaction) {
|
||||
@@ -497,7 +468,7 @@ TEST_F(CompactionServiceTest, CompactionFilter) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -505,7 +476,7 @@ TEST_F(CompactionServiceTest, CompactionFilter) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -519,9 +490,9 @@ TEST_F(CompactionServiceTest, CompactionFilter) {
|
||||
if (i > 5 && i <= 105) {
|
||||
ASSERT_EQ(result, "NOT_FOUND");
|
||||
} else if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
auto my_cs = GetCompactionService();
|
||||
@@ -576,9 +547,9 @@ TEST_F(CompactionServiceTest, ConcurrentCompaction) {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
auto result = Get(Key(i));
|
||||
if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
auto my_cs = GetCompactionService();
|
||||
@@ -593,7 +564,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -601,7 +572,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -646,7 +617,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -654,7 +625,7 @@ TEST_F(CompactionServiceTest, CompactionInfo) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -682,7 +653,7 @@ TEST_F(CompactionServiceTest, FallbackLocalAuto) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -690,7 +661,7 @@ TEST_F(CompactionServiceTest, FallbackLocalAuto) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -700,9 +671,9 @@ TEST_F(CompactionServiceTest, FallbackLocalAuto) {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
auto result = Get(Key(i));
|
||||
if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -825,7 +796,7 @@ TEST_F(CompactionServiceTest, RemoteEventListener) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -833,7 +804,7 @@ TEST_F(CompactionServiceTest, RemoteEventListener) {
|
||||
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" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value_new" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -850,103 +821,13 @@ TEST_F(CompactionServiceTest, RemoteEventListener) {
|
||||
for (int i = 0; i < 200; i++) {
|
||||
auto result = Get(Key(i));
|
||||
if (i % 2) {
|
||||
ASSERT_EQ(result, "value" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value" + ToString(i));
|
||||
} else {
|
||||
ASSERT_EQ(result, "value_new" + std::to_string(i));
|
||||
ASSERT_EQ(result, "value_new" + ToString(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CompactionServiceTest, TablePropertiesCollector) {
|
||||
const static std::string kUserPropertyName = "TestCount";
|
||||
|
||||
class TablePropertiesCollectorTest : public TablePropertiesCollector {
|
||||
public:
|
||||
Status Finish(UserCollectedProperties* properties) override {
|
||||
*properties = UserCollectedProperties{
|
||||
{kUserPropertyName, std::to_string(count_)},
|
||||
};
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
UserCollectedProperties GetReadableProperties() const override {
|
||||
return UserCollectedProperties();
|
||||
}
|
||||
|
||||
const char* Name() const override { return "TablePropertiesCollectorTest"; }
|
||||
|
||||
Status AddUserKey(const Slice& /*user_key*/, const Slice& /*value*/,
|
||||
EntryType /*type*/, SequenceNumber /*seq*/,
|
||||
uint64_t /*file_size*/) override {
|
||||
count_++;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t count_ = 0;
|
||||
};
|
||||
|
||||
class TablePropertiesCollectorFactoryTest
|
||||
: public TablePropertiesCollectorFactory {
|
||||
public:
|
||||
TablePropertiesCollector* CreateTablePropertiesCollector(
|
||||
TablePropertiesCollectorFactory::Context /*context*/) override {
|
||||
return new TablePropertiesCollectorTest();
|
||||
}
|
||||
|
||||
const char* Name() const override {
|
||||
return "TablePropertiesCollectorFactoryTest";
|
||||
}
|
||||
};
|
||||
|
||||
auto factory = new TablePropertiesCollectorFactoryTest();
|
||||
remote_table_properties_collector_factories.emplace_back(factory);
|
||||
|
||||
const int kNumSst = 3;
|
||||
const int kLevel0Trigger = 4;
|
||||
Options options = CurrentOptions();
|
||||
options.level0_file_num_compaction_trigger = kLevel0Trigger;
|
||||
ReopenWithCompactionService(&options);
|
||||
|
||||
// generate a few SSTs locally which should not have user property
|
||||
for (int i = 0; i < kNumSst; i++) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
ASSERT_OK(Put(Key(i * 10 + j), "value"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
TablePropertiesCollection fname_to_props;
|
||||
ASSERT_OK(db_->GetPropertiesOfAllTables(&fname_to_props));
|
||||
for (const auto& file_props : fname_to_props) {
|
||||
auto properties = file_props.second->user_collected_properties;
|
||||
auto it = properties.find(kUserPropertyName);
|
||||
ASSERT_EQ(it, properties.end());
|
||||
}
|
||||
|
||||
// trigger compaction
|
||||
for (int i = kNumSst; i < kLevel0Trigger; i++) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
ASSERT_OK(Put(Key(i * 10 + j), "value"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_OK(db_->GetPropertiesOfAllTables(&fname_to_props));
|
||||
|
||||
bool has_user_property = false;
|
||||
for (const auto& file_props : fname_to_props) {
|
||||
auto properties = file_props.second->user_collected_properties;
|
||||
auto it = properties.find(kUserPropertyName);
|
||||
if (it != properties.end()) {
|
||||
has_user_property = true;
|
||||
ASSERT_GT(std::stoi(it->second), 0);
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(has_user_property);
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -397,7 +397,7 @@ TEST_P(ComparatorDBTest, DoubleComparator) {
|
||||
for (uint32_t j = 0; j < divide_order; j++) {
|
||||
to_divide *= 10.0;
|
||||
}
|
||||
source_strings.push_back(std::to_string(r / to_divide));
|
||||
source_strings.push_back(ToString(r / to_divide));
|
||||
}
|
||||
|
||||
DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 200, 1000, 66);
|
||||
|
||||
+6
-8
@@ -40,8 +40,7 @@ Status VerifySstFileChecksum(const Options& options,
|
||||
Status VerifySstFileChecksum(const Options& options,
|
||||
const EnvOptions& env_options,
|
||||
const ReadOptions& read_options,
|
||||
const std::string& file_path,
|
||||
const SequenceNumber& largest_seqno) {
|
||||
const std::string& file_path) {
|
||||
std::unique_ptr<FSRandomAccessFile> file;
|
||||
uint64_t file_size;
|
||||
InternalKeyComparator internal_comparator(options.comparator);
|
||||
@@ -62,13 +61,12 @@ Status VerifySstFileChecksum(const Options& options,
|
||||
nullptr /* stats */, 0 /* hist_type */, nullptr /* file_read_hist */,
|
||||
ioptions.rate_limiter.get()));
|
||||
const bool kImmortal = true;
|
||||
auto reader_options = TableReaderOptions(
|
||||
ioptions, options.prefix_extractor, env_options, internal_comparator,
|
||||
false /* skip_filters */, !kImmortal, false /* force_direct_prefetch */,
|
||||
-1 /* level */);
|
||||
reader_options.largest_seqno = largest_seqno;
|
||||
s = ioptions.table_factory->NewTableReader(
|
||||
reader_options, std::move(file_reader), file_size, &table_reader,
|
||||
TableReaderOptions(ioptions, options.prefix_extractor, env_options,
|
||||
internal_comparator, false /* skip_filters */,
|
||||
!kImmortal, false /* force_direct_prefetch */,
|
||||
-1 /* level */),
|
||||
std::move(file_reader), file_size, &table_reader,
|
||||
false /* prefetch_index_and_filter_in_cache */);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
|
||||
+39
-267
@@ -308,7 +308,7 @@ class CorruptionTest : public testing::Test {
|
||||
uint64_t new_size = old_size - bytes_to_truncate;
|
||||
// If bytes_to_truncate == 0, it will do full truncation.
|
||||
if (bytes_to_truncate == 0) {
|
||||
new_size = 0;
|
||||
new_size = old_size;
|
||||
}
|
||||
ASSERT_OK(test::TruncateFile(env_, path, new_size));
|
||||
}
|
||||
@@ -354,7 +354,6 @@ TEST_F(CorruptionTest, PostPITRCorruptionWALsRetained) {
|
||||
options_.create_missing_column_families = true;
|
||||
std::vector<ColumnFamilyHandle*> cfhs;
|
||||
ASSERT_OK(DB::Open(options_, dbname_, cf_descs, &cfhs, &db_));
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
|
||||
ASSERT_OK(db_->Put(WriteOptions(), cfhs[0], "k", "v"));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), cfhs[1], "k", "v"));
|
||||
@@ -376,8 +375,6 @@ TEST_F(CorruptionTest, PostPITRCorruptionWALsRetained) {
|
||||
options_.avoid_flush_during_recovery = true;
|
||||
std::vector<ColumnFamilyHandle*> cfhs;
|
||||
ASSERT_OK(DB::Open(options_, dbname_, cf_descs, &cfhs, &db_));
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
|
||||
// Flush one but not both CFs and write some data so there's a seqno gap
|
||||
// between the PITR corruption and the next DB session's first WAL.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), cfhs[1], "k2", "v2"));
|
||||
@@ -394,7 +391,6 @@ TEST_F(CorruptionTest, PostPITRCorruptionWALsRetained) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
std::vector<ColumnFamilyHandle*> cfhs;
|
||||
ASSERT_OK(DB::Open(options_, dbname_, cf_descs, &cfhs, &db_));
|
||||
assert(db_ != nullptr); // suppress false clang-analyze report
|
||||
|
||||
for (auto* cfh : cfhs) {
|
||||
delete cfh;
|
||||
@@ -1049,22 +1045,15 @@ INSTANTIATE_TEST_CASE_P(CorruptionTest, CrashDuringRecoveryWithCorruptionTest,
|
||||
// "Column family inconsistency: SST file contains data beyond the point of
|
||||
// corruption" error will be hit, causing recovery to fail.
|
||||
//
|
||||
// After adding the fix, only after new WAL is synced, RocksDB persist a new
|
||||
// MANIFEST with column families to ensure RocksDB is in consistent state.
|
||||
// After adding the fix, corrupted WALs whose numbers are larger than the
|
||||
// corrupted wal and smaller than the new WAL are moved to a separate folder.
|
||||
// Only after new WAL is synced, RocksDB persist a new MANIFEST with column
|
||||
// families to ensure RocksDB is in consistent state.
|
||||
// RocksDB writes an empty WriteBatch as a sentinel to the new WAL which is
|
||||
// synced immediately afterwards. The sequence number of the sentinel
|
||||
// WriteBatch will be the next sequence number immediately after the largest
|
||||
// sequence number recovered from previous WALs and MANIFEST because of which DB
|
||||
// will be in consistent state.
|
||||
// If a future recovery starts from the new MANIFEST, then it means the new WAL
|
||||
// is successfully synced. Due to the sentinel empty write batch at the
|
||||
// beginning, kPointInTimeRecovery of WAL is guaranteed to go after this point.
|
||||
// If future recovery starts from the old MANIFEST, it means the writing the new
|
||||
// MANIFEST failed. It won't have the "SST ahead of WAL" error.
|
||||
//
|
||||
// The combination of corrupting a WAL and injecting an error during subsequent
|
||||
// re-open exposes the bug of prematurely persisting a new MANIFEST with
|
||||
// advanced ColumnFamilyData::log_number.
|
||||
TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
CloseDb();
|
||||
Options options;
|
||||
@@ -1075,7 +1064,7 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
options.env = env_;
|
||||
ASSERT_OK(DestroyDB(dbname_, options));
|
||||
options.create_if_missing = true;
|
||||
options.max_write_buffer_number = 8;
|
||||
options.max_write_buffer_number = 3;
|
||||
|
||||
Reopen(&options);
|
||||
Status s;
|
||||
@@ -1101,16 +1090,13 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
|
||||
// Write one key to test_cf.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), handles[1], "old_key", "dontcare"));
|
||||
ASSERT_OK(db_->Flush(FlushOptions(), handles[1]));
|
||||
|
||||
// Write to default_cf and flush this cf several times to advance wal
|
||||
// number. TEST_SwitchMemtable makes sure WALs are not synced and test can
|
||||
// corrupt un-sync WAL.
|
||||
// number.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key" + std::to_string(i),
|
||||
"value" + std::to_string(i)));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key" + std::to_string(i), "value"));
|
||||
ASSERT_OK(dbimpl->TEST_SwitchMemtable());
|
||||
}
|
||||
ASSERT_OK(db_->Put(WriteOptions(), handles[1], "dontcare", "dontcare"));
|
||||
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
@@ -1119,13 +1105,12 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
CloseDb();
|
||||
}
|
||||
|
||||
// 2. Corrupt second last un-syned wal file to emulate power reset which
|
||||
// caused the DB to lose the un-synced WAL.
|
||||
// 2. Corrupt second last wal file to emulate power reset which caused the DB
|
||||
// to lose the un-synced WAL.
|
||||
{
|
||||
std::vector<uint64_t> file_nums;
|
||||
GetSortedWalFiles(file_nums);
|
||||
size_t size = file_nums.size();
|
||||
assert(size >= 2);
|
||||
uint64_t log_num = file_nums[size - 2];
|
||||
CorruptFileWithTruncation(FileType::kWalFile, log_num,
|
||||
/*bytes_to_truncate=*/8);
|
||||
@@ -1142,31 +1127,25 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
// Case2: If avoid_flush_during_recovery = false, all column families have
|
||||
// flushed their data from WAL to L0 during recovery, and none of them will
|
||||
// ever need to read the WALs again.
|
||||
|
||||
// 4. Fault is injected to fail the recovery.
|
||||
{
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::GetLogSizeAndMaybeTruncate:0", [&](void* arg) {
|
||||
auto* tmp_s = reinterpret_cast<Status*>(arg);
|
||||
assert(tmp_s);
|
||||
*tmp_s = Status::IOError("Injected");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
handles.clear();
|
||||
options.avoid_flush_during_recovery = true;
|
||||
options.avoid_flush_during_recovery = avoid_flush_during_recovery_;
|
||||
s = DB::Open(options, dbname_, cf_descs, &handles, &db_);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_EQ("IO error: Injected", s.ToString());
|
||||
ASSERT_OK(s);
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
handles.clear();
|
||||
CloseDb();
|
||||
}
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
// 4. Corrupt max_wal_num to emulate second power reset which caused the
|
||||
// DB to again lose the un-synced WAL.
|
||||
{
|
||||
std::vector<uint64_t> file_nums;
|
||||
GetSortedWalFiles(file_nums);
|
||||
size_t size = file_nums.size();
|
||||
uint64_t log_num = file_nums[size - 1];
|
||||
CorruptFileWithTruncation(FileType::kWalFile, log_num);
|
||||
}
|
||||
|
||||
// 5. After second crash reopen the db with second corruption. Default family
|
||||
@@ -1189,23 +1168,6 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
{
|
||||
options.avoid_flush_during_recovery = avoid_flush_during_recovery_;
|
||||
ASSERT_OK(DB::Open(options, dbname_, cf_descs, &handles, &db_));
|
||||
|
||||
// Verify that data is not lost.
|
||||
{
|
||||
std::string v;
|
||||
ASSERT_OK(db_->Get(ReadOptions(), handles[1], "old_key", &v));
|
||||
ASSERT_EQ("dontcare", v);
|
||||
|
||||
v.clear();
|
||||
ASSERT_OK(db_->Get(ReadOptions(), "key" + std::to_string(0), &v));
|
||||
ASSERT_EQ("value" + std::to_string(0), v);
|
||||
|
||||
// Since it's corrupting second last wal, below key is not found.
|
||||
v.clear();
|
||||
ASSERT_EQ(db_->Get(ReadOptions(), "key" + std::to_string(1), &v),
|
||||
Status::NotFound());
|
||||
}
|
||||
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
@@ -1221,22 +1183,15 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecovery) {
|
||||
// file contains data beyond the point of corruption" error will be hit, causing
|
||||
// recovery to fail.
|
||||
//
|
||||
// After adding the fix, only after new WAL is synced, RocksDB persist a new
|
||||
// MANIFEST with column families to ensure RocksDB is in consistent state.
|
||||
// After adding the fix, corrupted WALs whose numbers are larger than the
|
||||
// corrupted wal and smaller than the new WAL are moved to a separate folder.
|
||||
// Only after new WAL is synced, RocksDB persist a new MANIFEST with column
|
||||
// families to ensure RocksDB is in consistent state.
|
||||
// RocksDB writes an empty WriteBatch as a sentinel to the new WAL which is
|
||||
// synced immediately afterwards. The sequence number of the sentinel
|
||||
// WriteBatch will be the next sequence number immediately after the largest
|
||||
// sequence number recovered from previous WALs and MANIFEST because of which DB
|
||||
// will be in consistent state.
|
||||
// If a future recovery starts from the new MANIFEST, then it means the new WAL
|
||||
// is successfully synced. Due to the sentinel empty write batch at the
|
||||
// beginning, kPointInTimeRecovery of WAL is guaranteed to go after this point.
|
||||
// If future recovery starts from the old MANIFEST, it means the writing the new
|
||||
// MANIFEST failed. It won't have the "SST ahead of WAL" error.
|
||||
//
|
||||
// The combination of corrupting a WAL and injecting an error during subsequent
|
||||
// re-open exposes the bug of prematurely persisting a new MANIFEST with
|
||||
// advanced ColumnFamilyData::log_number.
|
||||
TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
CloseDb();
|
||||
Options options;
|
||||
@@ -1270,6 +1225,7 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
// advance wal number so that some column families have advanced log_number
|
||||
// while other don't.
|
||||
{
|
||||
options.avoid_flush_during_recovery = avoid_flush_during_recovery_;
|
||||
ASSERT_OK(TransactionDB::Open(options, txn_db_opts, dbname_, cf_descs,
|
||||
&handles, &txn_db));
|
||||
|
||||
@@ -1278,8 +1234,6 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
ASSERT_OK(txn->Put(handles[1], "foo", "value"));
|
||||
ASSERT_OK(txn->SetName("txn0"));
|
||||
ASSERT_OK(txn->Prepare());
|
||||
ASSERT_OK(txn_db->Flush(FlushOptions()));
|
||||
|
||||
delete txn;
|
||||
txn = nullptr;
|
||||
|
||||
@@ -1288,19 +1242,17 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
|
||||
// Put and flush cf0
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ASSERT_OK(txn_db->Put(WriteOptions(), "key" + std::to_string(i),
|
||||
"value" + std::to_string(i)));
|
||||
ASSERT_OK(txn_db->Put(WriteOptions(), "dontcare", "value"));
|
||||
ASSERT_OK(dbimpl->TEST_SwitchMemtable());
|
||||
}
|
||||
|
||||
// Put cf1
|
||||
txn = txn_db->BeginTransaction(WriteOptions(), TransactionOptions());
|
||||
ASSERT_OK(txn->Put(handles[1], "foo1", "value1"));
|
||||
ASSERT_OK(txn->Put(handles[1], "foo1", "value"));
|
||||
ASSERT_OK(txn->Commit());
|
||||
|
||||
delete txn;
|
||||
txn = nullptr;
|
||||
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
@@ -1314,7 +1266,6 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
std::vector<uint64_t> file_nums;
|
||||
GetSortedWalFiles(file_nums);
|
||||
size_t size = file_nums.size();
|
||||
assert(size >= 2);
|
||||
uint64_t log_num = file_nums[size - 2];
|
||||
CorruptFileWithTruncation(FileType::kWalFile, log_num,
|
||||
/*bytes_to_truncate=*/8);
|
||||
@@ -1324,33 +1275,20 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
// family has higher log number than corrupted wal number. There may be old
|
||||
// WAL files that it must not delete because they can contain data of
|
||||
// uncommitted transactions. As a result, min_log_number_to_keep won't change.
|
||||
|
||||
{
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::Open::BeforeSyncWAL", [&](void* arg) {
|
||||
auto* tmp_s = reinterpret_cast<Status*>(arg);
|
||||
assert(tmp_s);
|
||||
*tmp_s = Status::IOError("Injected");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
options.avoid_flush_during_recovery = avoid_flush_during_recovery_;
|
||||
ASSERT_OK(TransactionDB::Open(options, txn_db_opts, dbname_, cf_descs,
|
||||
&handles, &txn_db));
|
||||
|
||||
handles.clear();
|
||||
s = TransactionDB::Open(options, txn_db_opts, dbname_, cf_descs, &handles,
|
||||
&txn_db);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_EQ("IO error: Injected", s.ToString());
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
CloseDb();
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
handles.clear();
|
||||
delete txn_db;
|
||||
}
|
||||
|
||||
// 4. Corrupt max_wal_num.
|
||||
// 4. Corrupt max_wal_num to emulate second power reset which caused the
|
||||
// DB to again lose the un-synced WAL.
|
||||
{
|
||||
std::vector<uint64_t> file_nums;
|
||||
GetSortedWalFiles(file_nums);
|
||||
@@ -1369,29 +1307,10 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
// recovered from previous WALs and MANIFEST, db will be in consistent state
|
||||
// and opens successfully.
|
||||
{
|
||||
options.avoid_flush_during_recovery = false;
|
||||
|
||||
ASSERT_OK(TransactionDB::Open(options, txn_db_opts, dbname_, cf_descs,
|
||||
&handles, &txn_db));
|
||||
|
||||
// Verify that data is not lost.
|
||||
{
|
||||
std::string v;
|
||||
// Key not visible since it's not committed.
|
||||
ASSERT_EQ(txn_db->Get(ReadOptions(), handles[1], "foo", &v),
|
||||
Status::NotFound());
|
||||
|
||||
v.clear();
|
||||
ASSERT_OK(txn_db->Get(ReadOptions(), "key" + std::to_string(0), &v));
|
||||
ASSERT_EQ("value" + std::to_string(0), v);
|
||||
|
||||
// Last WAL is corrupted which contains two keys below.
|
||||
v.clear();
|
||||
ASSERT_EQ(txn_db->Get(ReadOptions(), "key" + std::to_string(1), &v),
|
||||
Status::NotFound());
|
||||
v.clear();
|
||||
ASSERT_EQ(txn_db->Get(ReadOptions(), handles[1], "foo1", &v),
|
||||
Status::NotFound());
|
||||
}
|
||||
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
@@ -1399,153 +1318,6 @@ TEST_P(CrashDuringRecoveryWithCorruptionTest, TxnDbCrashDuringRecovery) {
|
||||
}
|
||||
}
|
||||
|
||||
// This test is similar to
|
||||
// CrashDuringRecoveryWithCorruptionTest.CrashDuringRecovery except it calls
|
||||
// flush and corrupts Last WAL. It calls flush to sync some of the WALs and
|
||||
// remaining are unsyned one of which is then corrupted to simulate crash.
|
||||
//
|
||||
// In case of non-TransactionDB with avoid_flush_during_recovery = true, RocksDB
|
||||
// won't flush the data from WAL to L0 for all column families if possible. As a
|
||||
// result, not all column families can increase their log_numbers, and
|
||||
// min_log_number_to_keep won't change.
|
||||
// It may prematurely persist a new MANIFEST even before we can declare the DB
|
||||
// is in consistent state after recovery (this is when the new WAL is synced)
|
||||
// and advances log_numbers for some column families.
|
||||
//
|
||||
// If there is power failure before we sync the new WAL, we will end up in
|
||||
// a situation in which after persisting the MANIFEST, RocksDB will see some
|
||||
// column families' log_numbers larger than the corrupted wal, and
|
||||
// "Column family inconsistency: SST file contains data beyond the point of
|
||||
// corruption" error will be hit, causing recovery to fail.
|
||||
//
|
||||
// After adding the fix, only after new WAL is synced, RocksDB persist a new
|
||||
// MANIFEST with column families to ensure RocksDB is in consistent state.
|
||||
// RocksDB writes an empty WriteBatch as a sentinel to the new WAL which is
|
||||
// synced immediately afterwards. The sequence number of the sentinel
|
||||
// WriteBatch will be the next sequence number immediately after the largest
|
||||
// sequence number recovered from previous WALs and MANIFEST because of which DB
|
||||
// will be in consistent state.
|
||||
// If a future recovery starts from the new MANIFEST, then it means the new WAL
|
||||
// is successfully synced. Due to the sentinel empty write batch at the
|
||||
// beginning, kPointInTimeRecovery of WAL is guaranteed to go after this point.
|
||||
// If future recovery starts from the old MANIFEST, it means the writing the new
|
||||
// MANIFEST failed. It won't have the "SST ahead of WAL" error.
|
||||
|
||||
// The combination of corrupting a WAL and injecting an error during subsequent
|
||||
// re-open exposes the bug of prematurely persisting a new MANIFEST with
|
||||
// advanced ColumnFamilyData::log_number.
|
||||
TEST_P(CrashDuringRecoveryWithCorruptionTest, CrashDuringRecoveryWithFlush) {
|
||||
CloseDb();
|
||||
Options options;
|
||||
options.wal_recovery_mode = WALRecoveryMode::kPointInTimeRecovery;
|
||||
options.avoid_flush_during_recovery = false;
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
|
||||
ASSERT_OK(DestroyDB(dbname_, options));
|
||||
Reopen(&options);
|
||||
|
||||
ColumnFamilyHandle* cfh = nullptr;
|
||||
const std::string test_cf_name = "test_cf";
|
||||
Status s = db_->CreateColumnFamily(options, test_cf_name, &cfh);
|
||||
ASSERT_OK(s);
|
||||
delete cfh;
|
||||
|
||||
CloseDb();
|
||||
|
||||
std::vector<ColumnFamilyDescriptor> cf_descs;
|
||||
cf_descs.emplace_back(kDefaultColumnFamilyName, options);
|
||||
cf_descs.emplace_back(test_cf_name, options);
|
||||
std::vector<ColumnFamilyHandle*> handles;
|
||||
|
||||
{
|
||||
ASSERT_OK(DB::Open(options, dbname_, cf_descs, &handles, &db_));
|
||||
|
||||
// Write one key to test_cf.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), handles[1], "old_key", "dontcare"));
|
||||
|
||||
// Write to default_cf and flush this cf several times to advance wal
|
||||
// number.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "key" + std::to_string(i),
|
||||
"value" + std::to_string(i)));
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
}
|
||||
|
||||
ASSERT_OK(db_->Put(WriteOptions(), handles[1], "dontcare", "dontcare"));
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
handles.clear();
|
||||
CloseDb();
|
||||
}
|
||||
|
||||
// Corrupt second last un-syned wal file to emulate power reset which
|
||||
// caused the DB to lose the un-synced WAL.
|
||||
{
|
||||
std::vector<uint64_t> file_nums;
|
||||
GetSortedWalFiles(file_nums);
|
||||
size_t size = file_nums.size();
|
||||
uint64_t log_num = file_nums[size - 1];
|
||||
CorruptFileWithTruncation(FileType::kWalFile, log_num,
|
||||
/*bytes_to_truncate=*/8);
|
||||
}
|
||||
|
||||
// Fault is injected to fail the recovery.
|
||||
{
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::GetLogSizeAndMaybeTruncate:0", [&](void* arg) {
|
||||
auto* tmp_s = reinterpret_cast<Status*>(arg);
|
||||
assert(tmp_s);
|
||||
*tmp_s = Status::IOError("Injected");
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
handles.clear();
|
||||
options.avoid_flush_during_recovery = true;
|
||||
s = DB::Open(options, dbname_, cf_descs, &handles, &db_);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_EQ("IO error: Injected", s.ToString());
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
CloseDb();
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
}
|
||||
|
||||
// Reopen db again
|
||||
{
|
||||
options.avoid_flush_during_recovery = avoid_flush_during_recovery_;
|
||||
ASSERT_OK(DB::Open(options, dbname_, cf_descs, &handles, &db_));
|
||||
|
||||
// Verify that data is not lost.
|
||||
{
|
||||
std::string v;
|
||||
ASSERT_OK(db_->Get(ReadOptions(), handles[1], "old_key", &v));
|
||||
ASSERT_EQ("dontcare", v);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
v.clear();
|
||||
ASSERT_OK(db_->Get(ReadOptions(), "key" + std::to_string(i), &v));
|
||||
ASSERT_EQ("value" + std::to_string(i), v);
|
||||
}
|
||||
|
||||
// Since it's corrupting last wal after Flush, below key is not found.
|
||||
v.clear();
|
||||
ASSERT_EQ(db_->Get(ReadOptions(), handles[1], "dontcare", &v),
|
||||
Status::NotFound());
|
||||
}
|
||||
|
||||
for (auto* h : handles) {
|
||||
delete h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -95,8 +95,8 @@ class CuckooTableDBTest : public testing::Test {
|
||||
|
||||
int NumTableFilesAtLevel(int level) {
|
||||
std::string property;
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.num-files-at-level" + std::to_string(level), &property));
|
||||
EXPECT_TRUE(db_->GetProperty("rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
return atoi(property.c_str());
|
||||
}
|
||||
|
||||
|
||||
+74
-498
@@ -12,7 +12,6 @@
|
||||
#include "db/db_test_util.h"
|
||||
#include "options/options_helper.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/filter_policy.h"
|
||||
#include "rocksdb/flush_block_policy.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
@@ -578,84 +577,55 @@ TEST_F(DBBasicTest, ManifestRollOver) {
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, IdentityAcrossRestarts) {
|
||||
constexpr size_t kMinIdSize = 10;
|
||||
TEST_F(DBBasicTest, IdentityAcrossRestarts1) {
|
||||
do {
|
||||
for (bool with_manifest : {false, true}) {
|
||||
std::string idfilename = IdentityFileName(dbname_);
|
||||
std::string id1, tmp;
|
||||
ASSERT_OK(db_->GetDbIdentity(id1));
|
||||
ASSERT_GE(id1.size(), kMinIdSize);
|
||||
std::string id1;
|
||||
ASSERT_OK(db_->GetDbIdentity(id1));
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.write_dbid_to_manifest = with_manifest;
|
||||
Reopen(options);
|
||||
std::string id2;
|
||||
ASSERT_OK(db_->GetDbIdentity(id2));
|
||||
// id2 should match id1 because identity was not regenerated
|
||||
ASSERT_EQ(id1, id2);
|
||||
ASSERT_OK(ReadFileToString(env_, idfilename, &tmp));
|
||||
ASSERT_EQ(tmp, id2);
|
||||
Options options = CurrentOptions();
|
||||
Reopen(options);
|
||||
std::string id2;
|
||||
ASSERT_OK(db_->GetDbIdentity(id2));
|
||||
// id1 should match id2 because identity was not regenerated
|
||||
ASSERT_EQ(id1.compare(id2), 0);
|
||||
|
||||
// Recover from deleted/missing IDENTITY
|
||||
ASSERT_OK(env_->DeleteFile(idfilename));
|
||||
Reopen(options);
|
||||
std::string id3;
|
||||
ASSERT_OK(db_->GetDbIdentity(id3));
|
||||
if (with_manifest) {
|
||||
// id3 should match id1 because identity was restored from manifest
|
||||
ASSERT_EQ(id1, id3);
|
||||
} else {
|
||||
// id3 should NOT match id1 because identity was regenerated
|
||||
ASSERT_NE(id1, id3);
|
||||
ASSERT_GE(id3.size(), kMinIdSize);
|
||||
}
|
||||
ASSERT_OK(ReadFileToString(env_, idfilename, &tmp));
|
||||
ASSERT_EQ(tmp, id3);
|
||||
|
||||
// Recover from truncated IDENTITY
|
||||
{
|
||||
std::unique_ptr<WritableFile> w;
|
||||
ASSERT_OK(env_->NewWritableFile(idfilename, &w, EnvOptions()));
|
||||
ASSERT_OK(w->Close());
|
||||
}
|
||||
Reopen(options);
|
||||
std::string id4;
|
||||
ASSERT_OK(db_->GetDbIdentity(id4));
|
||||
if (with_manifest) {
|
||||
// id4 should match id1 because identity was restored from manifest
|
||||
ASSERT_EQ(id1, id4);
|
||||
} else {
|
||||
// id4 should NOT match id1 because identity was regenerated
|
||||
ASSERT_NE(id1, id4);
|
||||
ASSERT_GE(id4.size(), kMinIdSize);
|
||||
}
|
||||
ASSERT_OK(ReadFileToString(env_, idfilename, &tmp));
|
||||
ASSERT_EQ(tmp, id4);
|
||||
|
||||
// Recover from overwritten IDENTITY
|
||||
std::string silly_id = "asdf123456789";
|
||||
{
|
||||
std::unique_ptr<WritableFile> w;
|
||||
ASSERT_OK(env_->NewWritableFile(idfilename, &w, EnvOptions()));
|
||||
ASSERT_OK(w->Append(silly_id));
|
||||
ASSERT_OK(w->Close());
|
||||
}
|
||||
Reopen(options);
|
||||
std::string id5;
|
||||
ASSERT_OK(db_->GetDbIdentity(id5));
|
||||
if (with_manifest) {
|
||||
// id4 should match id1 because identity was restored from manifest
|
||||
ASSERT_EQ(id1, id5);
|
||||
} else {
|
||||
ASSERT_EQ(id5, silly_id);
|
||||
}
|
||||
ASSERT_OK(ReadFileToString(env_, idfilename, &tmp));
|
||||
ASSERT_EQ(tmp, id5);
|
||||
std::string idfilename = IdentityFileName(dbname_);
|
||||
ASSERT_OK(env_->DeleteFile(idfilename));
|
||||
Reopen(options);
|
||||
std::string id3;
|
||||
ASSERT_OK(db_->GetDbIdentity(id3));
|
||||
if (options.write_dbid_to_manifest) {
|
||||
ASSERT_EQ(id1.compare(id3), 0);
|
||||
} else {
|
||||
// id1 should NOT match id3 because identity was regenerated
|
||||
ASSERT_NE(id1.compare(id3), 0);
|
||||
}
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_F(DBBasicTest, IdentityAcrossRestarts2) {
|
||||
do {
|
||||
std::string id1;
|
||||
ASSERT_OK(db_->GetDbIdentity(id1));
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.write_dbid_to_manifest = true;
|
||||
Reopen(options);
|
||||
std::string id2;
|
||||
ASSERT_OK(db_->GetDbIdentity(id2));
|
||||
// id1 should match id2 because identity was not regenerated
|
||||
ASSERT_EQ(id1.compare(id2), 0);
|
||||
|
||||
std::string idfilename = IdentityFileName(dbname_);
|
||||
ASSERT_OK(env_->DeleteFile(idfilename));
|
||||
Reopen(options);
|
||||
std::string id3;
|
||||
ASSERT_OK(db_->GetDbIdentity(id3));
|
||||
// id1 should NOT match id3 because identity was regenerated
|
||||
ASSERT_EQ(id1, id3);
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBBasicTest, Snapshot) {
|
||||
env_->SetMockSleep();
|
||||
@@ -1210,17 +1180,10 @@ TEST_F(DBBasicTest, DBCloseFlushError) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
class DBMultiGetTestWithParam
|
||||
: public DBBasicTest,
|
||||
public testing::WithParamInterface<std::tuple<bool, bool>> {};
|
||||
class DBMultiGetTestWithParam : public DBBasicTest,
|
||||
public testing::WithParamInterface<bool> {};
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
|
||||
"alyosha", "popovich"},
|
||||
@@ -1277,8 +1240,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
|
||||
keys.push_back(std::get<1>(cf_kv_vec[i]));
|
||||
}
|
||||
|
||||
values = MultiGet(cfs, keys, nullptr, std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()));
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_EQ(values.size(), num_keys);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
ASSERT_EQ(values[j], std::get<2>(cf_kv_vec[j]) + "_2");
|
||||
@@ -1292,8 +1254,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
|
||||
keys.push_back(std::get<1>(cf_kv_vec[3]));
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[4]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[4]));
|
||||
values = MultiGet(cfs, keys, nullptr, std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()));
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_EQ(values[0], std::get<2>(cf_kv_vec[0]) + "_2");
|
||||
ASSERT_EQ(values[1], std::get<2>(cf_kv_vec[3]) + "_2");
|
||||
ASSERT_EQ(values[2], std::get<2>(cf_kv_vec[4]) + "_2");
|
||||
@@ -1306,8 +1267,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
|
||||
keys.push_back(std::get<1>(cf_kv_vec[6]));
|
||||
cfs.push_back(std::get<0>(cf_kv_vec[1]));
|
||||
keys.push_back(std::get<1>(cf_kv_vec[1]));
|
||||
values = MultiGet(cfs, keys, nullptr, std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()));
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_EQ(values[0], std::get<2>(cf_kv_vec[7]) + "_2");
|
||||
ASSERT_EQ(values[1], std::get<2>(cf_kv_vec[6]) + "_2");
|
||||
ASSERT_EQ(values[2], std::get<2>(cf_kv_vec[1]) + "_2");
|
||||
@@ -1323,12 +1283,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFMutex) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
|
||||
"alyosha", "popovich"},
|
||||
@@ -1374,8 +1328,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFMutex) {
|
||||
keys.push_back("cf" + std::to_string(i) + "_key");
|
||||
}
|
||||
|
||||
values = MultiGet(cfs, keys, nullptr, std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()));
|
||||
values = MultiGet(cfs, keys, nullptr, GetParam());
|
||||
ASSERT_TRUE(last_try);
|
||||
ASSERT_EQ(values.size(), 8);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
@@ -1392,12 +1345,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFMutex) {
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFSnapshot) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
|
||||
"alyosha", "popovich"},
|
||||
@@ -1442,8 +1389,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFSnapshot) {
|
||||
}
|
||||
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
values = MultiGet(cfs, keys, snapshot, std::get<0>(GetParam()),
|
||||
std::get<1>(GetParam()));
|
||||
values = MultiGet(cfs, keys, snapshot, GetParam());
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
ASSERT_EQ(values.size(), 8);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
@@ -1459,12 +1405,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFSnapshot) {
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFUnsorted) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
Options options = CurrentOptions();
|
||||
CreateAndReopenWithCF({"one", "two"}, options);
|
||||
|
||||
@@ -1477,9 +1417,8 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFUnsorted) {
|
||||
std::vector<std::string> keys{"foo", "baz", "abc"};
|
||||
std::vector<std::string> values;
|
||||
|
||||
values = MultiGet(cfs, keys, /* snapshot */ nullptr,
|
||||
/* batched */ std::get<0>(GetParam()),
|
||||
/* async */ std::get<1>(GetParam()));
|
||||
values =
|
||||
MultiGet(cfs, keys, /* snapshot */ nullptr, /* batched */ GetParam());
|
||||
|
||||
ASSERT_EQ(values.size(), 3);
|
||||
ASSERT_EQ(values[0], "bar");
|
||||
@@ -1487,18 +1426,10 @@ TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFUnsorted) {
|
||||
ASSERT_EQ(values[2], "def");
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedSimpleUnsorted) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(DBMultiGetTestWithParam, DBMultiGetTestWithParam,
|
||||
testing::Bool());
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetBatchedSimpleUnsorted) {
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
SetPerfLevel(kEnableCount);
|
||||
@@ -1517,10 +1448,8 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedSimpleUnsorted) {
|
||||
std::vector<ColumnFamilyHandle*> cfs(keys.size(), handles_[1]);
|
||||
std::vector<Status> s(keys.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = std::get<1>(GetParam());
|
||||
db_->MultiGet(ro, handles_[1], keys.size(), keys.data(), values.data(),
|
||||
s.data(), false);
|
||||
db_->MultiGet(ReadOptions(), handles_[1], keys.size(), keys.data(),
|
||||
values.data(), s.data(), false);
|
||||
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
ASSERT_EQ(std::string(values[5].data(), values[5].size()), "v1");
|
||||
@@ -1541,18 +1470,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedSimpleUnsorted) {
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedSortedMultiFile) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedSortedMultiFile) {
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
SetPerfLevel(kEnableCount);
|
||||
@@ -1575,10 +1493,8 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedSortedMultiFile) {
|
||||
std::vector<ColumnFamilyHandle*> cfs(keys.size(), handles_[1]);
|
||||
std::vector<Status> s(keys.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = std::get<1>(GetParam());
|
||||
db_->MultiGet(ro, handles_[1], keys.size(), keys.data(), values.data(),
|
||||
s.data(), true);
|
||||
db_->MultiGet(ReadOptions(), handles_[1], keys.size(), keys.data(),
|
||||
values.data(), s.data(), true);
|
||||
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
ASSERT_EQ(std::string(values[0].data(), values[0].size()), "v1");
|
||||
@@ -1599,18 +1515,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedSortedMultiFile) {
|
||||
} while (ChangeOptions());
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedDuplicateKeys) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedDuplicateKeys) {
|
||||
Options opts = CurrentOptions();
|
||||
opts.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
CreateAndReopenWithCF({"pikachu"}, opts);
|
||||
@@ -1641,10 +1546,8 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedDuplicateKeys) {
|
||||
std::vector<ColumnFamilyHandle*> cfs(keys.size(), handles_[1]);
|
||||
std::vector<Status> s(keys.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = std::get<1>(GetParam());
|
||||
db_->MultiGet(ro, handles_[1], keys.size(), keys.data(), values.data(),
|
||||
s.data(), false);
|
||||
db_->MultiGet(ReadOptions(), handles_[1], keys.size(), keys.data(),
|
||||
values.data(), s.data(), false);
|
||||
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
ASSERT_EQ(std::string(values[0].data(), values[0].size()), "v8");
|
||||
@@ -1663,18 +1566,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedDuplicateKeys) {
|
||||
SetPerfLevel(kDisable);
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedMultiLevel) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedMultiLevel) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
Reopen(options);
|
||||
@@ -1733,7 +1625,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedMultiLevel) {
|
||||
keys.push_back("key_" + std::to_string(i));
|
||||
}
|
||||
|
||||
values = MultiGet(keys, nullptr, std::get<1>(GetParam()));
|
||||
values = MultiGet(keys, nullptr);
|
||||
ASSERT_EQ(values.size(), 16);
|
||||
for (unsigned int j = 0; j < values.size(); ++j) {
|
||||
int key = j + 64;
|
||||
@@ -1749,18 +1641,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedMultiLevel) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedMultiLevelMerge) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedMultiLevelMerge) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
@@ -1824,7 +1705,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedMultiLevelMerge) {
|
||||
keys.push_back("key_" + std::to_string(i));
|
||||
}
|
||||
|
||||
values = MultiGet(keys, nullptr, std::get<1>(GetParam()));
|
||||
values = MultiGet(keys, nullptr);
|
||||
ASSERT_EQ(values.size(), keys.size());
|
||||
for (unsigned int j = 0; j < 48; ++j) {
|
||||
int key = j + 32;
|
||||
@@ -1846,18 +1727,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedMultiLevelMerge) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSizeInMemory) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedValueSizeInMemory) {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
SetPerfLevel(kEnableCount);
|
||||
ASSERT_OK(Put(1, "k1", "v_1"));
|
||||
@@ -1874,7 +1744,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSizeInMemory) {
|
||||
get_perf_context()->Reset();
|
||||
ReadOptions ro;
|
||||
ro.value_size_soft_limit = 11;
|
||||
ro.async_io = std::get<1>(GetParam());
|
||||
db_->MultiGet(ro, handles_[1], keys.size(), keys.data(), values.data(),
|
||||
s.data(), false);
|
||||
|
||||
@@ -1892,17 +1761,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSizeInMemory) {
|
||||
SetPerfLevel(kDisable);
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSize) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedValueSize) {
|
||||
do {
|
||||
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
|
||||
SetPerfLevel(kEnableCount);
|
||||
@@ -1942,7 +1801,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSize) {
|
||||
|
||||
ReadOptions ro;
|
||||
ro.value_size_soft_limit = 20;
|
||||
ro.async_io = std::get<1>(GetParam());
|
||||
db_->MultiGet(ro, handles_[1], keys.size(), keys.data(), values.data(),
|
||||
s.data(), false);
|
||||
|
||||
@@ -1978,18 +1836,7 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSize) {
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (std::get<1>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
// Skip for unbatched MultiGet
|
||||
if (!std::get<0>(GetParam())) {
|
||||
ROCKSDB_GTEST_SKIP("This test is only for batched MultiGet");
|
||||
return;
|
||||
}
|
||||
TEST_F(DBBasicTest, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
options.merge_operator = MergeOperators::CreateStringAppendOperator();
|
||||
@@ -2061,7 +1908,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
ReadOptions read_options;
|
||||
read_options.verify_checksums = true;
|
||||
read_options.value_size_soft_limit = 380;
|
||||
read_options.async_io = std::get<1>(GetParam());
|
||||
db_->MultiGet(read_options, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data());
|
||||
|
||||
@@ -2093,217 +1939,6 @@ TEST_P(DBMultiGetTestWithParam, MultiGetBatchedValueSizeMultiLevelMerge) {
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DBMultiGetTestWithParam, DBMultiGetTestWithParam,
|
||||
testing::Combine(testing::Bool(), testing::Bool()));
|
||||
|
||||
#if USE_COROUTINES
|
||||
class DBMultiGetAsyncIOTest : public DBBasicTest {
|
||||
public:
|
||||
DBMultiGetAsyncIOTest()
|
||||
: DBBasicTest(), statistics_(ROCKSDB_NAMESPACE::CreateDBStatistics()) {
|
||||
BlockBasedTableOptions bbto;
|
||||
bbto.filter_policy.reset(NewBloomFilterPolicy(10));
|
||||
Options options = CurrentOptions();
|
||||
options.disable_auto_compactions = true;
|
||||
options.statistics = statistics_;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
Reopen(options);
|
||||
int num_keys = 0;
|
||||
|
||||
// Put all keys in the bottommost level, and overwrite some keys
|
||||
// in L0 and L1
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
EXPECT_OK(Put(Key(i), "val_l2_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
EXPECT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
EXPECT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(2);
|
||||
|
||||
for (int i = 0; i < 128; i += 3) {
|
||||
EXPECT_OK(Put(Key(i), "val_l1_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
EXPECT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
EXPECT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
MoveFilesToLevel(1);
|
||||
|
||||
for (int i = 0; i < 128; i += 5) {
|
||||
EXPECT_OK(Put(Key(i), "val_l0_" + std::to_string(i)));
|
||||
num_keys++;
|
||||
if (num_keys == 8) {
|
||||
EXPECT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
}
|
||||
if (num_keys > 0) {
|
||||
EXPECT_OK(Flush());
|
||||
num_keys = 0;
|
||||
}
|
||||
EXPECT_EQ(0, num_keys);
|
||||
}
|
||||
|
||||
const std::shared_ptr<Statistics>& statistics() { return statistics_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Statistics> statistics_;
|
||||
};
|
||||
|
||||
TEST_F(DBMultiGetAsyncIOTest, GetFromL0) {
|
||||
// All 3 keys in L0. The L0 files should be read serially.
|
||||
std::vector<std::string> key_strs{Key(0), Key(40), Key(80)};
|
||||
std::vector<Slice> keys{key_strs[0], key_strs[1], key_strs[2]};
|
||||
std::vector<PinnableSlice> values(key_strs.size());
|
||||
std::vector<Status> statuses(key_strs.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = true;
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data());
|
||||
ASSERT_EQ(values.size(), 3);
|
||||
ASSERT_OK(statuses[0]);
|
||||
ASSERT_OK(statuses[1]);
|
||||
ASSERT_OK(statuses[2]);
|
||||
ASSERT_EQ(values[0], "val_l0_" + std::to_string(0));
|
||||
ASSERT_EQ(values[1], "val_l0_" + std::to_string(40));
|
||||
ASSERT_EQ(values[2], "val_l0_" + std::to_string(80));
|
||||
|
||||
HistogramData multiget_io_batch_size;
|
||||
|
||||
statistics()->histogramData(MULTIGET_IO_BATCH_SIZE, &multiget_io_batch_size);
|
||||
|
||||
// No async IO in this case since we don't do parallel lookup in L0
|
||||
ASSERT_EQ(multiget_io_batch_size.count, 0);
|
||||
ASSERT_EQ(multiget_io_batch_size.max, 0);
|
||||
}
|
||||
|
||||
TEST_F(DBMultiGetAsyncIOTest, GetFromL1) {
|
||||
std::vector<std::string> key_strs;
|
||||
std::vector<Slice> keys;
|
||||
std::vector<PinnableSlice> values;
|
||||
std::vector<Status> statuses;
|
||||
|
||||
key_strs.push_back(Key(33));
|
||||
key_strs.push_back(Key(54));
|
||||
key_strs.push_back(Key(102));
|
||||
keys.push_back(key_strs[0]);
|
||||
keys.push_back(key_strs[1]);
|
||||
keys.push_back(key_strs[2]);
|
||||
values.resize(keys.size());
|
||||
statuses.resize(keys.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = true;
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data());
|
||||
ASSERT_EQ(values.size(), 3);
|
||||
ASSERT_EQ(statuses[0], Status::OK());
|
||||
ASSERT_EQ(statuses[1], Status::OK());
|
||||
ASSERT_EQ(statuses[2], Status::OK());
|
||||
ASSERT_EQ(values[0], "val_l1_" + std::to_string(33));
|
||||
ASSERT_EQ(values[1], "val_l1_" + std::to_string(54));
|
||||
ASSERT_EQ(values[2], "val_l1_" + std::to_string(102));
|
||||
|
||||
HistogramData multiget_io_batch_size;
|
||||
|
||||
statistics()->histogramData(MULTIGET_IO_BATCH_SIZE, &multiget_io_batch_size);
|
||||
|
||||
// A batch of 3 async IOs is expected, one for each overlapping file in L1
|
||||
ASSERT_EQ(multiget_io_batch_size.count, 1);
|
||||
ASSERT_EQ(multiget_io_batch_size.max, 3);
|
||||
}
|
||||
|
||||
TEST_F(DBMultiGetAsyncIOTest, LastKeyInFile) {
|
||||
std::vector<std::string> key_strs;
|
||||
std::vector<Slice> keys;
|
||||
std::vector<PinnableSlice> values;
|
||||
std::vector<Status> statuses;
|
||||
|
||||
// 21 is the last key in the first L1 file
|
||||
key_strs.push_back(Key(21));
|
||||
key_strs.push_back(Key(54));
|
||||
key_strs.push_back(Key(102));
|
||||
keys.push_back(key_strs[0]);
|
||||
keys.push_back(key_strs[1]);
|
||||
keys.push_back(key_strs[2]);
|
||||
values.resize(keys.size());
|
||||
statuses.resize(keys.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = true;
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data());
|
||||
ASSERT_EQ(values.size(), 3);
|
||||
ASSERT_EQ(statuses[0], Status::OK());
|
||||
ASSERT_EQ(statuses[1], Status::OK());
|
||||
ASSERT_EQ(statuses[2], Status::OK());
|
||||
ASSERT_EQ(values[0], "val_l1_" + std::to_string(21));
|
||||
ASSERT_EQ(values[1], "val_l1_" + std::to_string(54));
|
||||
ASSERT_EQ(values[2], "val_l1_" + std::to_string(102));
|
||||
|
||||
HistogramData multiget_io_batch_size;
|
||||
|
||||
statistics()->histogramData(MULTIGET_IO_BATCH_SIZE, &multiget_io_batch_size);
|
||||
|
||||
// Since the first MultiGet key is the last key in a file, the MultiGet is
|
||||
// expected to lookup in that file first, before moving on to other files.
|
||||
// So the first file lookup will issue one async read, and the next lookup
|
||||
// will lookup 2 files in parallel and issue 2 async reads
|
||||
ASSERT_EQ(multiget_io_batch_size.count, 2);
|
||||
ASSERT_EQ(multiget_io_batch_size.max, 2);
|
||||
}
|
||||
|
||||
TEST_F(DBMultiGetAsyncIOTest, GetFromL1AndL2) {
|
||||
std::vector<std::string> key_strs;
|
||||
std::vector<Slice> keys;
|
||||
std::vector<PinnableSlice> values;
|
||||
std::vector<Status> statuses;
|
||||
|
||||
// 33 and 102 are in L1, and 56 is in L2
|
||||
key_strs.push_back(Key(33));
|
||||
key_strs.push_back(Key(56));
|
||||
key_strs.push_back(Key(102));
|
||||
keys.push_back(key_strs[0]);
|
||||
keys.push_back(key_strs[1]);
|
||||
keys.push_back(key_strs[2]);
|
||||
values.resize(keys.size());
|
||||
statuses.resize(keys.size());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.async_io = true;
|
||||
dbfull()->MultiGet(ro, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), values.data(), statuses.data());
|
||||
ASSERT_EQ(values.size(), 3);
|
||||
ASSERT_EQ(statuses[0], Status::OK());
|
||||
ASSERT_EQ(statuses[1], Status::OK());
|
||||
ASSERT_EQ(statuses[2], Status::OK());
|
||||
ASSERT_EQ(values[0], "val_l1_" + std::to_string(33));
|
||||
ASSERT_EQ(values[1], "val_l2_" + std::to_string(56));
|
||||
ASSERT_EQ(values[2], "val_l1_" + std::to_string(102));
|
||||
|
||||
HistogramData multiget_io_batch_size;
|
||||
|
||||
statistics()->histogramData(MULTIGET_IO_BATCH_SIZE, &multiget_io_batch_size);
|
||||
|
||||
// There is only one MultiGet key in the bottommost level - 56. Thus
|
||||
// the bottommost level will not use async IO.
|
||||
ASSERT_EQ(multiget_io_batch_size.count, 1);
|
||||
ASSERT_EQ(multiget_io_batch_size.max, 2);
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
|
||||
TEST_F(DBBasicTest, MultiGetStats) {
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
@@ -3673,11 +3308,6 @@ class DeadlineRandomAccessFile : public FSRandomAccessFileOwnerWrapper {
|
||||
IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
|
||||
const IOOptions& options, IODebugContext* dbg) override;
|
||||
|
||||
IOStatus ReadAsync(FSReadRequest& req, const IOOptions& opts,
|
||||
std::function<void(const FSReadRequest&, void*)> cb,
|
||||
void* cb_arg, void** io_handle, IOHandleDeleter* del_fn,
|
||||
IODebugContext* dbg) override;
|
||||
|
||||
private:
|
||||
DeadlineFS& fs_;
|
||||
std::unique_ptr<FSRandomAccessFile> file_;
|
||||
@@ -3818,26 +3448,6 @@ IOStatus DeadlineRandomAccessFile::Read(uint64_t offset, size_t len,
|
||||
return s;
|
||||
}
|
||||
|
||||
IOStatus DeadlineRandomAccessFile::ReadAsync(
|
||||
FSReadRequest& req, const IOOptions& opts,
|
||||
std::function<void(const FSReadRequest&, void*)> cb, void* cb_arg,
|
||||
void** io_handle, IOHandleDeleter* del_fn, IODebugContext* dbg) {
|
||||
const std::chrono::microseconds deadline = fs_.GetDeadline();
|
||||
const std::chrono::microseconds io_timeout = fs_.GetIOTimeout();
|
||||
IOStatus s;
|
||||
if (deadline.count() || io_timeout.count()) {
|
||||
fs_.AssertDeadline(deadline, io_timeout, opts);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = FSRandomAccessFileWrapper::ReadAsync(req, opts, cb, cb_arg, io_handle,
|
||||
del_fn, dbg);
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = fs_.ShouldDelay(opts);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
IOStatus DeadlineRandomAccessFile::MultiRead(FSReadRequest* reqs,
|
||||
size_t num_reqs,
|
||||
const IOOptions& options,
|
||||
@@ -3859,8 +3469,7 @@ IOStatus DeadlineRandomAccessFile::MultiRead(FSReadRequest* reqs,
|
||||
|
||||
// A test class for intercepting random reads and injecting artificial
|
||||
// delays. Used for testing the MultiGet deadline feature
|
||||
class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet,
|
||||
public testing::WithParamInterface<bool> {
|
||||
class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet {
|
||||
public:
|
||||
DBBasicTestMultiGetDeadline()
|
||||
: DBBasicTestMultiGet(
|
||||
@@ -3883,13 +3492,7 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet,
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
|
||||
#ifndef USE_COROUTINES
|
||||
if (GetParam()) {
|
||||
ROCKSDB_GTEST_SKIP("This test requires coroutine support");
|
||||
return;
|
||||
}
|
||||
#endif // USE_COROUTINES
|
||||
TEST_F(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
|
||||
std::shared_ptr<DeadlineFS> fs = std::make_shared<DeadlineFS>(env_, false);
|
||||
std::unique_ptr<Env> env(new CompositeEnvWrapper(env_, fs));
|
||||
Options options = CurrentOptions();
|
||||
@@ -3920,7 +3523,6 @@ TEST_P(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
|
||||
|
||||
ReadOptions ro;
|
||||
ro.deadline = std::chrono::microseconds{env->NowMicros() + 10000};
|
||||
ro.async_io = GetParam();
|
||||
// Delay the first IO
|
||||
fs->SetDelayTrigger(ro.deadline, ro.io_timeout, 0);
|
||||
|
||||
@@ -4023,9 +3625,6 @@ TEST_P(DBBasicTestMultiGetDeadline, MultiGetDeadlineExceeded) {
|
||||
Close();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(DeadlineIO, DBBasicTestMultiGetDeadline,
|
||||
::testing::Bool());
|
||||
|
||||
TEST_F(DBBasicTest, ManifestWriteFailure) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -4125,29 +3724,6 @@ TEST_F(DBBasicTest, VerifyFileChecksums) {
|
||||
Reopen(options);
|
||||
ASSERT_TRUE(db_->VerifyFileChecksums(ReadOptions()).IsInvalidArgument());
|
||||
}
|
||||
|
||||
// TODO: re-enable after we provide finer-grained control for WAL tracking to
|
||||
// meet the needs of different use cases, durability levels and recovery modes.
|
||||
TEST_F(DBBasicTest, DISABLED_ManualWalSync) {
|
||||
Options options = CurrentOptions();
|
||||
options.track_and_verify_wals_in_manifest = true;
|
||||
options.wal_recovery_mode = WALRecoveryMode::kAbsoluteConsistency;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("x", "y"));
|
||||
// This does not create a new WAL.
|
||||
ASSERT_OK(db_->SyncWAL());
|
||||
EXPECT_FALSE(dbfull()->GetVersionSet()->GetWalSet().GetWals().empty());
|
||||
|
||||
std::unique_ptr<LogFile> wal;
|
||||
Status s = db_->GetCurrentWalFile(&wal);
|
||||
ASSERT_OK(s);
|
||||
Close();
|
||||
|
||||
EXPECT_OK(env_->DeleteFile(LogFileName(dbname_, wal->LogNumber())));
|
||||
|
||||
ASSERT_TRUE(TryReopen(options).IsCorruption());
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
// A test class for intercepting random reads and injecting artificial
|
||||
@@ -4207,7 +3783,7 @@ TEST_P(DBBasicTestDeadline, PointLookupDeadline) {
|
||||
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < 400; ++i) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string key = "k" + ToString(i);
|
||||
ASSERT_OK(Put(key, rnd.RandomString(100)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
@@ -4290,7 +3866,7 @@ TEST_P(DBBasicTestDeadline, IteratorDeadline) {
|
||||
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < 400; ++i) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string key = "k" + ToString(i);
|
||||
ASSERT_OK(Put(key, rnd.RandomString(100)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
+25
-28
@@ -13,7 +13,6 @@
|
||||
|
||||
#include "cache/cache_entry_roles.h"
|
||||
#include "cache/cache_key.h"
|
||||
#include "cache/fast_lru_cache.h"
|
||||
#include "cache/lru_cache.h"
|
||||
#include "db/column_family.h"
|
||||
#include "db/db_impl/db_impl.h"
|
||||
@@ -76,7 +75,7 @@ class DBBlockCacheTest : public DBTestBase {
|
||||
void InitTable(const Options& /*options*/) {
|
||||
std::string value(kValueSize, 'a');
|
||||
for (size_t i = 0; i < kNumBlocks; i++) {
|
||||
ASSERT_OK(Put(std::to_string(i), value.c_str()));
|
||||
ASSERT_OK(Put(ToString(i), value.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +204,7 @@ TEST_F(DBBlockCacheTest, IteratorBlockCacheUsage) {
|
||||
|
||||
ASSERT_EQ(0, cache->GetUsage());
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(std::to_string(0));
|
||||
iter->Seek(ToString(0));
|
||||
ASSERT_LT(0, cache->GetUsage());
|
||||
delete iter;
|
||||
iter = nullptr;
|
||||
@@ -236,7 +235,7 @@ TEST_F(DBBlockCacheTest, TestWithoutCompressedBlockCache) {
|
||||
// Load blocks into cache.
|
||||
for (size_t i = 0; i + 1 < kNumBlocks; i++) {
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(std::to_string(i));
|
||||
iter->Seek(ToString(i));
|
||||
ASSERT_OK(iter->status());
|
||||
CheckCacheCounters(options, 1, 0, 1, 0);
|
||||
iterators[i].reset(iter);
|
||||
@@ -249,7 +248,7 @@ TEST_F(DBBlockCacheTest, TestWithoutCompressedBlockCache) {
|
||||
// Test with strict capacity limit.
|
||||
cache->SetStrictCapacityLimit(true);
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(std::to_string(kNumBlocks - 1));
|
||||
iter->Seek(ToString(kNumBlocks - 1));
|
||||
ASSERT_TRUE(iter->status().IsIncomplete());
|
||||
CheckCacheCounters(options, 1, 0, 0, 1);
|
||||
delete iter;
|
||||
@@ -263,7 +262,7 @@ TEST_F(DBBlockCacheTest, TestWithoutCompressedBlockCache) {
|
||||
ASSERT_EQ(0, cache->GetPinnedUsage());
|
||||
for (size_t i = 0; i + 1 < kNumBlocks; i++) {
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(std::to_string(i));
|
||||
iter->Seek(ToString(i));
|
||||
ASSERT_OK(iter->status());
|
||||
CheckCacheCounters(options, 0, 1, 0, 0);
|
||||
iterators[i].reset(iter);
|
||||
@@ -289,7 +288,7 @@ TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) {
|
||||
|
||||
std::string value(kValueSize, 'a');
|
||||
for (size_t i = 0; i < kNumBlocks; i++) {
|
||||
ASSERT_OK(Put(std::to_string(i), value));
|
||||
ASSERT_OK(Put(ToString(i), value));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
@@ -313,7 +312,7 @@ TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) {
|
||||
|
||||
// Load blocks into cache.
|
||||
for (size_t i = 0; i < kNumBlocks - 1; i++) {
|
||||
ASSERT_EQ(value, Get(std::to_string(i)));
|
||||
ASSERT_EQ(value, Get(ToString(i)));
|
||||
CheckCacheCounters(options, 1, 0, 1, 0);
|
||||
CheckCompressedCacheCounters(options, 1, 0, 1, 0);
|
||||
}
|
||||
@@ -334,7 +333,7 @@ TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) {
|
||||
|
||||
// Load last key block.
|
||||
ASSERT_EQ("Result incomplete: Insert failed due to LRU cache being full.",
|
||||
Get(std::to_string(kNumBlocks - 1)));
|
||||
Get(ToString(kNumBlocks - 1)));
|
||||
// Failure will also record the miss counter.
|
||||
CheckCacheCounters(options, 1, 0, 0, 1);
|
||||
CheckCompressedCacheCounters(options, 1, 0, 1, 0);
|
||||
@@ -343,7 +342,7 @@ TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) {
|
||||
// cache and load into block cache.
|
||||
cache->SetStrictCapacityLimit(false);
|
||||
// Load last key block.
|
||||
ASSERT_EQ(value, Get(std::to_string(kNumBlocks - 1)));
|
||||
ASSERT_EQ(value, Get(ToString(kNumBlocks - 1)));
|
||||
CheckCacheCounters(options, 1, 0, 1, 0);
|
||||
CheckCompressedCacheCounters(options, 0, 1, 0, 0);
|
||||
}
|
||||
@@ -568,7 +567,7 @@ TEST_F(DBBlockCacheTest, FillCacheAndIterateDB) {
|
||||
Iterator* iter = nullptr;
|
||||
|
||||
iter = db_->NewIterator(read_options);
|
||||
iter->Seek(std::to_string(0));
|
||||
iter->Seek(ToString(0));
|
||||
while (iter->Valid()) {
|
||||
iter->Next();
|
||||
}
|
||||
@@ -646,10 +645,10 @@ TEST_F(DBBlockCacheTest, WarmCacheWithDataBlocksDuringFlush) {
|
||||
|
||||
std::string value(kValueSize, 'a');
|
||||
for (size_t i = 1; i <= kNumBlocks; i++) {
|
||||
ASSERT_OK(Put(std::to_string(i), value));
|
||||
ASSERT_OK(Put(ToString(i), value));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
ASSERT_EQ(value, Get(std::to_string(i)));
|
||||
ASSERT_EQ(value, Get(ToString(i)));
|
||||
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_DATA_MISS));
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_DATA_HIT));
|
||||
}
|
||||
@@ -706,7 +705,7 @@ TEST_P(DBBlockCacheTest1, WarmCacheWithBlocksDuringFlush) {
|
||||
|
||||
std::string value(kValueSize, 'a');
|
||||
for (size_t i = 1; i <= kNumBlocks; i++) {
|
||||
ASSERT_OK(Put(std::to_string(i), value));
|
||||
ASSERT_OK(Put(ToString(i), value));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
if (filter_type == 1) {
|
||||
@@ -718,7 +717,7 @@ TEST_P(DBBlockCacheTest1, WarmCacheWithBlocksDuringFlush) {
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_INDEX_ADD));
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_FILTER_ADD));
|
||||
}
|
||||
ASSERT_EQ(value, Get(std::to_string(i)));
|
||||
ASSERT_EQ(value, Get(ToString(i)));
|
||||
|
||||
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_DATA_MISS));
|
||||
ASSERT_EQ(i, options.statistics->getTickerCount(BLOCK_CACHE_DATA_HIT));
|
||||
@@ -773,12 +772,12 @@ TEST_F(DBBlockCacheTest, DynamicallyWarmCacheDuringFlush) {
|
||||
std::string value(kValueSize, 'a');
|
||||
|
||||
for (size_t i = 1; i <= 5; i++) {
|
||||
ASSERT_OK(Put(std::to_string(i), value));
|
||||
ASSERT_OK(Put(ToString(i), value));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(1,
|
||||
options.statistics->getAndResetTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
|
||||
ASSERT_EQ(value, Get(std::to_string(i)));
|
||||
ASSERT_EQ(value, Get(ToString(i)));
|
||||
ASSERT_EQ(0,
|
||||
options.statistics->getAndResetTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
ASSERT_EQ(
|
||||
@@ -791,12 +790,12 @@ TEST_F(DBBlockCacheTest, DynamicallyWarmCacheDuringFlush) {
|
||||
{{"block_based_table_factory", "{prepopulate_block_cache=kDisable;}"}}));
|
||||
|
||||
for (size_t i = 6; i <= kNumBlocks; i++) {
|
||||
ASSERT_OK(Put(std::to_string(i), value));
|
||||
ASSERT_OK(Put(ToString(i), value));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ(0,
|
||||
options.statistics->getAndResetTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
|
||||
ASSERT_EQ(value, Get(std::to_string(i)));
|
||||
ASSERT_EQ(value, Get(ToString(i)));
|
||||
ASSERT_EQ(1,
|
||||
options.statistics->getAndResetTickerCount(BLOCK_CACHE_DATA_ADD));
|
||||
ASSERT_EQ(
|
||||
@@ -935,8 +934,7 @@ TEST_F(DBBlockCacheTest, AddRedundantStats) {
|
||||
int iterations_tested = 0;
|
||||
for (std::shared_ptr<Cache> base_cache :
|
||||
{NewLRUCache(capacity, num_shard_bits),
|
||||
NewClockCache(capacity, num_shard_bits),
|
||||
NewFastLRUCache(capacity, num_shard_bits)}) {
|
||||
NewClockCache(capacity, num_shard_bits)}) {
|
||||
if (!base_cache) {
|
||||
// Skip clock cache when not supported
|
||||
continue;
|
||||
@@ -1290,8 +1288,7 @@ TEST_F(DBBlockCacheTest, CacheEntryRoleStats) {
|
||||
int iterations_tested = 0;
|
||||
for (bool partition : {false, true}) {
|
||||
for (std::shared_ptr<Cache> cache :
|
||||
{NewLRUCache(capacity), NewClockCache(capacity),
|
||||
NewFastLRUCache(capacity)}) {
|
||||
{NewLRUCache(capacity), NewClockCache(capacity)}) {
|
||||
if (!cache) {
|
||||
// Skip clock cache when not supported
|
||||
continue;
|
||||
@@ -1409,7 +1406,7 @@ TEST_F(DBBlockCacheTest, CacheEntryRoleStats) {
|
||||
|
||||
for (size_t i = 0; i < kNumCacheEntryRoles; ++i) {
|
||||
auto role = static_cast<CacheEntryRole>(i);
|
||||
EXPECT_EQ(std::to_string(expected[i]),
|
||||
EXPECT_EQ(ToString(expected[i]),
|
||||
values[BlockCacheEntryStatsMapKeys::EntryCount(role)]);
|
||||
}
|
||||
|
||||
@@ -1422,7 +1419,7 @@ TEST_F(DBBlockCacheTest, CacheEntryRoleStats) {
|
||||
// re-scanning stats, but not totally aggressive.
|
||||
// Within some time window, we will get cached entry stats
|
||||
env_->MockSleepForSeconds(1);
|
||||
EXPECT_EQ(std::to_string(prev_expected[static_cast<size_t>(
|
||||
EXPECT_EQ(ToString(prev_expected[static_cast<size_t>(
|
||||
CacheEntryRole::kWriteBuffer)]),
|
||||
values[BlockCacheEntryStatsMapKeys::EntryCount(
|
||||
CacheEntryRole::kWriteBuffer)]);
|
||||
@@ -1432,7 +1429,7 @@ TEST_F(DBBlockCacheTest, CacheEntryRoleStats) {
|
||||
ASSERT_TRUE(db_->GetMapProperty(DB::Properties::kBlockCacheEntryStats,
|
||||
&values));
|
||||
EXPECT_EQ(
|
||||
std::to_string(
|
||||
ToString(
|
||||
expected[static_cast<size_t>(CacheEntryRole::kWriteBuffer)]),
|
||||
values[BlockCacheEntryStatsMapKeys::EntryCount(
|
||||
CacheEntryRole::kWriteBuffer)]);
|
||||
@@ -1640,7 +1637,7 @@ TEST_P(DBBlockCacheKeyTest, StableCacheKeys) {
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options);
|
||||
std::vector<std::string> external;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
std::string f = dbname_ + "/external" + std::to_string(i) + ".sst";
|
||||
std::string f = dbname_ + "/external" + ToString(i) + ".sst";
|
||||
external.push_back(f);
|
||||
ASSERT_OK(sst_file_writer.Open(f));
|
||||
ASSERT_OK(sst_file_writer.Put(Key(key_count), "abc"));
|
||||
@@ -1724,7 +1721,7 @@ class CacheKeyTest : public testing::Test {
|
||||
// Like SemiStructuredUniqueIdGen::GenerateNext
|
||||
tp_.db_session_id = EncodeSessionId(base_session_upper_,
|
||||
base_session_lower_ ^ session_counter_);
|
||||
tp_.db_id = std::to_string(db_id_);
|
||||
tp_.db_id = ToString(db_id_);
|
||||
tp_.orig_file_number = file_number_;
|
||||
bool is_stable;
|
||||
std::string cur_session_id = ""; // ignored
|
||||
|
||||
+135
-82
@@ -111,7 +111,6 @@ TEST_P(DBBloomFilterTestDefFormatVersion, KeyMayExist) {
|
||||
options_override.filter_policy = Create(20, bfp_impl_);
|
||||
options_override.partition_filters = partition_filters_;
|
||||
options_override.metadata_block_size = 32;
|
||||
options_override.full_block_cache = true;
|
||||
Options options = CurrentOptions(options_override);
|
||||
if (partition_filters_) {
|
||||
auto* table_options =
|
||||
@@ -858,7 +857,7 @@ TEST_F(DBBloomFilterTest, BloomFilterCompatibility) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
|
||||
std::string prefix = std::to_string(i) + "_";
|
||||
std::string prefix = ToString(i) + "_";
|
||||
ASSERT_OK(Put(prefix + "A", "val"));
|
||||
ASSERT_OK(Put(prefix + "Z", "val"));
|
||||
ASSERT_OK(Flush());
|
||||
@@ -873,7 +872,7 @@ TEST_F(DBBloomFilterTest, BloomFilterCompatibility) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
for (size_t j = 0; j < kCompatibilityConfigs.size(); ++j) {
|
||||
std::string prefix = std::to_string(j) + "_";
|
||||
std::string prefix = ToString(j) + "_";
|
||||
ASSERT_EQ("val", Get(prefix + "A")); // Filter positive
|
||||
ASSERT_EQ("val", Get(prefix + "Z")); // Filter positive
|
||||
// Filter negative, with high probability
|
||||
@@ -886,27 +885,103 @@ TEST_F(DBBloomFilterTest, BloomFilterCompatibility) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A cache wrapper that tracks peaks and increments of filter
|
||||
* construction cache reservation.
|
||||
* p0
|
||||
* / \ p1
|
||||
* / \ /\
|
||||
* / \/ \
|
||||
* a / b \
|
||||
* peaks = {p0, p1}
|
||||
* increments = {p1-a, p2-b}
|
||||
*/
|
||||
class FilterConstructResPeakTrackingCache : public CacheWrapper {
|
||||
public:
|
||||
explicit FilterConstructResPeakTrackingCache(std::shared_ptr<Cache> target)
|
||||
: CacheWrapper(std::move(target)),
|
||||
cur_cache_res_(0),
|
||||
cache_res_peak_(0),
|
||||
cache_res_increment_(0),
|
||||
last_peak_tracked_(false),
|
||||
cache_res_increments_sum_(0) {}
|
||||
|
||||
using Cache::Insert;
|
||||
Status Insert(const Slice& key, void* value, size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value),
|
||||
Handle** handle = nullptr,
|
||||
Priority priority = Priority::LOW) override {
|
||||
Status s = target_->Insert(key, value, charge, deleter, handle, priority);
|
||||
if (deleter == kNoopDeleterForFilterConstruction) {
|
||||
if (last_peak_tracked_) {
|
||||
cache_res_peak_ = 0;
|
||||
cache_res_increment_ = 0;
|
||||
last_peak_tracked_ = false;
|
||||
}
|
||||
cur_cache_res_ += charge;
|
||||
cache_res_peak_ = std::max(cache_res_peak_, cur_cache_res_);
|
||||
cache_res_increment_ += charge;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
using Cache::Release;
|
||||
bool Release(Handle* handle, bool erase_if_last_ref = false) override {
|
||||
auto deleter = GetDeleter(handle);
|
||||
if (deleter == kNoopDeleterForFilterConstruction) {
|
||||
if (!last_peak_tracked_) {
|
||||
cache_res_peaks_.push_back(cache_res_peak_);
|
||||
cache_res_increments_sum_ += cache_res_increment_;
|
||||
last_peak_tracked_ = true;
|
||||
}
|
||||
cur_cache_res_ -= GetCharge(handle);
|
||||
}
|
||||
bool is_successful = target_->Release(handle, erase_if_last_ref);
|
||||
return is_successful;
|
||||
}
|
||||
|
||||
std::deque<std::size_t> GetReservedCachePeaks() { return cache_res_peaks_; }
|
||||
|
||||
std::size_t GetReservedCacheIncrementSum() {
|
||||
return cache_res_increments_sum_;
|
||||
}
|
||||
|
||||
private:
|
||||
static const Cache::DeleterFn kNoopDeleterForFilterConstruction;
|
||||
|
||||
std::size_t cur_cache_res_;
|
||||
std::size_t cache_res_peak_;
|
||||
std::size_t cache_res_increment_;
|
||||
bool last_peak_tracked_;
|
||||
std::deque<std::size_t> cache_res_peaks_;
|
||||
std::size_t cache_res_increments_sum_;
|
||||
};
|
||||
|
||||
const Cache::DeleterFn
|
||||
FilterConstructResPeakTrackingCache::kNoopDeleterForFilterConstruction =
|
||||
CacheReservationManagerImpl<
|
||||
CacheEntryRole::kFilterConstruction>::TEST_GetNoopDeleterForRole();
|
||||
|
||||
// To align with the type of hash entry being reserved in implementation.
|
||||
using FilterConstructionReserveMemoryHash = uint64_t;
|
||||
|
||||
class ChargeFilterConstructionTestWithParam
|
||||
class DBFilterConstructionReserveMemoryTestWithParam
|
||||
: public DBTestBase,
|
||||
public testing::WithParamInterface<std::tuple<
|
||||
CacheEntryRoleOptions::Decision, std::string, bool, bool>> {
|
||||
public testing::WithParamInterface<
|
||||
std::tuple<bool, std::string, bool, bool>> {
|
||||
public:
|
||||
ChargeFilterConstructionTestWithParam()
|
||||
DBFilterConstructionReserveMemoryTestWithParam()
|
||||
: DBTestBase("db_bloom_filter_tests",
|
||||
/*env_do_fsync=*/true),
|
||||
num_key_(0),
|
||||
charge_filter_construction_(std::get<0>(GetParam())),
|
||||
reserve_table_builder_memory_(std::get<0>(GetParam())),
|
||||
policy_(std::get<1>(GetParam())),
|
||||
partition_filters_(std::get<2>(GetParam())),
|
||||
detect_filter_construct_corruption_(std::get<3>(GetParam())) {
|
||||
if (charge_filter_construction_ ==
|
||||
CacheEntryRoleOptions::Decision::kDisabled ||
|
||||
policy_ == kDeprecatedBlock || policy_ == kLegacyBloom) {
|
||||
if (!reserve_table_builder_memory_ || policy_ == kDeprecatedBlock ||
|
||||
policy_ == kLegacyBloom) {
|
||||
// For these cases, we only interested in whether filter construction
|
||||
// cache charging happens instead of its accuracy. Therefore we don't
|
||||
// cache resevation happens instead of its accuracy. Therefore we don't
|
||||
// need many keys.
|
||||
num_key_ = 5;
|
||||
} else if (partition_filters_) {
|
||||
@@ -921,11 +996,11 @@ class ChargeFilterConstructionTestWithParam
|
||||
sizeof(FilterConstructionReserveMemoryHash);
|
||||
} else if (policy_ == kFastLocalBloom) {
|
||||
// For Bloom Filter + FullFilter case, since we design the num_key_ to
|
||||
// make hash entry cache charging be a multiple of dummy entries, the
|
||||
// make hash entry cache reservation be a multiple of dummy entries, the
|
||||
// correct behavior of charging final filter on top of it will trigger at
|
||||
// least another dummy entry insertion. Therefore we can assert that
|
||||
// behavior and we don't need a large number of keys to verify we
|
||||
// indeed charge the final filter for in cache, even though final
|
||||
// indeed charge the final filter for cache reservation, even though final
|
||||
// filter is a lot smaller than hash entries.
|
||||
num_key_ = 1 *
|
||||
CacheReservationManagerImpl<
|
||||
@@ -935,7 +1010,7 @@ class ChargeFilterConstructionTestWithParam
|
||||
// For Ribbon Filter + FullFilter case, we need a large enough number of
|
||||
// keys so that charging final filter after releasing the hash entries
|
||||
// reservation will trigger at least another dummy entry (or equivalently
|
||||
// to saying, causing another peak in cache charging) as banding
|
||||
// to saying, causing another peak in cache reservation) as banding
|
||||
// reservation might not be a multiple of dummy entry.
|
||||
num_key_ = 12 *
|
||||
CacheReservationManagerImpl<
|
||||
@@ -951,9 +1026,7 @@ class ChargeFilterConstructionTestWithParam
|
||||
// calculation.
|
||||
constexpr std::size_t kCacheCapacity = 100 * 1024 * 1024;
|
||||
|
||||
table_options.cache_usage_options.options_overrides.insert(
|
||||
{CacheEntryRole::kFilterConstruction,
|
||||
{/*.charged = */ charge_filter_construction_}});
|
||||
table_options.reserve_table_builder_memory = reserve_table_builder_memory_;
|
||||
table_options.filter_policy = Create(10, policy_);
|
||||
table_options.partition_filters = partition_filters_;
|
||||
if (table_options.partition_filters) {
|
||||
@@ -971,8 +1044,7 @@ class ChargeFilterConstructionTestWithParam
|
||||
lo.capacity = kCacheCapacity;
|
||||
lo.num_shard_bits = 0; // 2^0 shard
|
||||
lo.strict_capacity_limit = true;
|
||||
cache_ = std::make_shared<
|
||||
TargetCacheChargeTrackingCache<CacheEntryRole::kFilterConstruction>>(
|
||||
cache_ = std::make_shared<FilterConstructResPeakTrackingCache>(
|
||||
(NewLRUCache(lo)));
|
||||
table_options.block_cache = cache_;
|
||||
|
||||
@@ -981,73 +1053,56 @@ class ChargeFilterConstructionTestWithParam
|
||||
|
||||
std::size_t GetNumKey() { return num_key_; }
|
||||
|
||||
CacheEntryRoleOptions::Decision ChargeFilterConstructMemory() {
|
||||
return charge_filter_construction_;
|
||||
}
|
||||
bool ReserveTableBuilderMemory() { return reserve_table_builder_memory_; }
|
||||
|
||||
std::string GetFilterPolicy() { return policy_; }
|
||||
|
||||
bool PartitionFilters() { return partition_filters_; }
|
||||
|
||||
std::shared_ptr<
|
||||
TargetCacheChargeTrackingCache<CacheEntryRole::kFilterConstruction>>
|
||||
GetCache() {
|
||||
std::shared_ptr<FilterConstructResPeakTrackingCache>
|
||||
GetFilterConstructResPeakTrackingCache() {
|
||||
return cache_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t num_key_;
|
||||
CacheEntryRoleOptions::Decision charge_filter_construction_;
|
||||
bool reserve_table_builder_memory_;
|
||||
std::string policy_;
|
||||
bool partition_filters_;
|
||||
std::shared_ptr<
|
||||
TargetCacheChargeTrackingCache<CacheEntryRole::kFilterConstruction>>
|
||||
cache_;
|
||||
std::shared_ptr<FilterConstructResPeakTrackingCache> cache_;
|
||||
bool detect_filter_construct_corruption_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
ChargeFilterConstructionTestWithParam,
|
||||
ChargeFilterConstructionTestWithParam,
|
||||
::testing::Values(
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kDisabled,
|
||||
kFastLocalBloom, false, false),
|
||||
DBFilterConstructionReserveMemoryTestWithParam,
|
||||
DBFilterConstructionReserveMemoryTestWithParam,
|
||||
::testing::Values(std::make_tuple(false, kFastLocalBloom, false, false),
|
||||
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kFastLocalBloom, false, false),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kFastLocalBloom, false, true),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kFastLocalBloom, true, false),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kFastLocalBloom, true, true),
|
||||
std::make_tuple(true, kFastLocalBloom, false, false),
|
||||
std::make_tuple(true, kFastLocalBloom, false, true),
|
||||
std::make_tuple(true, kFastLocalBloom, true, false),
|
||||
std::make_tuple(true, kFastLocalBloom, true, true),
|
||||
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kStandard128Ribbon, false, false),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kStandard128Ribbon, false, true),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kStandard128Ribbon, true, false),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kStandard128Ribbon, true, true),
|
||||
std::make_tuple(true, kStandard128Ribbon, false, false),
|
||||
std::make_tuple(true, kStandard128Ribbon, false, true),
|
||||
std::make_tuple(true, kStandard128Ribbon, true, false),
|
||||
std::make_tuple(true, kStandard128Ribbon, true, true),
|
||||
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled,
|
||||
kDeprecatedBlock, false, false),
|
||||
std::make_tuple(CacheEntryRoleOptions::Decision::kEnabled, kLegacyBloom,
|
||||
false, false)));
|
||||
std::make_tuple(true, kDeprecatedBlock, false, false),
|
||||
std::make_tuple(true, kLegacyBloom, false, false)));
|
||||
|
||||
// TODO: Speed up this test, and reduce disk space usage (~700MB)
|
||||
// The current test inserts many keys (on the scale of dummy entry size)
|
||||
// in order to make small memory user (e.g, final filter, partitioned hash
|
||||
// entries/filter/banding) , which is proportional to the number of
|
||||
// keys, big enough so that its cache charging triggers dummy entry insertion
|
||||
// keys, big enough so that its cache reservation triggers dummy entry insertion
|
||||
// and becomes observable in the test.
|
||||
//
|
||||
// However, inserting that many keys slows down this test and leaves future
|
||||
// developers an opportunity to speed it up.
|
||||
//
|
||||
// Possible approaches & challenges:
|
||||
// 1. Use sync point during cache charging of filter construction
|
||||
// 1. Use sync point during cache reservation of filter construction
|
||||
//
|
||||
// Benefit: It does not rely on triggering dummy entry insertion
|
||||
// but the sync point to verify small memory user is charged correctly.
|
||||
@@ -1056,7 +1111,7 @@ INSTANTIATE_TEST_CASE_P(
|
||||
//
|
||||
// 2. Make dummy entry size configurable and set it small in the test
|
||||
//
|
||||
// Benefit: It increases the precision of cache charging and therefore
|
||||
// Benefit: It increases the precision of cache reservation and therefore
|
||||
// small memory usage can still trigger insertion of dummy entry.
|
||||
//
|
||||
// Challenge: change CacheReservationManager related APIs and a hack
|
||||
@@ -1064,17 +1119,16 @@ INSTANTIATE_TEST_CASE_P(
|
||||
// CacheReservationManager used in filter construction for testing
|
||||
// since CacheReservationManager is not exposed at the high level.
|
||||
//
|
||||
TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
TEST_P(DBFilterConstructionReserveMemoryTestWithParam, ReserveMemory) {
|
||||
Options options = CurrentOptions();
|
||||
// We set write_buffer_size big enough so that in the case where there is
|
||||
// filter construction cache charging, flush won't be triggered before we
|
||||
// filter construction cache reservation, flush won't be triggered before we
|
||||
// manually trigger it for clean testing
|
||||
options.write_buffer_size = 640 << 20;
|
||||
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
std::shared_ptr<
|
||||
TargetCacheChargeTrackingCache<CacheEntryRole::kFilterConstruction>>
|
||||
cache = GetCache();
|
||||
std::shared_ptr<FilterConstructResPeakTrackingCache> cache =
|
||||
GetFilterConstructResPeakTrackingCache();
|
||||
options.create_if_missing = true;
|
||||
// Disable auto compaction to prevent its unexpected side effect
|
||||
// to the number of keys per partition designed by us in the test
|
||||
@@ -1085,33 +1139,32 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
ASSERT_OK(Put(Key(i), Key(i)));
|
||||
}
|
||||
|
||||
ASSERT_EQ(cache->GetChargedCacheIncrementSum(), 0)
|
||||
ASSERT_EQ(cache->GetReservedCacheIncrementSum(), 0)
|
||||
<< "Flush was triggered too early in the test case with filter "
|
||||
"construction cache charging - please make sure no flush triggered "
|
||||
"construction cache reservation - please make sure no flush triggered "
|
||||
"during the key insertions above";
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
bool charge_filter_construction = (ChargeFilterConstructMemory() ==
|
||||
CacheEntryRoleOptions::Decision::kEnabled);
|
||||
bool reserve_table_builder_memory = ReserveTableBuilderMemory();
|
||||
std::string policy = GetFilterPolicy();
|
||||
bool partition_filters = PartitionFilters();
|
||||
bool detect_filter_construct_corruption =
|
||||
table_options.detect_filter_construct_corruption;
|
||||
|
||||
std::deque<std::size_t> filter_construction_cache_res_peaks =
|
||||
cache->GetChargedCachePeaks();
|
||||
cache->GetReservedCachePeaks();
|
||||
std::size_t filter_construction_cache_res_increments_sum =
|
||||
cache->GetChargedCacheIncrementSum();
|
||||
cache->GetReservedCacheIncrementSum();
|
||||
|
||||
if (!charge_filter_construction) {
|
||||
if (!reserve_table_builder_memory) {
|
||||
EXPECT_EQ(filter_construction_cache_res_peaks.size(), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (policy == kDeprecatedBlock || policy == kLegacyBloom) {
|
||||
EXPECT_EQ(filter_construction_cache_res_peaks.size(), 0)
|
||||
<< "There shouldn't be filter construction cache charging as this "
|
||||
<< "There shouldn't be filter construction cache reservation as this "
|
||||
"feature does not support kDeprecatedBlock "
|
||||
"nor kLegacyBloom";
|
||||
return;
|
||||
@@ -1185,14 +1238,14 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
*/
|
||||
if (!partition_filters) {
|
||||
EXPECT_EQ(filter_construction_cache_res_peaks.size(), 1)
|
||||
<< "Filter construction cache charging should have only 1 peak in "
|
||||
<< "Filter construction cache reservation should have only 1 peak in "
|
||||
"case: kFastLocalBloom + FullFilter";
|
||||
std::size_t filter_construction_cache_res_peak =
|
||||
filter_construction_cache_res_peaks[0];
|
||||
EXPECT_GT(filter_construction_cache_res_peak,
|
||||
predicted_hash_entries_cache_res)
|
||||
<< "The testing number of hash entries is designed to make hash "
|
||||
"entries cache charging be multiples of dummy entries"
|
||||
"entries cache reservation be multiples of dummy entries"
|
||||
" so the correct behavior of charging final filter on top of it"
|
||||
" should've triggered at least another dummy entry insertion";
|
||||
|
||||
@@ -1205,7 +1258,7 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
return;
|
||||
} else {
|
||||
EXPECT_GE(filter_construction_cache_res_peaks.size(), 2)
|
||||
<< "Filter construction cache charging should have multiple peaks "
|
||||
<< "Filter construction cache reservation should have multiple peaks "
|
||||
"in case: kFastLocalBloom + "
|
||||
"PartitionedFilter";
|
||||
std::size_t predicted_filter_construction_cache_res_increments_sum =
|
||||
@@ -1312,11 +1365,11 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
CacheReservationManagerImpl<
|
||||
CacheEntryRole::kFilterConstruction>::GetDummyEntrySize()),
|
||||
1)
|
||||
<< "Final filter cache charging too small for this test - please "
|
||||
<< "Final filter cache reservation too small for this test - please "
|
||||
"increase the number of keys";
|
||||
if (!detect_filter_construct_corruption) {
|
||||
EXPECT_EQ(filter_construction_cache_res_peaks.size(), 2)
|
||||
<< "Filter construction cache charging should have 2 peaks in "
|
||||
<< "Filter construction cache reservation should have 2 peaks in "
|
||||
"case: kStandard128Ribbon + "
|
||||
"FullFilter. "
|
||||
"The second peak is resulted from charging the final filter "
|
||||
@@ -1335,7 +1388,7 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
predicted_filter_construction_cache_res_peak * 1.1);
|
||||
} else {
|
||||
EXPECT_EQ(filter_construction_cache_res_peaks.size(), 1)
|
||||
<< "Filter construction cache charging should have 1 peaks in "
|
||||
<< "Filter construction cache reservation should have 1 peaks in "
|
||||
"case: kStandard128Ribbon + FullFilter "
|
||||
"+ detect_filter_construct_corruption. "
|
||||
"The previous second peak now disappears since we don't "
|
||||
@@ -1356,13 +1409,13 @@ TEST_P(ChargeFilterConstructionTestWithParam, Basic) {
|
||||
} else {
|
||||
if (!detect_filter_construct_corruption) {
|
||||
EXPECT_GE(filter_construction_cache_res_peaks.size(), 3)
|
||||
<< "Filter construction cache charging should have more than 3 "
|
||||
<< "Filter construction cache reservation should have more than 3 "
|
||||
"peaks "
|
||||
"in case: kStandard128Ribbon + "
|
||||
"PartitionedFilter";
|
||||
} else {
|
||||
EXPECT_GE(filter_construction_cache_res_peaks.size(), 2)
|
||||
<< "Filter construction cache charging should have more than 2 "
|
||||
<< "Filter construction cache reservation should have more than 2 "
|
||||
"peaks "
|
||||
"in case: kStandard128Ribbon + "
|
||||
"PartitionedFilter + detect_filter_construct_corruption";
|
||||
@@ -1659,11 +1712,11 @@ class TestingContextCustomFilterPolicy
|
||||
test_report_ +=
|
||||
OptionsHelper::compaction_style_to_string[context.compaction_style];
|
||||
test_report_ += ",n=";
|
||||
test_report_ += std::to_string(context.num_levels);
|
||||
test_report_ += ROCKSDB_NAMESPACE::ToString(context.num_levels);
|
||||
test_report_ += ",l=";
|
||||
test_report_ += std::to_string(context.level_at_creation);
|
||||
test_report_ += ROCKSDB_NAMESPACE::ToString(context.level_at_creation);
|
||||
test_report_ += ",b=";
|
||||
test_report_ += std::to_string(int{context.is_bottommost});
|
||||
test_report_ += ROCKSDB_NAMESPACE::ToString(int{context.is_bottommost});
|
||||
test_report_ += ",r=";
|
||||
test_report_ += table_file_creation_reason_to_string[context.reason];
|
||||
test_report_ += "\n";
|
||||
|
||||
@@ -454,7 +454,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterDeletesAll) {
|
||||
// put some data
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(Put(std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -755,7 +755,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterContextCfId) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
// Compaction filters aplies to all records, regardless snapshots.
|
||||
TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
std::string five = std::to_string(5);
|
||||
std::string five = ToString(5);
|
||||
Options options = CurrentOptions();
|
||||
options.compaction_filter_factory = std::make_shared<DeleteISFilterFactory>();
|
||||
options.disable_auto_compactions = true;
|
||||
@@ -766,7 +766,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
const Snapshot* snapshot = nullptr;
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ASSERT_OK(Put(std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
@@ -968,71 +968,6 @@ TEST_F(DBTestCompactionFilter, IgnoreSnapshotsFalseRecovery) {
|
||||
ASSERT_TRUE(TryReopen(options).IsNotSupported());
|
||||
}
|
||||
|
||||
TEST_F(DBTestCompactionFilter, DropKeyWithSingleDelete) {
|
||||
Options options = GetDefaultOptions();
|
||||
options.create_if_missing = true;
|
||||
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put("a", "v0"));
|
||||
ASSERT_OK(Put("b", "v0"));
|
||||
const Snapshot* snapshot = db_->GetSnapshot();
|
||||
|
||||
ASSERT_OK(SingleDelete("b"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
{
|
||||
CompactRangeOptions cro;
|
||||
cro.change_level = true;
|
||||
cro.target_level = options.num_levels - 1;
|
||||
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
||||
}
|
||||
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
Close();
|
||||
|
||||
class DeleteFilterV2 : public CompactionFilter {
|
||||
public:
|
||||
Decision FilterV2(int /*level*/, const Slice& key, ValueType /*value_type*/,
|
||||
const Slice& /*existing_value*/,
|
||||
std::string* /*new_value*/,
|
||||
std::string* /*skip_until*/) const override {
|
||||
if (key.starts_with("b")) {
|
||||
return Decision::kPurge;
|
||||
}
|
||||
return Decision::kRemove;
|
||||
}
|
||||
|
||||
const char* Name() const override { return "DeleteFilterV2"; }
|
||||
} delete_filter_v2;
|
||||
|
||||
options.compaction_filter = &delete_filter_v2;
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put("b", "v1"));
|
||||
ASSERT_OK(Put("x", "v1"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(Put("r", "v1"));
|
||||
ASSERT_OK(Put("z", "v1"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
Close();
|
||||
|
||||
options.compaction_filter = nullptr;
|
||||
Reopen(options);
|
||||
ASSERT_OK(SingleDelete("b"));
|
||||
ASSERT_OK(Flush());
|
||||
{
|
||||
CompactRangeOptions cro;
|
||||
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
|
||||
ASSERT_OK(db_->CompactRange(cro, nullptr, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
+13
-38
@@ -2409,30 +2409,6 @@ TEST_P(DBCompactionTestWithParam, LevelCompactionCFPathUse) {
|
||||
|
||||
check_getvalues();
|
||||
|
||||
{ // Also verify GetLiveFilesStorageInfo with db_paths / cf_paths
|
||||
std::vector<LiveFileStorageInfo> new_infos;
|
||||
LiveFilesStorageInfoOptions lfsio;
|
||||
lfsio.wal_size_for_flush = UINT64_MAX; // no flush
|
||||
ASSERT_OK(db_->GetLiveFilesStorageInfo(lfsio, &new_infos));
|
||||
std::unordered_map<std::string, int> live_sst_by_dir;
|
||||
for (auto& info : new_infos) {
|
||||
if (info.file_type == kTableFile) {
|
||||
live_sst_by_dir[info.directory]++;
|
||||
// Verify file on disk (no directory confusion)
|
||||
uint64_t size;
|
||||
ASSERT_OK(env_->GetFileSize(
|
||||
info.directory + "/" + info.relative_filename, &size));
|
||||
ASSERT_EQ(info.size, size);
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(3U * 3U, live_sst_by_dir.size());
|
||||
for (auto& paths : {options.db_paths, cf_opt1.cf_paths, cf_opt2.cf_paths}) {
|
||||
ASSERT_EQ(1, live_sst_by_dir[paths[0].path]);
|
||||
ASSERT_EQ(4, live_sst_by_dir[paths[1].path]);
|
||||
ASSERT_EQ(2, live_sst_by_dir[paths[2].path]);
|
||||
}
|
||||
}
|
||||
|
||||
ReopenWithColumnFamilies({"default", "one", "two"}, option_vector);
|
||||
|
||||
check_getvalues();
|
||||
@@ -2817,7 +2793,7 @@ TEST_P(DBCompactionTestWithParam, DISABLED_CompactFilesOnLevelCompaction) {
|
||||
|
||||
Random rnd(301);
|
||||
for (int key = 64 * kEntriesPerBuffer; key >= 0; --key) {
|
||||
ASSERT_OK(Put(1, std::to_string(key), rnd.RandomString(kTestValueSize)));
|
||||
ASSERT_OK(Put(1, ToString(key), rnd.RandomString(kTestValueSize)));
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(handles_[1]));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -2849,7 +2825,7 @@ TEST_P(DBCompactionTestWithParam, DISABLED_CompactFilesOnLevelCompaction) {
|
||||
|
||||
// make sure all key-values are still there.
|
||||
for (int key = 64 * kEntriesPerBuffer; key >= 0; --key) {
|
||||
ASSERT_NE(Get(1, std::to_string(key)), "NOT_FOUND");
|
||||
ASSERT_NE(Get(1, ToString(key)), "NOT_FOUND");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4404,8 +4380,7 @@ TEST_F(DBCompactionTest, LevelPeriodicCompactionWithCompactionFilters) {
|
||||
for (CompactionFilterType comp_filter_type :
|
||||
{kUseCompactionFilter, kUseCompactionFilterFactory}) {
|
||||
// Assert that periodic compactions are not enabled.
|
||||
ASSERT_EQ(std::numeric_limits<uint64_t>::max() - 1,
|
||||
options.periodic_compaction_seconds);
|
||||
ASSERT_EQ(port::kMaxUint64 - 1, options.periodic_compaction_seconds);
|
||||
|
||||
if (comp_filter_type == kUseCompactionFilter) {
|
||||
options.compaction_filter = &test_compaction_filter;
|
||||
@@ -4668,9 +4643,9 @@ TEST_F(DBCompactionTest, CompactRangeSkipFlushAfterDelay) {
|
||||
});
|
||||
|
||||
TEST_SYNC_POINT("DBCompactionTest::CompactRangeSkipFlushAfterDelay:PreFlush");
|
||||
ASSERT_OK(Put(std::to_string(0), rnd.RandomString(1024)));
|
||||
ASSERT_OK(Put(ToString(0), rnd.RandomString(1024)));
|
||||
ASSERT_OK(dbfull()->Flush(flush_opts));
|
||||
ASSERT_OK(Put(std::to_string(0), rnd.RandomString(1024)));
|
||||
ASSERT_OK(Put(ToString(0), rnd.RandomString(1024)));
|
||||
TEST_SYNC_POINT("DBCompactionTest::CompactRangeSkipFlushAfterDelay:PostFlush");
|
||||
manual_compaction_thread.join();
|
||||
|
||||
@@ -4679,7 +4654,7 @@ TEST_F(DBCompactionTest, CompactRangeSkipFlushAfterDelay) {
|
||||
std::string num_keys_in_memtable;
|
||||
ASSERT_TRUE(db_->GetProperty(DB::Properties::kNumEntriesActiveMemTable,
|
||||
&num_keys_in_memtable));
|
||||
ASSERT_EQ(std::to_string(1), num_keys_in_memtable);
|
||||
ASSERT_EQ(ToString(1), num_keys_in_memtable);
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
@@ -4828,7 +4803,7 @@ TEST_F(DBCompactionTest, SubcompactionEvent) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 10 + j;
|
||||
ASSERT_OK(Put(Key(key_id), "value" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -4838,7 +4813,7 @@ TEST_F(DBCompactionTest, SubcompactionEvent) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
int key_id = i * 20 + j * 2;
|
||||
ASSERT_OK(Put(Key(key_id), "value" + std::to_string(key_id)));
|
||||
ASSERT_OK(Put(Key(key_id), "value" + ToString(key_id)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -5830,7 +5805,7 @@ TEST_P(DBCompactionTestWithBottommostParam, SequenceKeysManualCompaction) {
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
|
||||
ASSERT_EQ(std::to_string(kSstNum), FilesPerLevel(0));
|
||||
ASSERT_EQ(ToString(kSstNum), FilesPerLevel(0));
|
||||
|
||||
auto cro = CompactRangeOptions();
|
||||
cro.bottommost_level_compaction = bottommost_level_compaction_;
|
||||
@@ -5843,7 +5818,7 @@ TEST_P(DBCompactionTestWithBottommostParam, SequenceKeysManualCompaction) {
|
||||
ASSERT_EQ("0,1", FilesPerLevel(0));
|
||||
} else {
|
||||
// Just trivial move from level 0 -> 1
|
||||
ASSERT_EQ("0," + std::to_string(kSstNum), FilesPerLevel(0));
|
||||
ASSERT_EQ("0," + ToString(kSstNum), FilesPerLevel(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7174,7 +7149,7 @@ TEST_F(DBCompactionTest, DisableManualCompactionThreadQueueFull) {
|
||||
ASSERT_OK(Put(Key(2), "value2"));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ(std::to_string(kNumL0Files + (kNumL0Files / 2)), FilesPerLevel(0));
|
||||
ASSERT_EQ(ToString(kNumL0Files + (kNumL0Files / 2)), FilesPerLevel(0));
|
||||
|
||||
db_->DisableManualCompaction();
|
||||
|
||||
@@ -7231,7 +7206,7 @@ TEST_F(DBCompactionTest, DisableManualCompactionThreadQueueFullDBClose) {
|
||||
ASSERT_OK(Put(Key(2), "value2"));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ(std::to_string(kNumL0Files + (kNumL0Files / 2)), FilesPerLevel(0));
|
||||
ASSERT_EQ(ToString(kNumL0Files + (kNumL0Files / 2)), FilesPerLevel(0));
|
||||
|
||||
db_->DisableManualCompaction();
|
||||
|
||||
@@ -7291,7 +7266,7 @@ TEST_F(DBCompactionTest, DBCloseWithManualCompaction) {
|
||||
ASSERT_OK(Put(Key(2), "value2"));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ(std::to_string(kNumL0Files + (kNumL0Files / 2)), FilesPerLevel(0));
|
||||
ASSERT_EQ(ToString(kNumL0Files + (kNumL0Files / 2)), FilesPerLevel(0));
|
||||
|
||||
// Close DB with manual compaction and auto triggered compaction in the queue.
|
||||
auto s = db_->Close();
|
||||
|
||||
+2
-41
@@ -124,9 +124,6 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
|
||||
}
|
||||
|
||||
Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
|
||||
// Record tracked WALs as a (minimum) cross-check for directory scan
|
||||
std::vector<uint64_t> required_by_manifest;
|
||||
|
||||
// If caller disabled deletions, this function should return files that are
|
||||
// guaranteed not to be deleted until deletions are re-enabled. We need to
|
||||
// wait for pending purges to finish since WalManager doesn't know which
|
||||
@@ -140,13 +137,6 @@ Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
|
||||
while (pending_purge_obsolete_files_ > 0 || bg_purge_scheduled_ > 0) {
|
||||
bg_cv_.Wait();
|
||||
}
|
||||
|
||||
// Record tracked WALs as a (minimum) cross-check for directory scan
|
||||
const auto& manifest_wals = versions_->GetWalSet().GetWals();
|
||||
required_by_manifest.reserve(manifest_wals.size());
|
||||
for (const auto& wal : manifest_wals) {
|
||||
required_by_manifest.push_back(wal.first);
|
||||
}
|
||||
}
|
||||
|
||||
Status s = wal_manager_.GetSortedWalFiles(files);
|
||||
@@ -160,29 +150,6 @@ Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
|
||||
assert(deletions_disabled.IsNotSupported());
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
// Verify includes those required by manifest (one sorted list is superset
|
||||
// of the other)
|
||||
auto required = required_by_manifest.begin();
|
||||
auto included = files.begin();
|
||||
|
||||
while (required != required_by_manifest.end()) {
|
||||
if (included == files.end() || *required < (*included)->LogNumber()) {
|
||||
// FAIL - did not find
|
||||
return Status::Corruption(
|
||||
"WAL file " + std::to_string(*required) +
|
||||
" required by manifest but not in directory list");
|
||||
}
|
||||
if (*required == (*included)->LogNumber()) {
|
||||
++required;
|
||||
++included;
|
||||
} else {
|
||||
assert(*required > (*included)->LogNumber());
|
||||
++included;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -210,7 +177,7 @@ Status DBImpl::GetLiveFilesStorageInfo(
|
||||
VectorLogPtr live_wal_files;
|
||||
bool flush_memtable = true;
|
||||
if (!immutable_db_options_.allow_2pc) {
|
||||
if (opts.wal_size_for_flush == std::numeric_limits<uint64_t>::max()) {
|
||||
if (opts.wal_size_for_flush == port::kMaxUint64) {
|
||||
flush_memtable = false;
|
||||
} else if (opts.wal_size_for_flush > 0) {
|
||||
// If the outstanding log files are small, we skip the flush.
|
||||
@@ -382,13 +349,7 @@ Status DBImpl::GetLiveFilesStorageInfo(
|
||||
TEST_SYNC_POINT("CheckpointImpl::CreateCheckpoint:SavedLiveFiles2");
|
||||
|
||||
if (s.ok()) {
|
||||
// To maximize the effectiveness of track_and_verify_wals_in_manifest,
|
||||
// sync WAL when it is enabled.
|
||||
s = FlushWAL(
|
||||
immutable_db_options_.track_and_verify_wals_in_manifest /* sync */);
|
||||
if (s.IsNotSupported()) { // read-only DB or similar
|
||||
s = Status::OK();
|
||||
}
|
||||
s = FlushWAL(false /* sync */);
|
||||
}
|
||||
|
||||
TEST_SYNC_POINT("CheckpointImpl::CreateCustomCheckpoint:AfterGetLive1");
|
||||
|
||||
+1
-1
@@ -2356,7 +2356,7 @@ TEST_P(DBAtomicFlushTest, PrecomputeMinLogNumberToKeepNon2PC) {
|
||||
ASSERT_OK(Flush(cf_ids));
|
||||
uint64_t log_num_after_flush = dbfull()->TEST_GetCurrentLogNumber();
|
||||
|
||||
uint64_t min_log_number_to_keep = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t min_log_number_to_keep = port::kMaxUint64;
|
||||
autovector<ColumnFamilyData*> flushed_cfds;
|
||||
autovector<autovector<VersionEdit*>> flush_edits;
|
||||
for (size_t i = 0; i != num_cfs; ++i) {
|
||||
|
||||
+31
-21
@@ -567,7 +567,7 @@ Status DBImpl::CloseHelper() {
|
||||
// flushing by first checking if there is a need for
|
||||
// flushing (but need to implement something
|
||||
// else than imm()->IsFlushPending() because the output
|
||||
// memtables added to imm() don't trigger flushes).
|
||||
// memtables added to imm() dont trigger flushes).
|
||||
if (immutable_db_options_.experimental_mempurge_threshold > 0.0) {
|
||||
Status flush_ret;
|
||||
mutex_.Unlock();
|
||||
@@ -849,8 +849,7 @@ void DBImpl::PersistStats() {
|
||||
if (stats_slice_.find(stat.first) != stats_slice_.end()) {
|
||||
uint64_t delta = stat.second - stats_slice_[stat.first];
|
||||
s = batch.Put(persist_stats_cf_handle_,
|
||||
Slice(key, std::min(100, length)),
|
||||
std::to_string(delta));
|
||||
Slice(key, std::min(100, length)), ToString(delta));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1337,7 +1336,6 @@ Status DBImpl::FlushWAL(bool sync) {
|
||||
}
|
||||
|
||||
Status DBImpl::SyncWAL() {
|
||||
TEST_SYNC_POINT("DBImpl::SyncWAL:Begin");
|
||||
autovector<log::Writer*, 1> logs_to_sync;
|
||||
bool need_log_dir_sync;
|
||||
uint64_t current_log_number;
|
||||
@@ -1350,7 +1348,7 @@ Status DBImpl::SyncWAL() {
|
||||
current_log_number = logfile_number_;
|
||||
|
||||
while (logs_.front().number <= current_log_number &&
|
||||
logs_.front().IsSyncing()) {
|
||||
logs_.front().getting_synced) {
|
||||
log_sync_cv_.Wait();
|
||||
}
|
||||
// First check that logs are safe to sync in background.
|
||||
@@ -1367,7 +1365,8 @@ Status DBImpl::SyncWAL() {
|
||||
for (auto it = logs_.begin();
|
||||
it != logs_.end() && it->number <= current_log_number; ++it) {
|
||||
auto& log = *it;
|
||||
log.PrepareForSync();
|
||||
assert(!log.getting_synced);
|
||||
log.getting_synced = true;
|
||||
logs_to_sync.push_back(log.writer);
|
||||
}
|
||||
|
||||
@@ -1440,24 +1439,24 @@ Status DBImpl::MarkLogsSynced(uint64_t up_to, bool synced_dir) {
|
||||
VersionEdit synced_wals;
|
||||
for (auto it = logs_.begin(); it != logs_.end() && it->number <= up_to;) {
|
||||
auto& wal = *it;
|
||||
assert(wal.IsSyncing());
|
||||
|
||||
assert(wal.getting_synced);
|
||||
if (logs_.size() > 1) {
|
||||
if (immutable_db_options_.track_and_verify_wals_in_manifest &&
|
||||
wal.GetPreSyncSize() > 0) {
|
||||
synced_wals.AddWal(wal.number, WalMetadata(wal.GetPreSyncSize()));
|
||||
wal.writer->file()->GetFileSize() > 0) {
|
||||
synced_wals.AddWal(wal.number,
|
||||
WalMetadata(wal.writer->file()->GetFileSize()));
|
||||
}
|
||||
logs_to_free_.push_back(wal.ReleaseWriter());
|
||||
// To modify logs_ both mutex_ and log_write_mutex_ must be held
|
||||
InstrumentedMutexLock l(&log_write_mutex_);
|
||||
it = logs_.erase(it);
|
||||
} else {
|
||||
wal.FinishSync();
|
||||
wal.getting_synced = false;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
assert(logs_.empty() || logs_[0].number > up_to ||
|
||||
(logs_.size() == 1 && !logs_[0].IsSyncing()));
|
||||
(logs_.size() == 1 && !logs_[0].getting_synced));
|
||||
|
||||
Status s;
|
||||
if (synced_wals.IsWalAddition()) {
|
||||
@@ -1477,7 +1476,8 @@ void DBImpl::MarkLogsNotSynced(uint64_t up_to) {
|
||||
for (auto it = logs_.begin(); it != logs_.end() && it->number <= up_to;
|
||||
++it) {
|
||||
auto& wal = *it;
|
||||
wal.FinishSync();
|
||||
assert(wal.getting_synced);
|
||||
wal.getting_synced = false;
|
||||
}
|
||||
log_sync_cv_.SignalAll();
|
||||
}
|
||||
@@ -1722,6 +1722,17 @@ Status DBImpl::Get(const ReadOptions& read_options,
|
||||
return s;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class GetWithTimestampReadCallback : public ReadCallback {
|
||||
public:
|
||||
explicit GetWithTimestampReadCallback(SequenceNumber seq)
|
||||
: ReadCallback(seq) {}
|
||||
bool IsVisibleFullCheck(SequenceNumber seq) override {
|
||||
return seq <= max_visible_seq_;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
Status DBImpl::GetImpl(const ReadOptions& read_options, const Slice& key,
|
||||
GetImplOptions& get_impl_options) {
|
||||
assert(get_impl_options.value != nullptr ||
|
||||
@@ -2578,8 +2589,7 @@ Status DBImpl::MultiGetImpl(
|
||||
? MultiGetContext::MAX_BATCH_SIZE
|
||||
: keys_left;
|
||||
MultiGetContext ctx(sorted_keys, start_key + num_keys - keys_left,
|
||||
batch_size, snapshot, read_options, GetFileSystem(),
|
||||
stats_);
|
||||
batch_size, snapshot, read_options);
|
||||
MultiGetRange range = ctx.GetMultiGetRange();
|
||||
range.AddValueSize(curr_value_size);
|
||||
bool lookup_current = false;
|
||||
@@ -3345,7 +3355,7 @@ bool DBImpl::GetProperty(ColumnFamilyHandle* column_family,
|
||||
bool ret_value =
|
||||
GetIntPropertyInternal(cfd, *property_info, false, &int_value);
|
||||
if (ret_value) {
|
||||
*value = std::to_string(int_value);
|
||||
*value = ToString(int_value);
|
||||
}
|
||||
return ret_value;
|
||||
} else if (property_info->handle_string) {
|
||||
@@ -3980,8 +3990,8 @@ Status DBImpl::CheckConsistency() {
|
||||
} else if (fsize != md.size) {
|
||||
corruption_messages += "Sst file size mismatch: " + file_path +
|
||||
". Size recorded in manifest " +
|
||||
std::to_string(md.size) + ", actual size " +
|
||||
std::to_string(fsize) + "\n";
|
||||
ToString(md.size) + ", actual size " +
|
||||
ToString(fsize) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5113,8 +5123,8 @@ Status DBImpl::VerifyChecksumInternal(const ReadOptions& read_options,
|
||||
fmeta->file_checksum_func_name, fname,
|
||||
read_options);
|
||||
} else {
|
||||
s = ROCKSDB_NAMESPACE::VerifySstFileChecksum(
|
||||
opts, file_options_, read_options, fname, fd.largest_seqno);
|
||||
s = ROCKSDB_NAMESPACE::VerifySstFileChecksum(opts, file_options_,
|
||||
read_options, fname);
|
||||
}
|
||||
RecordTick(stats_, VERIFY_CHECKSUM_READ_BYTES,
|
||||
IOSTATS(bytes_read) - prev_bytes_read);
|
||||
@@ -5328,7 +5338,7 @@ Status DBImpl::ReserveFileNumbersBeforeIngestion(
|
||||
|
||||
Status DBImpl::GetCreationTimeOfOldestFile(uint64_t* creation_time) {
|
||||
if (mutable_db_options_.max_open_files == -1) {
|
||||
uint64_t oldest_time = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t oldest_time = port::kMaxUint64;
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
if (!cfd->IsDropped()) {
|
||||
uint64_t ctime;
|
||||
|
||||
+7
-95
@@ -1240,39 +1240,6 @@ class DBImpl : public DB {
|
||||
|
||||
std::atomic<bool> shutting_down_;
|
||||
|
||||
// RecoveryContext struct stores the context about version edits along
|
||||
// with corresponding column_family_data and column_family_options.
|
||||
class RecoveryContext {
|
||||
public:
|
||||
~RecoveryContext() {
|
||||
for (auto& edit_list : edit_lists_) {
|
||||
for (auto* edit : edit_list) {
|
||||
delete edit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateVersionEdits(ColumnFamilyData* cfd, const VersionEdit& edit) {
|
||||
assert(cfd != nullptr);
|
||||
if (map_.find(cfd->GetID()) == map_.end()) {
|
||||
uint32_t size = static_cast<uint32_t>(map_.size());
|
||||
map_.emplace(cfd->GetID(), size);
|
||||
cfds_.emplace_back(cfd);
|
||||
mutable_cf_opts_.emplace_back(cfd->GetLatestMutableCFOptions());
|
||||
edit_lists_.emplace_back(autovector<VersionEdit*>());
|
||||
}
|
||||
uint32_t i = map_[cfd->GetID()];
|
||||
edit_lists_[i].emplace_back(new VersionEdit(edit));
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> map_; // cf_id to index;
|
||||
autovector<ColumnFamilyData*> cfds_;
|
||||
autovector<const MutableCFOptions*> mutable_cf_opts_;
|
||||
autovector<autovector<VersionEdit*>> edit_lists_;
|
||||
// files_to_delete_ contains sst files
|
||||
std::unordered_set<std::string> files_to_delete_;
|
||||
};
|
||||
|
||||
// Except in DB::Open(), WriteOptionsFile can only be called when:
|
||||
// Persist options to options file.
|
||||
// If need_mutex_lock = false, the method will lock DB mutex.
|
||||
@@ -1389,19 +1356,16 @@ class DBImpl : public DB {
|
||||
// be made to the descriptor are added to *edit.
|
||||
// recovered_seq is set to less than kMaxSequenceNumber if the log's tail is
|
||||
// skipped.
|
||||
// recovery_ctx stores the context about version edits and all those
|
||||
// edits are persisted to new Manifest after successfully syncing the new WAL.
|
||||
virtual Status Recover(
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families,
|
||||
bool read_only = false, bool error_if_wal_file_exists = false,
|
||||
bool error_if_data_exists_in_wals = false,
|
||||
uint64_t* recovered_seq = nullptr,
|
||||
RecoveryContext* recovery_ctx = nullptr);
|
||||
uint64_t* recovered_seq = nullptr);
|
||||
|
||||
virtual bool OwnTablesAndLogs() const { return true; }
|
||||
|
||||
// Set DB identity file, and write DB ID to manifest if necessary.
|
||||
Status SetDBId(bool read_only, RecoveryContext* recovery_ctx);
|
||||
Status SetDBId(bool read_only);
|
||||
|
||||
// REQUIRES: db mutex held when calling this function, but the db mutex can
|
||||
// be released and re-acquired. Db mutex will be held when the function
|
||||
@@ -1410,15 +1374,12 @@ class DBImpl : public DB {
|
||||
// not referenced in the MANIFEST (e.g.
|
||||
// 1. It's best effort recovery;
|
||||
// 2. The VersionEdits referencing the SST files are appended to
|
||||
// RecoveryContext, DB crashes when syncing the MANIFEST, the VersionEdits are
|
||||
// MANIFEST, DB crashes when syncing the MANIFEST, the VersionEdits are
|
||||
// still not synced to MANIFEST during recovery.)
|
||||
// It stores the SST files to be deleted in RecoveryContext. In the
|
||||
// We delete these SST files. In the
|
||||
// meantime, we find out the largest file number present in the paths, and
|
||||
// bump up the version set's next_file_number_ to be 1 + largest_file_number.
|
||||
// recovery_ctx stores the context about version edits and files to be
|
||||
// deleted. All those edits are persisted to new Manifest after successfully
|
||||
// syncing the new WAL.
|
||||
Status DeleteUnreferencedSstFiles(RecoveryContext* recovery_ctx);
|
||||
Status DeleteUnreferencedSstFiles();
|
||||
|
||||
// SetDbSessionId() should be called in the constuctor DBImpl()
|
||||
// to ensure that db_session_id_ gets updated every time the DB is opened
|
||||
@@ -1428,14 +1389,6 @@ class DBImpl : public DB {
|
||||
Status FailIfTsSizesMismatch(const ColumnFamilyHandle* column_family,
|
||||
const Slice& ts) const;
|
||||
|
||||
// recovery_ctx stores the context about version edits and
|
||||
// LogAndApplyForRecovery persist all those edits to new Manifest after
|
||||
// successfully syncing new WAL.
|
||||
// LogAndApplyForRecovery should be called only once during recovery and it
|
||||
// should be called when RocksDB writes to a first new MANIFEST since this
|
||||
// recovery.
|
||||
Status LogAndApplyForRecovery(const RecoveryContext& recovery_ctx);
|
||||
|
||||
private:
|
||||
friend class DB;
|
||||
friend class ErrorHandler;
|
||||
@@ -1512,38 +1465,12 @@ class DBImpl : public DB {
|
||||
return s;
|
||||
}
|
||||
|
||||
bool IsSyncing() { return getting_synced; }
|
||||
|
||||
uint64_t GetPreSyncSize() {
|
||||
assert(getting_synced);
|
||||
return pre_sync_size;
|
||||
}
|
||||
|
||||
void PrepareForSync() {
|
||||
assert(!getting_synced);
|
||||
// Size is expected to be monotonically increasing.
|
||||
assert(writer->file()->GetFlushedSize() >= pre_sync_size);
|
||||
getting_synced = true;
|
||||
pre_sync_size = writer->file()->GetFlushedSize();
|
||||
}
|
||||
|
||||
void FinishSync() {
|
||||
assert(getting_synced);
|
||||
getting_synced = false;
|
||||
}
|
||||
|
||||
uint64_t number;
|
||||
// Visual Studio doesn't support deque's member to be noncopyable because
|
||||
// of a std::unique_ptr as a member.
|
||||
log::Writer* writer; // own
|
||||
|
||||
private:
|
||||
// true for some prefix of logs_
|
||||
bool getting_synced = false;
|
||||
// The size of the file before the sync happens. This amount is guaranteed
|
||||
// to be persisted even if appends happen during sync so it can be used for
|
||||
// tracking the synced size in MANIFEST.
|
||||
uint64_t pre_sync_size = 0;
|
||||
};
|
||||
|
||||
// PurgeFileInfo is a structure to hold information of files to be deleted in
|
||||
@@ -1718,8 +1645,7 @@ class DBImpl : public DB {
|
||||
// corrupted_log_found is set to true if we recover from a corrupted log file.
|
||||
Status RecoverLogFiles(const std::vector<uint64_t>& log_numbers,
|
||||
SequenceNumber* next_sequence, bool read_only,
|
||||
bool* corrupted_log_found,
|
||||
RecoveryContext* recovery_ctx);
|
||||
bool* corrupted_log_found);
|
||||
|
||||
// The following two methods are used to flush a memtable to
|
||||
// storage. The first one is used at database RecoveryTime (when the
|
||||
@@ -2048,11 +1974,6 @@ class DBImpl : public DB {
|
||||
IOStatus CreateWAL(uint64_t log_file_num, uint64_t recycle_log_number,
|
||||
size_t preallocate_block_size, log::Writer** new_log);
|
||||
|
||||
// Verify SST file unique id between Manifest and table properties to make
|
||||
// sure they're the same. Currently only used during DB open when
|
||||
// `verify_sst_unique_id_in_manifest = true`.
|
||||
Status VerifySstUniqueIdInManifest();
|
||||
|
||||
// Validate self-consistency of DB options
|
||||
static Status ValidateOptions(const DBOptions& db_options);
|
||||
// Validate self-consistency of DB options and its consistency with cf options
|
||||
@@ -2378,7 +2299,7 @@ class DBImpl : public DB {
|
||||
|
||||
static const int KEEP_LOG_FILE_NUM = 1000;
|
||||
// MSVC version 1800 still does not have constexpr for ::max()
|
||||
static const uint64_t kNoTimeOut = std::numeric_limits<uint64_t>::max();
|
||||
static const uint64_t kNoTimeOut = port::kMaxUint64;
|
||||
|
||||
std::string db_absolute_path_;
|
||||
|
||||
@@ -2474,15 +2395,6 @@ class DBImpl : public DB {
|
||||
std::unique_ptr<StallInterface> wbm_stall_;
|
||||
};
|
||||
|
||||
class GetWithTimestampReadCallback : public ReadCallback {
|
||||
public:
|
||||
explicit GetWithTimestampReadCallback(SequenceNumber seq)
|
||||
: ReadCallback(seq) {}
|
||||
bool IsVisibleFullCheck(SequenceNumber seq) override {
|
||||
return seq <= max_visible_seq_;
|
||||
}
|
||||
};
|
||||
|
||||
extern Options SanitizeOptions(const std::string& db, const Options& src,
|
||||
bool read_only = false);
|
||||
|
||||
|
||||
@@ -88,13 +88,14 @@ IOStatus DBImpl::SyncClosedLogs(JobContext* job_context) {
|
||||
autovector<log::Writer*, 1> logs_to_sync;
|
||||
uint64_t current_log_number = logfile_number_;
|
||||
while (logs_.front().number < current_log_number &&
|
||||
logs_.front().IsSyncing()) {
|
||||
logs_.front().getting_synced) {
|
||||
log_sync_cv_.Wait();
|
||||
}
|
||||
for (auto it = logs_.begin();
|
||||
it != logs_.end() && it->number < current_log_number; ++it) {
|
||||
auto& log = *it;
|
||||
log.PrepareForSync();
|
||||
assert(!log.getting_synced);
|
||||
log.getting_synced = true;
|
||||
logs_to_sync.push_back(log.writer);
|
||||
}
|
||||
|
||||
@@ -187,7 +188,7 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
// a memtable without knowing such snapshot(s).
|
||||
uint64_t max_memtable_id = needs_to_sync_closed_wals
|
||||
? cfd->imm()->GetLatestMemTableID()
|
||||
: std::numeric_limits<uint64_t>::max();
|
||||
: port::kMaxUint64;
|
||||
|
||||
// If needs_to_sync_closed_wals is false, then the flush job will pick ALL
|
||||
// existing memtables of the column family when PickMemTable() is called
|
||||
@@ -1040,8 +1041,7 @@ Status DBImpl::CompactRangeInternal(const CompactRangeOptions& options,
|
||||
}
|
||||
s = RunManualCompaction(cfd, ColumnFamilyData::kCompactAllLevels,
|
||||
final_output_level, options, begin, end, exclusive,
|
||||
false, std::numeric_limits<uint64_t>::max(),
|
||||
trim_ts);
|
||||
false, port::kMaxUint64, trim_ts);
|
||||
} else {
|
||||
int first_overlapped_level = kInvalidLevel;
|
||||
int max_overlapped_level = kInvalidLevel;
|
||||
@@ -1078,7 +1078,7 @@ Status DBImpl::CompactRangeInternal(const CompactRangeOptions& options,
|
||||
if (s.ok() && first_overlapped_level != kInvalidLevel) {
|
||||
// max_file_num_to_ignore can be used to filter out newly created SST
|
||||
// files, useful for bottom level compaction in a manual compaction
|
||||
uint64_t max_file_num_to_ignore = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t max_file_num_to_ignore = port::kMaxUint64;
|
||||
uint64_t next_file_number = versions_->current_next_file_number();
|
||||
final_output_level = max_overlapped_level;
|
||||
int output_level;
|
||||
@@ -1650,8 +1650,7 @@ Status DBImpl::ReFitLevel(ColumnFamilyData* cfd, int level, int target_level) {
|
||||
f->smallest, f->largest, f->fd.smallest_seqno, f->fd.largest_seqno,
|
||||
f->marked_for_compaction, f->temperature, f->oldest_blob_file_number,
|
||||
f->oldest_ancester_time, f->file_creation_time, f->file_checksum,
|
||||
f->file_checksum_func_name, f->min_timestamp, f->max_timestamp,
|
||||
f->unique_id);
|
||||
f->file_checksum_func_name, f->min_timestamp, f->max_timestamp);
|
||||
}
|
||||
ROCKS_LOG_DEBUG(immutable_db_options_.info_log,
|
||||
"[%s] Apply version edit:\n%s", cfd->GetName().c_str(),
|
||||
@@ -1856,12 +1855,11 @@ Status DBImpl::RunManualCompaction(
|
||||
}
|
||||
}
|
||||
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log,
|
||||
"[%s] Manual compaction starting", cfd->GetName().c_str());
|
||||
|
||||
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL,
|
||||
immutable_db_options_.info_log.get());
|
||||
|
||||
ROCKS_LOG_BUFFER(&log_buffer, "[%s] Manual compaction starting",
|
||||
cfd->GetName().c_str());
|
||||
|
||||
// We don't check bg_error_ here, because if we get the error in compaction,
|
||||
// the compaction will set manual.status to bg_error_ and set manual.done to
|
||||
// true.
|
||||
@@ -2015,7 +2013,7 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
|
||||
// be created and scheduled, status::OK() will be returned.
|
||||
s = SwitchMemtable(cfd, &context);
|
||||
}
|
||||
const uint64_t flush_memtable_id = std::numeric_limits<uint64_t>::max();
|
||||
const uint64_t flush_memtable_id = port::kMaxUint64;
|
||||
if (s.ok()) {
|
||||
if (cfd->imm()->NumNotFlushed() != 0 || !cfd->mem()->IsEmpty() ||
|
||||
!cached_recoverable_state_empty_.load()) {
|
||||
@@ -3277,7 +3275,7 @@ Status DBImpl::BackgroundCompaction(bool* made_progress,
|
||||
f->fd.largest_seqno, f->marked_for_compaction, f->temperature,
|
||||
f->oldest_blob_file_number, f->oldest_ancester_time,
|
||||
f->file_creation_time, f->file_checksum, f->file_checksum_func_name,
|
||||
f->min_timestamp, f->max_timestamp, f->unique_id);
|
||||
f->min_timestamp, f->max_timestamp);
|
||||
|
||||
ROCKS_LOG_BUFFER(
|
||||
log_buffer,
|
||||
|
||||
@@ -118,11 +118,10 @@ Status DBImpl::TEST_CompactRange(int level, const Slice* begin,
|
||||
cfd->ioptions()->compaction_style == kCompactionStyleFIFO)
|
||||
? level
|
||||
: level + 1;
|
||||
return RunManualCompaction(
|
||||
cfd, level, output_level, CompactRangeOptions(), begin, end, true,
|
||||
disallow_trivial_move,
|
||||
std::numeric_limits<uint64_t>::max() /*max_file_num_to_ignore*/,
|
||||
"" /*trim_ts*/);
|
||||
return RunManualCompaction(cfd, level, output_level, CompactRangeOptions(),
|
||||
begin, end, true, disallow_trivial_move,
|
||||
port::kMaxUint64 /*max_file_num_to_ignore*/,
|
||||
"" /*trim_ts*/);
|
||||
}
|
||||
|
||||
Status DBImpl::TEST_SwitchMemtable(ColumnFamilyData* cfd) {
|
||||
|
||||
@@ -137,7 +137,7 @@ Status DBImpl::PromoteL0(ColumnFamilyHandle* column_family, int target_level) {
|
||||
f->fd.largest_seqno, f->marked_for_compaction, f->temperature,
|
||||
f->oldest_blob_file_number, f->oldest_ancester_time,
|
||||
f->file_creation_time, f->file_checksum, f->file_checksum_func_name,
|
||||
f->min_timestamp, f->max_timestamp, f->unique_id);
|
||||
f->min_timestamp, f->max_timestamp);
|
||||
}
|
||||
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
|
||||
+28
-29
@@ -280,7 +280,7 @@ void DBImpl::FindObsoleteFiles(JobContext* job_context, bool force,
|
||||
}
|
||||
while (!logs_.empty() && logs_.front().number < min_log_number) {
|
||||
auto& log = logs_.front();
|
||||
if (log.IsSyncing()) {
|
||||
if (log.getting_synced) {
|
||||
log_sync_cv_.Wait();
|
||||
// logs_ could have changed while we were waiting.
|
||||
continue;
|
||||
@@ -761,7 +761,7 @@ uint64_t PrecomputeMinLogNumberToKeepNon2PC(
|
||||
assert(!cfds_to_flush.empty());
|
||||
assert(cfds_to_flush.size() == edit_lists.size());
|
||||
|
||||
uint64_t min_log_number_to_keep = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t min_log_number_to_keep = port::kMaxUint64;
|
||||
for (const auto& edit_list : edit_lists) {
|
||||
uint64_t log = 0;
|
||||
for (const auto& e : edit_list) {
|
||||
@@ -773,7 +773,7 @@ uint64_t PrecomputeMinLogNumberToKeepNon2PC(
|
||||
min_log_number_to_keep = std::min(min_log_number_to_keep, log);
|
||||
}
|
||||
}
|
||||
if (min_log_number_to_keep == std::numeric_limits<uint64_t>::max()) {
|
||||
if (min_log_number_to_keep == port::kMaxUint64) {
|
||||
min_log_number_to_keep = cfds_to_flush[0]->GetLogNumber();
|
||||
for (size_t i = 1; i < cfds_to_flush.size(); i++) {
|
||||
min_log_number_to_keep =
|
||||
@@ -863,7 +863,7 @@ uint64_t PrecomputeMinLogNumberToKeep2PC(
|
||||
return min_log_number_to_keep;
|
||||
}
|
||||
|
||||
Status DBImpl::SetDBId(bool read_only, RecoveryContext* recovery_ctx) {
|
||||
Status DBImpl::SetDBId(bool read_only) {
|
||||
Status s;
|
||||
// Happens when immutable_db_options_.write_dbid_to_manifest is set to true
|
||||
// the very first time.
|
||||
@@ -889,30 +889,15 @@ Status DBImpl::SetDBId(bool read_only, RecoveryContext* recovery_ctx) {
|
||||
return s;
|
||||
}
|
||||
s = GetDbIdentityFromIdentityFile(&db_id_);
|
||||
if (s.ok() && db_id_.empty()) {
|
||||
// Patch version of same fix as
|
||||
// https://github.com/facebook/rocksdb/pull/10173
|
||||
// (less intrusive, more obviously low-touch)
|
||||
if (read_only) {
|
||||
db_id_ = env_->GenerateUniqueId();
|
||||
return Status::OK();
|
||||
} else {
|
||||
s = SetIdentityFile(env_, dbname_);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
s = GetDbIdentityFromIdentityFile(&db_id_);
|
||||
}
|
||||
if (immutable_db_options_.write_dbid_to_manifest && s.ok()) {
|
||||
assert(!read_only);
|
||||
assert(recovery_ctx != nullptr);
|
||||
assert(versions_->GetColumnFamilySet() != nullptr);
|
||||
VersionEdit edit;
|
||||
edit.SetDBId(db_id_);
|
||||
Options options;
|
||||
MutableCFOptions mutable_cf_options(options);
|
||||
versions_->db_id_ = db_id_;
|
||||
recovery_ctx->UpdateVersionEdits(
|
||||
versions_->GetColumnFamilySet()->GetDefault(), edit);
|
||||
s = versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(),
|
||||
mutable_cf_options, &edit, &mutex_, nullptr,
|
||||
/* new_descriptor_log */ false);
|
||||
}
|
||||
} else if (!read_only) {
|
||||
s = SetIdentityFile(env_, dbname_, db_id_);
|
||||
@@ -920,7 +905,7 @@ Status DBImpl::SetDBId(bool read_only, RecoveryContext* recovery_ctx) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::DeleteUnreferencedSstFiles(RecoveryContext* recovery_ctx) {
|
||||
Status DBImpl::DeleteUnreferencedSstFiles() {
|
||||
mutex_.AssertHeld();
|
||||
std::vector<std::string> paths;
|
||||
paths.push_back(NormalizePath(dbname_ + std::string(1, kFilePathSeparator)));
|
||||
@@ -940,6 +925,7 @@ Status DBImpl::DeleteUnreferencedSstFiles(RecoveryContext* recovery_ctx) {
|
||||
|
||||
uint64_t next_file_number = versions_->current_next_file_number();
|
||||
uint64_t largest_file_number = next_file_number;
|
||||
std::set<std::string> files_to_delete;
|
||||
Status s;
|
||||
for (const auto& path : paths) {
|
||||
std::vector<std::string> files;
|
||||
@@ -957,9 +943,8 @@ Status DBImpl::DeleteUnreferencedSstFiles(RecoveryContext* recovery_ctx) {
|
||||
const std::string normalized_fpath = path + fname;
|
||||
largest_file_number = std::max(largest_file_number, number);
|
||||
if (type == kTableFile && number >= next_file_number &&
|
||||
recovery_ctx->files_to_delete_.find(normalized_fpath) ==
|
||||
recovery_ctx->files_to_delete_.end()) {
|
||||
recovery_ctx->files_to_delete_.emplace(normalized_fpath);
|
||||
files_to_delete.find(normalized_fpath) == files_to_delete.end()) {
|
||||
files_to_delete.insert(normalized_fpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -976,7 +961,21 @@ Status DBImpl::DeleteUnreferencedSstFiles(RecoveryContext* recovery_ctx) {
|
||||
assert(versions_->GetColumnFamilySet());
|
||||
ColumnFamilyData* default_cfd = versions_->GetColumnFamilySet()->GetDefault();
|
||||
assert(default_cfd);
|
||||
recovery_ctx->UpdateVersionEdits(default_cfd, edit);
|
||||
s = versions_->LogAndApply(
|
||||
default_cfd, *default_cfd->GetLatestMutableCFOptions(), &edit, &mutex_,
|
||||
directories_.GetDbDir(), /*new_descriptor_log*/ false);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
mutex_.Unlock();
|
||||
for (const auto& fname : files_to_delete) {
|
||||
s = env_->DeleteFile(fname);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_.Lock();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
+75
-134
@@ -399,7 +399,7 @@ IOStatus Directories::SetDirectories(FileSystem* fs, const std::string& dbname,
|
||||
Status DBImpl::Recover(
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families, bool read_only,
|
||||
bool error_if_wal_file_exists, bool error_if_data_exists_in_wals,
|
||||
uint64_t* recovered_seq, RecoveryContext* recovery_ctx) {
|
||||
uint64_t* recovered_seq) {
|
||||
mutex_.AssertHeld();
|
||||
|
||||
bool is_new_db = false;
|
||||
@@ -518,15 +518,9 @@ Status DBImpl::Recover(
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
if (immutable_db_options_.verify_sst_unique_id_in_manifest) {
|
||||
s = VerifySstUniqueIdInManifest();
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
s = SetDBId(read_only, recovery_ctx);
|
||||
s = SetDBId(read_only);
|
||||
if (s.ok() && !read_only) {
|
||||
s = DeleteUnreferencedSstFiles(recovery_ctx);
|
||||
s = DeleteUnreferencedSstFiles();
|
||||
}
|
||||
|
||||
if (immutable_db_options_.paranoid_checks && s.ok()) {
|
||||
@@ -541,6 +535,10 @@ Status DBImpl::Recover(
|
||||
}
|
||||
}
|
||||
}
|
||||
// DB mutex is already held
|
||||
if (s.ok() && immutable_db_options_.persist_stats_to_disk) {
|
||||
s = InitPersistStatsColumnFamily();
|
||||
}
|
||||
|
||||
std::vector<std::string> files_in_wal_dir;
|
||||
if (s.ok()) {
|
||||
@@ -610,10 +608,7 @@ Status DBImpl::Recover(
|
||||
WalNumber max_wal_number =
|
||||
versions_->GetWalSet().GetWals().rbegin()->first;
|
||||
edit.DeleteWalsBefore(max_wal_number + 1);
|
||||
assert(recovery_ctx != nullptr);
|
||||
assert(versions_->GetColumnFamilySet() != nullptr);
|
||||
recovery_ctx->UpdateVersionEdits(
|
||||
versions_->GetColumnFamilySet()->GetDefault(), edit);
|
||||
s = versions_->LogAndApplyToDefaultColumnFamily(&edit, &mutex_);
|
||||
}
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
@@ -649,8 +644,8 @@ Status DBImpl::Recover(
|
||||
std::sort(wals.begin(), wals.end());
|
||||
|
||||
bool corrupted_wal_found = false;
|
||||
s = RecoverLogFiles(wals, &next_sequence, read_only, &corrupted_wal_found,
|
||||
recovery_ctx);
|
||||
s = RecoverLogFiles(wals, &next_sequence, read_only,
|
||||
&corrupted_wal_found);
|
||||
if (corrupted_wal_found && recovered_seq != nullptr) {
|
||||
*recovered_seq = next_sequence;
|
||||
}
|
||||
@@ -703,25 +698,6 @@ Status DBImpl::Recover(
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::VerifySstUniqueIdInManifest() {
|
||||
mutex_.AssertHeld();
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"Verifying SST unique id between MANIFEST and SST file table properties");
|
||||
Status status;
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
if (!cfd->IsDropped()) {
|
||||
auto version = cfd->current();
|
||||
version->Ref();
|
||||
mutex_.Unlock();
|
||||
status = version->VerifySstUniqueIds();
|
||||
mutex_.Lock();
|
||||
version->Unref();
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
Status DBImpl::PersistentStatsProcessFormatVersion() {
|
||||
mutex_.AssertHeld();
|
||||
Status s;
|
||||
@@ -784,11 +760,11 @@ Status DBImpl::PersistentStatsProcessFormatVersion() {
|
||||
WriteBatch batch;
|
||||
if (s.ok()) {
|
||||
s = batch.Put(persist_stats_cf_handle_, kFormatVersionKeyString,
|
||||
std::to_string(kStatsCFCurrentFormatVersion));
|
||||
ToString(kStatsCFCurrentFormatVersion));
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = batch.Put(persist_stats_cf_handle_, kCompatibleVersionKeyString,
|
||||
std::to_string(kStatsCFCompatibleFormatVersion));
|
||||
ToString(kStatsCFCompatibleFormatVersion));
|
||||
}
|
||||
if (s.ok()) {
|
||||
WriteOptions wo;
|
||||
@@ -829,30 +805,10 @@ Status DBImpl::InitPersistStatsColumnFamily() {
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::LogAndApplyForRecovery(const RecoveryContext& recovery_ctx) {
|
||||
mutex_.AssertHeld();
|
||||
assert(versions_->descriptor_log_ == nullptr);
|
||||
Status s = versions_->LogAndApply(
|
||||
recovery_ctx.cfds_, recovery_ctx.mutable_cf_opts_,
|
||||
recovery_ctx.edit_lists_, &mutex_, directories_.GetDbDir());
|
||||
if (s.ok() && !(recovery_ctx.files_to_delete_.empty())) {
|
||||
mutex_.Unlock();
|
||||
for (const auto& fname : recovery_ctx.files_to_delete_) {
|
||||
s = env_->DeleteFile(fname);
|
||||
if (!s.ok()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_.Lock();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// REQUIRES: wal_numbers are sorted in ascending order
|
||||
Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& wal_numbers,
|
||||
SequenceNumber* next_sequence, bool read_only,
|
||||
bool* corrupted_wal_found,
|
||||
RecoveryContext* recovery_ctx) {
|
||||
bool* corrupted_wal_found) {
|
||||
struct LogReporter : public log::Reader::Reporter {
|
||||
Env* env;
|
||||
Logger* info_log;
|
||||
@@ -991,6 +947,7 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& wal_numbers,
|
||||
// Read all the records and add to a memtable
|
||||
std::string scratch;
|
||||
Slice record;
|
||||
WriteBatch batch;
|
||||
|
||||
TEST_SYNC_POINT_CALLBACK("DBImpl::RecoverLogFiles:BeforeReadWal",
|
||||
/*arg=*/nullptr);
|
||||
@@ -1004,15 +961,10 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& wal_numbers,
|
||||
continue;
|
||||
}
|
||||
|
||||
// We create a new batch and initialize with a valid prot_info_ to store
|
||||
// the data checksums
|
||||
WriteBatch batch(0, 0, 8, 0);
|
||||
|
||||
status = WriteBatchInternal::SetContents(&batch, record);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
SequenceNumber sequence = WriteBatchInternal::Sequence(&batch);
|
||||
|
||||
if (immutable_db_options_.wal_recovery_mode ==
|
||||
@@ -1310,36 +1262,44 @@ Status DBImpl::RecoverLogFiles(const std::vector<uint64_t>& wal_numbers,
|
||||
// VersionSet::next_file_number_ always to be strictly greater than any
|
||||
// log number
|
||||
versions_->MarkFileNumberUsed(max_wal_number + 1);
|
||||
assert(recovery_ctx != nullptr);
|
||||
|
||||
autovector<ColumnFamilyData*> cfds;
|
||||
autovector<const MutableCFOptions*> cf_opts;
|
||||
autovector<autovector<VersionEdit*>> edit_lists;
|
||||
for (auto* cfd : *versions_->GetColumnFamilySet()) {
|
||||
cfds.push_back(cfd);
|
||||
cf_opts.push_back(cfd->GetLatestMutableCFOptions());
|
||||
auto iter = version_edits.find(cfd->GetID());
|
||||
assert(iter != version_edits.end());
|
||||
recovery_ctx->UpdateVersionEdits(cfd, iter->second);
|
||||
edit_lists.push_back({&iter->second});
|
||||
}
|
||||
|
||||
std::unique_ptr<VersionEdit> wal_deletion;
|
||||
if (flushed) {
|
||||
VersionEdit wal_deletion;
|
||||
wal_deletion = std::make_unique<VersionEdit>();
|
||||
if (immutable_db_options_.track_and_verify_wals_in_manifest) {
|
||||
wal_deletion.DeleteWalsBefore(max_wal_number + 1);
|
||||
wal_deletion->DeleteWalsBefore(max_wal_number + 1);
|
||||
}
|
||||
if (!allow_2pc()) {
|
||||
// In non-2pc mode, flushing the memtables of the column families
|
||||
// means we can advance min_log_number_to_keep.
|
||||
wal_deletion.SetMinLogNumberToKeep(max_wal_number + 1);
|
||||
wal_deletion->SetMinLogNumberToKeep(max_wal_number + 1);
|
||||
}
|
||||
assert(versions_->GetColumnFamilySet() != nullptr);
|
||||
recovery_ctx->UpdateVersionEdits(
|
||||
versions_->GetColumnFamilySet()->GetDefault(), wal_deletion);
|
||||
edit_lists.back().push_back(wal_deletion.get());
|
||||
}
|
||||
|
||||
// write MANIFEST with update
|
||||
status = versions_->LogAndApply(cfds, cf_opts, edit_lists, &mutex_,
|
||||
directories_.GetDbDir(),
|
||||
/*new_descriptor_log=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
if (status.ok()) {
|
||||
if (data_seen && !flushed) {
|
||||
status = RestoreAliveLogFiles(wal_numbers);
|
||||
} else if (!wal_numbers.empty()) { // If there's no data in the WAL, or we
|
||||
// flushed all the data, still
|
||||
} else {
|
||||
// If there's no data in the WAL, or we flushed all the data, still
|
||||
// truncate the log file. If the process goes into a crash loop before
|
||||
// the file is deleted, the preallocated space will never get freed.
|
||||
const bool truncate = !read_only;
|
||||
@@ -1362,7 +1322,6 @@ Status DBImpl::GetLogSizeAndMaybeTruncate(uint64_t wal_number, bool truncate,
|
||||
Status s;
|
||||
// This gets the appear size of the wals, not including preallocated space.
|
||||
s = env_->GetFileSize(fname, &log.size);
|
||||
TEST_SYNC_POINT_CALLBACK("DBImpl::GetLogSizeAndMaybeTruncate:0", /*arg=*/&s);
|
||||
if (s.ok() && truncate) {
|
||||
std::unique_ptr<FSWritableFile> last_log;
|
||||
Status truncate_status = fs_->ReopenWritableFile(
|
||||
@@ -1534,14 +1493,13 @@ Status DBImpl::WriteLevel0TableForRecovery(int job_id, ColumnFamilyData* cfd,
|
||||
constexpr int level = 0;
|
||||
|
||||
if (s.ok() && has_output) {
|
||||
edit->AddFile(level, meta.fd.GetNumber(), meta.fd.GetPathId(),
|
||||
meta.fd.GetFileSize(), meta.smallest, meta.largest,
|
||||
meta.fd.smallest_seqno, meta.fd.largest_seqno,
|
||||
meta.marked_for_compaction, meta.temperature,
|
||||
meta.oldest_blob_file_number, meta.oldest_ancester_time,
|
||||
meta.file_creation_time, meta.file_checksum,
|
||||
meta.file_checksum_func_name, meta.min_timestamp,
|
||||
meta.max_timestamp, meta.unique_id);
|
||||
edit->AddFile(
|
||||
level, meta.fd.GetNumber(), meta.fd.GetPathId(), meta.fd.GetFileSize(),
|
||||
meta.smallest, meta.largest, meta.fd.smallest_seqno,
|
||||
meta.fd.largest_seqno, meta.marked_for_compaction, meta.temperature,
|
||||
meta.oldest_blob_file_number, meta.oldest_ancester_time,
|
||||
meta.file_creation_time, meta.file_checksum,
|
||||
meta.file_checksum_func_name, meta.min_timestamp, meta.max_timestamp);
|
||||
|
||||
for (const auto& blob : blob_file_additions) {
|
||||
edit->AddBlobFile(blob);
|
||||
@@ -1735,7 +1693,6 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
}
|
||||
|
||||
*dbptr = nullptr;
|
||||
assert(handles);
|
||||
handles->clear();
|
||||
|
||||
size_t max_write_buffer_size = 0;
|
||||
@@ -1778,13 +1735,11 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
}
|
||||
|
||||
impl->wal_in_db_path_ = impl->immutable_db_options_.IsWalDirSameAsDBPath();
|
||||
RecoveryContext recovery_ctx;
|
||||
impl->mutex_.Lock();
|
||||
|
||||
impl->mutex_.Lock();
|
||||
// Handles create_if_missing, error_if_exists
|
||||
uint64_t recovered_seq(kMaxSequenceNumber);
|
||||
s = impl->Recover(column_families, false, false, false, &recovered_seq,
|
||||
&recovery_ctx);
|
||||
s = impl->Recover(column_families, false, false, false, &recovered_seq);
|
||||
if (s.ok()) {
|
||||
uint64_t new_log_number = impl->versions_->NewFileNumber();
|
||||
log::Writer* new_log = nullptr;
|
||||
@@ -1801,6 +1756,40 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
// set column family handles
|
||||
for (auto cf : column_families) {
|
||||
auto cfd =
|
||||
impl->versions_->GetColumnFamilySet()->GetColumnFamily(cf.name);
|
||||
if (cfd != nullptr) {
|
||||
handles->push_back(
|
||||
new ColumnFamilyHandleImpl(cfd, impl, &impl->mutex_));
|
||||
impl->NewThreadStatusCfInfo(cfd);
|
||||
} else {
|
||||
if (db_options.create_missing_column_families) {
|
||||
// missing column family, create it
|
||||
ColumnFamilyHandle* handle;
|
||||
impl->mutex_.Unlock();
|
||||
s = impl->CreateColumnFamily(cf.options, cf.name, &handle);
|
||||
impl->mutex_.Lock();
|
||||
if (s.ok()) {
|
||||
handles->push_back(handle);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s = Status::InvalidArgument("Column family not found", cf.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.ok()) {
|
||||
SuperVersionContext sv_context(/* create_superversion */ true);
|
||||
for (auto cfd : *impl->versions_->GetColumnFamilySet()) {
|
||||
impl->InstallSuperVersionAndScheduleWork(
|
||||
cfd, &sv_context, *cfd->GetLatestMutableCFOptions());
|
||||
}
|
||||
sv_context.Clean();
|
||||
if (impl->two_write_queues_) {
|
||||
impl->log_write_mutex_.Lock();
|
||||
}
|
||||
@@ -1832,7 +1821,6 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
if (s.ok()) {
|
||||
// Need to fsync, otherwise it might get lost after a power reset.
|
||||
s = impl->FlushWAL(false);
|
||||
TEST_SYNC_POINT_CALLBACK("DBImpl::Open::BeforeSyncWAL", /*arg=*/&s);
|
||||
if (s.ok()) {
|
||||
s = log_writer->file()->Sync(impl->immutable_db_options_.use_fsync);
|
||||
}
|
||||
@@ -1840,53 +1828,6 @@ Status DBImpl::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.ok()) {
|
||||
s = impl->LogAndApplyForRecovery(recovery_ctx);
|
||||
}
|
||||
|
||||
if (s.ok() && impl->immutable_db_options_.persist_stats_to_disk) {
|
||||
impl->mutex_.AssertHeld();
|
||||
s = impl->InitPersistStatsColumnFamily();
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
// set column family handles
|
||||
for (auto cf : column_families) {
|
||||
auto cfd =
|
||||
impl->versions_->GetColumnFamilySet()->GetColumnFamily(cf.name);
|
||||
if (cfd != nullptr) {
|
||||
handles->push_back(
|
||||
new ColumnFamilyHandleImpl(cfd, impl, &impl->mutex_));
|
||||
impl->NewThreadStatusCfInfo(cfd);
|
||||
} else {
|
||||
if (db_options.create_missing_column_families) {
|
||||
// missing column family, create it
|
||||
ColumnFamilyHandle* handle = nullptr;
|
||||
impl->mutex_.Unlock();
|
||||
s = impl->CreateColumnFamily(cf.options, cf.name, &handle);
|
||||
impl->mutex_.Lock();
|
||||
if (s.ok()) {
|
||||
handles->push_back(handle);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s = Status::InvalidArgument("Column family not found", cf.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
SuperVersionContext sv_context(/* create_superversion */ true);
|
||||
for (auto cfd : *impl->versions_->GetColumnFamilySet()) {
|
||||
impl->InstallSuperVersionAndScheduleWork(
|
||||
cfd, &sv_context, *cfd->GetLatestMutableCFOptions());
|
||||
}
|
||||
sv_context.Clean();
|
||||
}
|
||||
|
||||
if (s.ok() && impl->immutable_db_options_.persist_stats_to_disk) {
|
||||
// try to read format version
|
||||
s = impl->PersistentStatsProcessFormatVersion();
|
||||
|
||||
@@ -33,38 +33,20 @@ DBImplReadOnly::~DBImplReadOnly() {}
|
||||
Status DBImplReadOnly::Get(const ReadOptions& read_options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
PinnableSlice* pinnable_val) {
|
||||
return Get(read_options, column_family, key, pinnable_val,
|
||||
/*timestamp*/ nullptr);
|
||||
}
|
||||
|
||||
Status DBImplReadOnly::Get(const ReadOptions& read_options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
PinnableSlice* pinnable_val,
|
||||
std::string* timestamp) {
|
||||
assert(pinnable_val != nullptr);
|
||||
// TODO: stopwatch DB_GET needed?, perf timer needed?
|
||||
PERF_TIMER_GUARD(get_snapshot_time);
|
||||
|
||||
assert(column_family);
|
||||
if (read_options.timestamp) {
|
||||
const Status s =
|
||||
FailIfTsSizesMismatch(column_family, *(read_options.timestamp));
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
} else {
|
||||
const Status s = FailIfCfHasTs(column_family);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
const Comparator* ucmp = column_family->GetComparator();
|
||||
assert(ucmp);
|
||||
std::string* ts = ucmp->timestamp_size() > 0 ? timestamp : nullptr;
|
||||
if (ucmp->timestamp_size() || read_options.timestamp) {
|
||||
// TODO: support timestamp
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
Status s;
|
||||
SequenceNumber snapshot = versions_->LastSequence();
|
||||
GetWithTimestampReadCallback read_cb(snapshot);
|
||||
auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);
|
||||
auto cfd = cfh->cfd();
|
||||
if (tracer_) {
|
||||
@@ -76,23 +58,19 @@ Status DBImplReadOnly::Get(const ReadOptions& read_options,
|
||||
SuperVersion* super_version = cfd->GetSuperVersion();
|
||||
MergeContext merge_context;
|
||||
SequenceNumber max_covering_tombstone_seq = 0;
|
||||
LookupKey lkey(key, snapshot, read_options.timestamp);
|
||||
LookupKey lkey(key, snapshot);
|
||||
PERF_TIMER_STOP(get_snapshot_time);
|
||||
if (super_version->mem->Get(lkey, pinnable_val->GetSelf(), ts, &s,
|
||||
&merge_context, &max_covering_tombstone_seq,
|
||||
read_options, &read_cb)) {
|
||||
if (super_version->mem->Get(lkey, pinnable_val->GetSelf(),
|
||||
/*timestamp=*/nullptr, &s, &merge_context,
|
||||
&max_covering_tombstone_seq, read_options)) {
|
||||
pinnable_val->PinSelf();
|
||||
RecordTick(stats_, MEMTABLE_HIT);
|
||||
} else {
|
||||
PERF_TIMER_GUARD(get_from_output_files_time);
|
||||
PinnedIteratorsManager pinned_iters_mgr;
|
||||
super_version->current->Get(
|
||||
read_options, lkey, pinnable_val, ts, &s, &merge_context,
|
||||
&max_covering_tombstone_seq, &pinned_iters_mgr,
|
||||
/*value_found*/ nullptr,
|
||||
/*key_exists*/ nullptr, /*seq*/ nullptr, &read_cb,
|
||||
/*is_blob*/ nullptr,
|
||||
/*do_merge*/ true);
|
||||
super_version->current->Get(read_options, lkey, pinnable_val,
|
||||
/*timestamp=*/nullptr, &s, &merge_context,
|
||||
&max_covering_tombstone_seq, &pinned_iters_mgr);
|
||||
RecordTick(stats_, MEMTABLE_MISS);
|
||||
}
|
||||
RecordTick(stats_, NUMBER_KEYS_READ);
|
||||
@@ -106,17 +84,11 @@ Status DBImplReadOnly::Get(const ReadOptions& read_options,
|
||||
Iterator* DBImplReadOnly::NewIterator(const ReadOptions& read_options,
|
||||
ColumnFamilyHandle* column_family) {
|
||||
assert(column_family);
|
||||
if (read_options.timestamp) {
|
||||
const Status s =
|
||||
FailIfTsSizesMismatch(column_family, *(read_options.timestamp));
|
||||
if (!s.ok()) {
|
||||
return NewErrorIterator(s);
|
||||
}
|
||||
} else {
|
||||
const Status s = FailIfCfHasTs(column_family);
|
||||
if (!s.ok()) {
|
||||
return NewErrorIterator(s);
|
||||
}
|
||||
const Comparator* ucmp = column_family->GetComparator();
|
||||
assert(ucmp);
|
||||
if (ucmp->timestamp_size() || read_options.timestamp) {
|
||||
// TODO: support timestamp
|
||||
return NewErrorIterator(Status::NotSupported());
|
||||
}
|
||||
auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);
|
||||
auto cfd = cfh->cfd();
|
||||
@@ -146,19 +118,16 @@ Status DBImplReadOnly::NewIterators(
|
||||
const std::vector<ColumnFamilyHandle*>& column_families,
|
||||
std::vector<Iterator*>* iterators) {
|
||||
if (read_options.timestamp) {
|
||||
for (auto* cf : column_families) {
|
||||
assert(cf);
|
||||
const Status s = FailIfTsSizesMismatch(cf, *(read_options.timestamp));
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
// TODO: support timestamp
|
||||
return Status::NotSupported();
|
||||
} else {
|
||||
for (auto* cf : column_families) {
|
||||
assert(cf);
|
||||
const Status s = FailIfCfHasTs(cf);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
const Comparator* ucmp = cf->GetComparator();
|
||||
assert(ucmp);
|
||||
if (ucmp->timestamp_size()) {
|
||||
// TODO: support timestamp
|
||||
return Status::NotSupported();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,6 @@ class DBImplReadOnly : public DBImpl {
|
||||
virtual Status Get(const ReadOptions& options,
|
||||
ColumnFamilyHandle* column_family, const Slice& key,
|
||||
PinnableSlice* value) override;
|
||||
Status Get(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
||||
const Slice& key, PinnableSlice* value,
|
||||
std::string* timestamp) override;
|
||||
|
||||
// TODO: Implement ReadOnly MultiGet?
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@ DBImplSecondary::~DBImplSecondary() {}
|
||||
Status DBImplSecondary::Recover(
|
||||
const std::vector<ColumnFamilyDescriptor>& column_families,
|
||||
bool /*readonly*/, bool /*error_if_wal_file_exists*/,
|
||||
bool /*error_if_data_exists_in_wals*/, uint64_t*,
|
||||
RecoveryContext* /*recovery_ctx*/) {
|
||||
bool /*error_if_data_exists_in_wals*/, uint64_t*) {
|
||||
mutex_.AssertHeld();
|
||||
|
||||
JobContext job_context(0);
|
||||
@@ -248,16 +247,15 @@ Status DBImplSecondary::RecoverLogFiles(
|
||||
if (seq_of_batch <= seq) {
|
||||
continue;
|
||||
}
|
||||
auto curr_log_num = std::numeric_limits<uint64_t>::max();
|
||||
auto curr_log_num = port::kMaxUint64;
|
||||
if (cfd_to_current_log_.count(cfd) > 0) {
|
||||
curr_log_num = cfd_to_current_log_[cfd];
|
||||
}
|
||||
// If the active memtable contains records added by replaying an
|
||||
// earlier WAL, then we need to seal the memtable, add it to the
|
||||
// immutable memtable list and create a new active memtable.
|
||||
if (!cfd->mem()->IsEmpty() &&
|
||||
(curr_log_num == std::numeric_limits<uint64_t>::max() ||
|
||||
curr_log_num != log_number)) {
|
||||
if (!cfd->mem()->IsEmpty() && (curr_log_num == port::kMaxUint64 ||
|
||||
curr_log_num != log_number)) {
|
||||
const MutableCFOptions mutable_cf_options =
|
||||
*cfd->GetLatestMutableCFOptions();
|
||||
MemTable* new_mem =
|
||||
@@ -773,19 +771,12 @@ Status DBImplSecondary::CompactWithoutInstallation(
|
||||
|
||||
const int job_id = next_job_id_.fetch_add(1);
|
||||
|
||||
// use primary host's db_id for running the compaction, but db_session_id is
|
||||
// using the local one, which is to make sure the unique id is unique from
|
||||
// the remote compactors. Because the id is generated from db_id,
|
||||
// db_session_id and orig_file_number, unlike the local compaction, remote
|
||||
// compaction cannot guarantee the uniqueness of orig_file_number, the file
|
||||
// number is only assigned when compaction is done.
|
||||
CompactionServiceCompactionJob compaction_job(
|
||||
job_id, c.get(), immutable_db_options_, mutable_db_options_,
|
||||
file_options_for_compaction_, versions_.get(), &shutting_down_,
|
||||
&log_buffer, output_dir.get(), stats_, &mutex_, &error_handler_,
|
||||
input.snapshots, table_cache_, &event_logger_, dbname_, io_tracer_,
|
||||
options.canceled, input.db_id, db_session_id_, secondary_path_, input,
|
||||
result);
|
||||
options.canceled, db_id_, db_session_id_, secondary_path_, input, result);
|
||||
|
||||
mutex_.Unlock();
|
||||
s = compaction_job.Run();
|
||||
@@ -840,8 +831,6 @@ Status DB::OpenAndCompact(
|
||||
override_options.table_factory;
|
||||
compaction_input.column_family.options.sst_partitioner_factory =
|
||||
override_options.sst_partitioner_factory;
|
||||
compaction_input.column_family.options.table_properties_collector_factories =
|
||||
override_options.table_properties_collector_factories;
|
||||
compaction_input.db_options.listeners = override_options.listeners;
|
||||
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
|
||||
@@ -81,8 +81,8 @@ class DBImplSecondary : public DBImpl {
|
||||
// and log_readers_ to facilitate future operations.
|
||||
Status Recover(const std::vector<ColumnFamilyDescriptor>& column_families,
|
||||
bool read_only, bool error_if_wal_file_exists,
|
||||
bool error_if_data_exists_in_wals, uint64_t* = nullptr,
|
||||
RecoveryContext* recovery_ctx = nullptr) override;
|
||||
bool error_if_data_exists_in_wals,
|
||||
uint64_t* = nullptr) override;
|
||||
|
||||
// Implementations of the DB interface
|
||||
using DB::Get;
|
||||
|
||||
@@ -1105,16 +1105,17 @@ Status DBImpl::PreprocessWrite(const WriteOptions& write_options,
|
||||
// Note: there does not seem to be a reason to wait for parallel sync at
|
||||
// this early step but it is not important since parallel sync (SyncWAL) and
|
||||
// need_log_sync are usually not used together.
|
||||
while (logs_.front().IsSyncing()) {
|
||||
while (logs_.front().getting_synced) {
|
||||
log_sync_cv_.Wait();
|
||||
}
|
||||
for (auto& log : logs_) {
|
||||
assert(!log.getting_synced);
|
||||
// This is just to prevent the logs to be synced by a parallel SyncWAL
|
||||
// call. We will do the actual syncing later after we will write to the
|
||||
// WAL.
|
||||
// Note: there does not seem to be a reason to set this early before we
|
||||
// actually write to the WAL
|
||||
log.PrepareForSync();
|
||||
log.getting_synced = true;
|
||||
}
|
||||
} else {
|
||||
*need_log_sync = false;
|
||||
|
||||
+18
-26
@@ -35,12 +35,10 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
Header(options.info_log, "DB SUMMARY\n");
|
||||
Header(options.info_log, "DB Session ID: %s\n", session_id.c_str());
|
||||
|
||||
Status s;
|
||||
// Get files in dbname dir
|
||||
s = env->GetChildren(dbname, &files);
|
||||
if (!s.ok()) {
|
||||
Error(options.info_log, "Error when reading %s dir %s\n", dbname.c_str(),
|
||||
s.ToString().c_str());
|
||||
if (!env->GetChildren(dbname, &files).ok()) {
|
||||
Error(options.info_log,
|
||||
"Error when reading %s dir\n", dbname.c_str());
|
||||
}
|
||||
std::sort(files.begin(), files.end());
|
||||
for (const std::string& file : files) {
|
||||
@@ -55,27 +53,24 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
Header(options.info_log, "IDENTITY file: %s\n", file.c_str());
|
||||
break;
|
||||
case kDescriptorFile:
|
||||
s = env->GetFileSize(dbname + "/" + file, &file_size);
|
||||
if (s.ok()) {
|
||||
if (env->GetFileSize(dbname + "/" + file, &file_size).ok()) {
|
||||
Header(options.info_log,
|
||||
"MANIFEST file: %s size: %" PRIu64 " Bytes\n", file.c_str(),
|
||||
file_size);
|
||||
} else {
|
||||
Error(options.info_log,
|
||||
"Error when reading MANIFEST file: %s/%s %s\n", dbname.c_str(),
|
||||
file.c_str(), s.ToString().c_str());
|
||||
Error(options.info_log, "Error when reading MANIFEST file: %s/%s\n",
|
||||
dbname.c_str(), file.c_str());
|
||||
}
|
||||
break;
|
||||
case kWalFile:
|
||||
s = env->GetFileSize(dbname + "/" + file, &file_size);
|
||||
if (s.ok()) {
|
||||
if (env->GetFileSize(dbname + "/" + file, &file_size).ok()) {
|
||||
wal_info.append(file)
|
||||
.append(" size: ")
|
||||
.append(std::to_string(file_size))
|
||||
.append(" ; ");
|
||||
} else {
|
||||
Error(options.info_log, "Error when reading LOG file: %s/%s %s\n",
|
||||
dbname.c_str(), file.c_str(), s.ToString().c_str());
|
||||
Error(options.info_log, "Error when reading LOG file: %s/%s\n",
|
||||
dbname.c_str(), file.c_str());
|
||||
}
|
||||
break;
|
||||
case kTableFile:
|
||||
@@ -91,10 +86,10 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
// Get sst files in db_path dir
|
||||
for (auto& db_path : options.db_paths) {
|
||||
if (dbname.compare(db_path.path) != 0) {
|
||||
s = env->GetChildren(db_path.path, &files);
|
||||
if (!s.ok()) {
|
||||
Error(options.info_log, "Error when reading %s dir %s\n",
|
||||
db_path.path.c_str(), s.ToString().c_str());
|
||||
if (!env->GetChildren(db_path.path, &files).ok()) {
|
||||
Error(options.info_log,
|
||||
"Error when reading %s dir\n",
|
||||
db_path.path.c_str());
|
||||
continue;
|
||||
}
|
||||
std::sort(files.begin(), files.end());
|
||||
@@ -116,25 +111,22 @@ void DumpDBFileSummary(const ImmutableDBOptions& options,
|
||||
// Get wal file in wal_dir
|
||||
const auto& wal_dir = options.GetWalDir(dbname);
|
||||
if (!options.IsWalDirSameAsDBPath(dbname)) {
|
||||
s = env->GetChildren(wal_dir, &files);
|
||||
if (!s.ok()) {
|
||||
Error(options.info_log, "Error when reading %s dir %s\n", wal_dir.c_str(),
|
||||
s.ToString().c_str());
|
||||
if (!env->GetChildren(wal_dir, &files).ok()) {
|
||||
Error(options.info_log, "Error when reading %s dir\n", wal_dir.c_str());
|
||||
return;
|
||||
}
|
||||
wal_info.clear();
|
||||
for (const std::string& file : files) {
|
||||
if (ParseFileName(file, &number, &type)) {
|
||||
if (type == kWalFile) {
|
||||
s = env->GetFileSize(wal_dir + "/" + file, &file_size);
|
||||
if (s.ok()) {
|
||||
if (env->GetFileSize(wal_dir + "/" + file, &file_size).ok()) {
|
||||
wal_info.append(file)
|
||||
.append(" size: ")
|
||||
.append(std::to_string(file_size))
|
||||
.append(" ; ");
|
||||
} else {
|
||||
Error(options.info_log, "Error when reading LOG file %s/%s %s\n",
|
||||
wal_dir.c_str(), file.c_str(), s.ToString().c_str());
|
||||
Error(options.info_log, "Error when reading LOG file %s/%s\n",
|
||||
wal_dir.c_str(), file.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ TEST_F(DBIteratorStressTest, StressTest) {
|
||||
a /= 10;
|
||||
++len;
|
||||
}
|
||||
std::string s = std::to_string(rnd.Next() % static_cast<uint64_t>(max_key));
|
||||
std::string s = ToString(rnd.Next() % static_cast<uint64_t>(max_key));
|
||||
s.insert(0, len - (int)s.size(), '0');
|
||||
return s;
|
||||
};
|
||||
@@ -444,13 +444,12 @@ TEST_F(DBIteratorStressTest, StressTest) {
|
||||
for (double mutation_probability : {0.01, 0.5}) {
|
||||
for (double target_hidden_fraction : {0.1, 0.5}) {
|
||||
std::string trace_str =
|
||||
"entries: " + std::to_string(num_entries) +
|
||||
", key_space: " + std::to_string(key_space) +
|
||||
", error_probability: " + std::to_string(error_probability) +
|
||||
", mutation_probability: " +
|
||||
std::to_string(mutation_probability) +
|
||||
"entries: " + ToString(num_entries) +
|
||||
", key_space: " + ToString(key_space) +
|
||||
", error_probability: " + ToString(error_probability) +
|
||||
", mutation_probability: " + ToString(mutation_probability) +
|
||||
", target_hidden_fraction: " +
|
||||
std::to_string(target_hidden_fraction);
|
||||
ToString(target_hidden_fraction);
|
||||
SCOPED_TRACE(trace_str);
|
||||
if (trace) {
|
||||
std::cout << trace_str << std::endl;
|
||||
@@ -471,7 +470,7 @@ TEST_F(DBIteratorStressTest, StressTest) {
|
||||
types[rnd.Next() % (sizeof(types) / sizeof(types[0]))];
|
||||
}
|
||||
e.sequence = i;
|
||||
e.value = "v" + std::to_string(i);
|
||||
e.value = "v" + ToString(i);
|
||||
ParsedInternalKey internal_key(e.key, e.sequence, e.type);
|
||||
AppendInternalKey(&e.ikey, internal_key);
|
||||
|
||||
|
||||
+8
-8
@@ -766,7 +766,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
internal_iter->AddMerge("b", "merge_1");
|
||||
internal_iter->AddMerge("a", "merge_2");
|
||||
for (size_t k = 0; k < 200; ++k) {
|
||||
internal_iter->AddPut("c", std::to_string(k));
|
||||
internal_iter->AddPut("c", ToString(k));
|
||||
}
|
||||
internal_iter->Finish();
|
||||
|
||||
@@ -780,7 +780,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
ASSERT_TRUE(db_iter->Valid());
|
||||
|
||||
ASSERT_EQ(db_iter->key().ToString(), "c");
|
||||
ASSERT_EQ(db_iter->value().ToString(), std::to_string(i));
|
||||
ASSERT_EQ(db_iter->value().ToString(), ToString(i));
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(db_iter->Valid());
|
||||
|
||||
@@ -925,11 +925,11 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
internal_iter->AddMerge("b", "merge_1");
|
||||
internal_iter->AddMerge("a", "merge_2");
|
||||
for (size_t k = 0; k < 200; ++k) {
|
||||
internal_iter->AddPut("d", std::to_string(k));
|
||||
internal_iter->AddPut("d", ToString(k));
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < 200; ++k) {
|
||||
internal_iter->AddPut("c", std::to_string(k));
|
||||
internal_iter->AddPut("c", ToString(k));
|
||||
}
|
||||
internal_iter->Finish();
|
||||
|
||||
@@ -942,7 +942,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
ASSERT_TRUE(db_iter->Valid());
|
||||
|
||||
ASSERT_EQ(db_iter->key().ToString(), "d");
|
||||
ASSERT_EQ(db_iter->value().ToString(), std::to_string(i));
|
||||
ASSERT_EQ(db_iter->value().ToString(), ToString(i));
|
||||
db_iter->Prev();
|
||||
ASSERT_TRUE(db_iter->Valid());
|
||||
|
||||
@@ -966,7 +966,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
internal_iter->AddMerge("b", "b");
|
||||
internal_iter->AddMerge("a", "a");
|
||||
for (size_t k = 0; k < 200; ++k) {
|
||||
internal_iter->AddMerge("c", std::to_string(k));
|
||||
internal_iter->AddMerge("c", ToString(k));
|
||||
}
|
||||
internal_iter->Finish();
|
||||
|
||||
@@ -981,7 +981,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
|
||||
ASSERT_EQ(db_iter->key().ToString(), "c");
|
||||
std::string merge_result = "0";
|
||||
for (size_t j = 1; j <= i; ++j) {
|
||||
merge_result += "," + std::to_string(j);
|
||||
merge_result += "," + ToString(j);
|
||||
}
|
||||
ASSERT_EQ(db_iter->value().ToString(), merge_result);
|
||||
|
||||
@@ -3156,7 +3156,7 @@ TEST_F(DBIteratorTest, ReverseToForwardWithDisappearingKeys) {
|
||||
internal_iter->AddPut("a", "A");
|
||||
internal_iter->AddPut("b", "B");
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
internal_iter->AddPut("c" + std::to_string(i), "");
|
||||
internal_iter->AddPut("c" + ToString(i), "");
|
||||
}
|
||||
internal_iter->Finish();
|
||||
|
||||
|
||||
@@ -111,12 +111,9 @@ TEST_P(DBIteratorTest, PersistedTierOnIterator) {
|
||||
TEST_P(DBIteratorTest, NonBlockingIteration) {
|
||||
do {
|
||||
ReadOptions non_blocking_opts, regular_opts;
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.full_block_cache = true;
|
||||
Options options = CurrentOptions(options_override);
|
||||
Options options = CurrentOptions();
|
||||
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
|
||||
non_blocking_opts.read_tier = kBlockCacheTier;
|
||||
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
// write one kv to the database.
|
||||
ASSERT_OK(Put(1, "a", "b"));
|
||||
@@ -3160,7 +3157,7 @@ TEST_F(DBIteratorWithReadCallbackTest, ReadCallback) {
|
||||
uint64_t num_versions =
|
||||
CurrentOptions().max_sequential_skip_in_iterations + 10;
|
||||
for (uint64_t i = 0; i < num_versions; i++) {
|
||||
ASSERT_OK(Put("bar", std::to_string(i)));
|
||||
ASSERT_OK(Put("bar", ToString(i)));
|
||||
}
|
||||
SequenceNumber seq3 = db_->GetLatestSequenceNumber();
|
||||
TestReadCallback callback2(seq3);
|
||||
@@ -3189,7 +3186,7 @@ TEST_F(DBIteratorWithReadCallbackTest, ReadCallback) {
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_EQ("bar", iter->key());
|
||||
ASSERT_EQ(std::to_string(num_versions - 1), iter->value());
|
||||
ASSERT_EQ(ToString(num_versions - 1), iter->value());
|
||||
|
||||
delete iter;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ class DbKvChecksumTest
|
||||
|
||||
void CorruptNextByteCallBack(void* arg) {
|
||||
Slice encoded = *static_cast<Slice*>(arg);
|
||||
if (entry_len_ == std::numeric_limits<size_t>::max()) {
|
||||
if (entry_len_ == port::kMaxSizet) {
|
||||
// We learn the entry size on the first attempt
|
||||
entry_len_ = encoded.size();
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class DbKvChecksumTest
|
||||
WriteBatchOpType op_type_;
|
||||
char corrupt_byte_addend_;
|
||||
size_t corrupt_byte_offset_ = 0;
|
||||
size_t entry_len_ = std::numeric_limits<size_t>::max();
|
||||
size_t entry_len_ = port::kMaxSizet;
|
||||
};
|
||||
|
||||
std::string GetTestNameSuffix(
|
||||
|
||||
@@ -187,7 +187,7 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorCorruptedLog) {
|
||||
DestroyAndReopen(options);
|
||||
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
ASSERT_OK(Put("key" + std::to_string(i), DummyString(10)));
|
||||
ASSERT_OK(Put("key" + ToString(i), DummyString(10)));
|
||||
}
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
@@ -263,20 +263,20 @@ TEST_F(DBTestXactLogIterator, TransactionLogIteratorBlobs) {
|
||||
struct Handler : public WriteBatch::Handler {
|
||||
std::string seen;
|
||||
Status PutCF(uint32_t cf, const Slice& key, const Slice& value) override {
|
||||
seen += "Put(" + std::to_string(cf) + ", " + key.ToString() + ", " +
|
||||
std::to_string(value.size()) + ")";
|
||||
seen += "Put(" + ToString(cf) + ", " + key.ToString() + ", " +
|
||||
ToString(value.size()) + ")";
|
||||
return Status::OK();
|
||||
}
|
||||
Status MergeCF(uint32_t cf, const Slice& key, const Slice& value) override {
|
||||
seen += "Merge(" + std::to_string(cf) + ", " + key.ToString() + ", " +
|
||||
std::to_string(value.size()) + ")";
|
||||
seen += "Merge(" + ToString(cf) + ", " + key.ToString() + ", " +
|
||||
ToString(value.size()) + ")";
|
||||
return Status::OK();
|
||||
}
|
||||
void LogData(const Slice& blob) override {
|
||||
seen += "LogData(" + blob.ToString() + ")";
|
||||
}
|
||||
Status DeleteCF(uint32_t cf, const Slice& key) override {
|
||||
seen += "Delete(" + std::to_string(cf) + ", " + key.ToString() + ")";
|
||||
seen += "Delete(" + ToString(cf) + ", " + key.ToString() + ")";
|
||||
return Status::OK();
|
||||
}
|
||||
} handler;
|
||||
|
||||
@@ -97,7 +97,7 @@ class MockMemTableRepFactory : public MemTableRepFactory {
|
||||
|
||||
private:
|
||||
MockMemTableRep* mock_rep_;
|
||||
// workaround since there's no std::numeric_limits<uint32_t>::max() yet.
|
||||
// workaround since there's no port::kMaxUint32 yet.
|
||||
uint32_t last_column_family_id_ = static_cast<uint32_t>(-1);
|
||||
};
|
||||
|
||||
@@ -171,7 +171,7 @@ TEST_F(DBMemTableTest, DuplicateSeq) {
|
||||
if (!insert_dup) {
|
||||
seq++;
|
||||
}
|
||||
Status s = mem->Add(seq, kTypeValue, "foo", "value" + std::to_string(seq),
|
||||
Status s = mem->Add(seq, kTypeValue, "foo", "value" + ToString(seq),
|
||||
nullptr /* kv_prot_info */);
|
||||
if (insert_dup) {
|
||||
ASSERT_TRUE(s.IsTryAgain());
|
||||
|
||||
+12
-28
@@ -95,22 +95,6 @@ TEST_F(DBOptionsTest, ImmutableTrackAndVerifyWalsInManifest) {
|
||||
ASSERT_FALSE(s.ok());
|
||||
}
|
||||
|
||||
TEST_F(DBOptionsTest, ImmutableVerifySstUniqueIdInManifest) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
|
||||
ImmutableDBOptions db_options(options);
|
||||
ASSERT_TRUE(db_options.verify_sst_unique_id_in_manifest);
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_TRUE(dbfull()->GetDBOptions().verify_sst_unique_id_in_manifest);
|
||||
|
||||
Status s =
|
||||
dbfull()->SetDBOptions({{"verify_sst_unique_id_in_manifest", "false"}});
|
||||
ASSERT_FALSE(s.ok());
|
||||
}
|
||||
|
||||
// RocksDB lite don't support dynamic options.
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
@@ -440,8 +424,8 @@ TEST_F(DBOptionsTest, WritableFileMaxBufferSize) {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
int i = 0;
|
||||
for (; i < 3; i++) {
|
||||
ASSERT_OK(Put("foo", std::to_string(i)));
|
||||
ASSERT_OK(Put("bar", std::to_string(i)));
|
||||
ASSERT_OK(Put("foo", ToString(i)));
|
||||
ASSERT_OK(Put("bar", ToString(i)));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -458,8 +442,8 @@ TEST_F(DBOptionsTest, WritableFileMaxBufferSize) {
|
||||
dbfull()->GetDBOptions().writable_file_max_buffer_size);
|
||||
i = 0;
|
||||
for (; i < 3; i++) {
|
||||
ASSERT_OK(Put("foo", std::to_string(i)));
|
||||
ASSERT_OK(Put("bar", std::to_string(i)));
|
||||
ASSERT_OK(Put("foo", ToString(i)));
|
||||
ASSERT_OK(Put("bar", ToString(i)));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -589,8 +573,8 @@ TEST_F(DBOptionsTest, SetOptionsMayTriggerCompaction) {
|
||||
Reopen(options);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Need to insert two keys to avoid trivial move.
|
||||
ASSERT_OK(Put("foo", std::to_string(i)));
|
||||
ASSERT_OK(Put("bar", std::to_string(i)));
|
||||
ASSERT_OK(Put("foo", ToString(i)));
|
||||
ASSERT_OK(Put("bar", ToString(i)));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ("3", FilesPerLevel());
|
||||
@@ -733,8 +717,8 @@ TEST_F(DBOptionsTest, SetStatsDumpPeriodSec) {
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
unsigned int num = rand() % 5000 + 1;
|
||||
ASSERT_OK(dbfull()->SetDBOptions(
|
||||
{{"stats_dump_period_sec", std::to_string(num)}}));
|
||||
ASSERT_OK(
|
||||
dbfull()->SetDBOptions({{"stats_dump_period_sec", ToString(num)}}));
|
||||
ASSERT_EQ(num, dbfull()->GetDBOptions().stats_dump_period_sec);
|
||||
}
|
||||
Close();
|
||||
@@ -925,7 +909,7 @@ TEST_F(DBOptionsTest, SetFIFOCompactionOptions) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -956,7 +940,7 @@ TEST_F(DBOptionsTest, SetFIFOCompactionOptions) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -988,7 +972,7 @@ TEST_F(DBOptionsTest, SetFIFOCompactionOptions) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -1052,7 +1036,7 @@ TEST_F(DBOptionsTest, FIFOTtlBackwardCompatible) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
+15
-16
@@ -593,9 +593,9 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ResetTableProperties(&sum_tp);
|
||||
for (int level = 0; level < kMaxLevel; ++level) {
|
||||
db_->GetProperty(DB::Properties::kAggregatedTablePropertiesAtLevel +
|
||||
std::to_string(level),
|
||||
&level_tp_strings[level]);
|
||||
db_->GetProperty(
|
||||
DB::Properties::kAggregatedTablePropertiesAtLevel + ToString(level),
|
||||
&level_tp_strings[level]);
|
||||
ParseTablePropertiesString(level_tp_strings[level], &level_tps[level]);
|
||||
sum_tp.data_size += level_tps[level].data_size;
|
||||
sum_tp.index_size += level_tps[level].index_size;
|
||||
@@ -1091,7 +1091,7 @@ TEST_F(DBPropertiesTest, EstimateCompressionRatio) {
|
||||
for (int j = 0; j < kNumEntriesPerFile; ++j) {
|
||||
// Put common data ("key") at end to prevent delta encoding from
|
||||
// compressing the key effectively
|
||||
std::string key = std::to_string(i) + std::to_string(j) + "key";
|
||||
std::string key = ToString(i) + ToString(j) + "key";
|
||||
ASSERT_OK(dbfull()->Put(WriteOptions(), key, kVal));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
@@ -1185,7 +1185,7 @@ class CountingDeleteTabPropCollector : public TablePropertiesCollector {
|
||||
|
||||
Status Finish(UserCollectedProperties* properties) override {
|
||||
*properties =
|
||||
UserCollectedProperties{{"num_delete", std::to_string(num_deletes_)}};
|
||||
UserCollectedProperties{{"num_delete", ToString(num_deletes_)}};
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -1215,7 +1215,7 @@ class BlockCountingTablePropertiesCollector : public TablePropertiesCollector {
|
||||
|
||||
Status Finish(UserCollectedProperties* properties) override {
|
||||
(*properties)[kNumSampledBlocksPropertyName] =
|
||||
std::to_string(num_sampled_blocks_);
|
||||
ToString(num_sampled_blocks_);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -1235,7 +1235,7 @@ class BlockCountingTablePropertiesCollector : public TablePropertiesCollector {
|
||||
|
||||
UserCollectedProperties GetReadableProperties() const override {
|
||||
return UserCollectedProperties{
|
||||
{kNumSampledBlocksPropertyName, std::to_string(num_sampled_blocks_)},
|
||||
{kNumSampledBlocksPropertyName, ToString(num_sampled_blocks_)},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1272,8 +1272,7 @@ TEST_F(DBPropertiesTest, GetUserDefinedTableProperties) {
|
||||
// Create 4 tables
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(
|
||||
db_->Put(WriteOptions(), std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
}
|
||||
@@ -1313,7 +1312,7 @@ TEST_F(DBPropertiesTest, UserDefinedTablePropertiesContext) {
|
||||
// Create 2 files
|
||||
for (int table = 0; table < 2; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(Put(1, std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(1, ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(Flush(1));
|
||||
}
|
||||
@@ -1323,7 +1322,7 @@ TEST_F(DBPropertiesTest, UserDefinedTablePropertiesContext) {
|
||||
// Trigger automatic compactions.
|
||||
for (int table = 0; table < 3; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(Put(1, std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(1, ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -1340,7 +1339,7 @@ TEST_F(DBPropertiesTest, UserDefinedTablePropertiesContext) {
|
||||
// Create 4 tables in default column family
|
||||
for (int table = 0; table < 2; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(Put(std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -1350,7 +1349,7 @@ TEST_F(DBPropertiesTest, UserDefinedTablePropertiesContext) {
|
||||
// Trigger automatic compactions.
|
||||
for (int table = 0; table < 3; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(Put(std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -1546,7 +1545,7 @@ TEST_F(DBPropertiesTest, BlockAddForCompressionSampling) {
|
||||
user_props.end());
|
||||
ASSERT_EQ(user_props.at(BlockCountingTablePropertiesCollector::
|
||||
kNumSampledBlocksPropertyName),
|
||||
std::to_string(sample_for_compression ? 1 : 0));
|
||||
ToString(sample_for_compression ? 1 : 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1743,11 +1742,11 @@ TEST_F(DBPropertiesTest, SstFilesSize) {
|
||||
Reopen(options);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(Put("key" + std::to_string(i), std::string(1000, 'v')));
|
||||
ASSERT_OK(Put("key" + ToString(i), std::string(1000, 'v')));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ASSERT_OK(Delete("key" + std::to_string(i)));
|
||||
ASSERT_OK(Delete("key" + ToString(i)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
uint64_t sst_size;
|
||||
|
||||
@@ -190,10 +190,9 @@ TEST_F(DBRangeDelTest, MaxCompactionBytesCutsOutputFiles) {
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(NumTableFilesAtLevel(2), 2);
|
||||
|
||||
ASSERT_OK(
|
||||
db_->SetOptions(db_->DefaultColumnFamily(),
|
||||
{{"target_file_size_base",
|
||||
std::to_string(100 * opts.max_compaction_bytes)}}));
|
||||
ASSERT_OK(db_->SetOptions(
|
||||
db_->DefaultColumnFamily(),
|
||||
{{"target_file_size_base", ToString(100 * opts.max_compaction_bytes)}}));
|
||||
|
||||
// It spans the whole key-range, thus will be included in all output files
|
||||
ASSERT_OK(db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(),
|
||||
@@ -501,8 +500,7 @@ TEST_F(DBRangeDelTest, ValidUniversalSubcompactionBoundaries) {
|
||||
1 /* input_level */, 2 /* output_level */, CompactRangeOptions(),
|
||||
nullptr /* begin */, nullptr /* end */, true /* exclusive */,
|
||||
true /* disallow_trivial_move */,
|
||||
std::numeric_limits<uint64_t>::max() /* max_file_num_to_ignore */,
|
||||
"" /*trim_ts*/));
|
||||
port::kMaxUint64 /* max_file_num_to_ignore */, "" /*trim_ts*/));
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
|
||||
@@ -1,331 +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 "db/db_with_timestamp_test_util.h"
|
||||
#include "test_util/testutil.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class DBReadOnlyTestWithTimestamp : public DBBasicTestWithTimestampBase {
|
||||
public:
|
||||
DBReadOnlyTestWithTimestamp()
|
||||
: DBBasicTestWithTimestampBase("db_readonly_test_with_timestamp") {}
|
||||
};
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBReadOnlyTestWithTimestamp, IteratorAndGetReadTimestampSizeMismatch) {
|
||||
const int kNumKeysPerFile = 128;
|
||||
const uint64_t kMaxKey = 1024;
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
const std::string write_timestamp = Timestamp(1, 0);
|
||||
WriteOptions write_opts;
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
Status s = db_->Put(write_opts, Key1(key), write_timestamp,
|
||||
"value" + std::to_string(key));
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
|
||||
// Reopen the database in read only mode to test its timestamp support.
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
ReadOptions read_opts;
|
||||
std::string different_size_read_timestamp;
|
||||
PutFixed32(&different_size_read_timestamp, 2);
|
||||
Slice different_size_read_ts = different_size_read_timestamp;
|
||||
read_opts.timestamp = &different_size_read_ts;
|
||||
{
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_opts));
|
||||
ASSERT_FALSE(iter->Valid());
|
||||
ASSERT_TRUE(iter->status().IsInvalidArgument());
|
||||
}
|
||||
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
std::string value_from_get;
|
||||
std::string timestamp;
|
||||
ASSERT_TRUE(db_->Get(read_opts, Key1(key), &value_from_get, ×tamp)
|
||||
.IsInvalidArgument());
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBReadOnlyTestWithTimestamp,
|
||||
IteratorAndGetReadTimestampSpecifiedWithoutWriteTimestamp) {
|
||||
const int kNumKeysPerFile = 128;
|
||||
const uint64_t kMaxKey = 1024;
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
WriteOptions write_opts;
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
Status s = db_->Put(write_opts, Key1(key), "value" + std::to_string(key));
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
|
||||
// Reopen the database in read only mode to test its timestamp support.
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
ReadOptions read_opts;
|
||||
const std::string read_timestamp = Timestamp(2, 0);
|
||||
Slice read_ts = read_timestamp;
|
||||
read_opts.timestamp = &read_ts;
|
||||
{
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_opts));
|
||||
ASSERT_FALSE(iter->Valid());
|
||||
ASSERT_TRUE(iter->status().IsInvalidArgument());
|
||||
}
|
||||
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
std::string value_from_get;
|
||||
std::string timestamp;
|
||||
ASSERT_TRUE(db_->Get(read_opts, Key1(key), &value_from_get, ×tamp)
|
||||
.IsInvalidArgument());
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBReadOnlyTestWithTimestamp, IteratorAndGet) {
|
||||
const int kNumKeysPerFile = 128;
|
||||
const uint64_t kMaxKey = 1024;
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
const std::vector<uint64_t> start_keys = {1, 0};
|
||||
const std::vector<std::string> write_timestamps = {Timestamp(1, 0),
|
||||
Timestamp(3, 0)};
|
||||
const std::vector<std::string> read_timestamps = {Timestamp(2, 0),
|
||||
Timestamp(4, 0)};
|
||||
for (size_t i = 0; i < write_timestamps.size(); ++i) {
|
||||
WriteOptions write_opts;
|
||||
for (uint64_t key = start_keys[i]; key <= kMaxKey; ++key) {
|
||||
Status s = db_->Put(write_opts, Key1(key), write_timestamps[i],
|
||||
"value" + std::to_string(i));
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Reopen the database in read only mode to test its timestamp support.
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
|
||||
auto get_value_and_check = [](DB* db, ReadOptions read_opts, Slice key,
|
||||
Slice expected_value, std::string expected_ts) {
|
||||
std::string value_from_get;
|
||||
std::string timestamp;
|
||||
ASSERT_OK(db->Get(read_opts, key.ToString(), &value_from_get, ×tamp));
|
||||
ASSERT_EQ(expected_value, value_from_get);
|
||||
ASSERT_EQ(expected_ts, timestamp);
|
||||
};
|
||||
for (size_t i = 0; i < read_timestamps.size(); ++i) {
|
||||
ReadOptions read_opts;
|
||||
Slice read_ts = read_timestamps[i];
|
||||
read_opts.timestamp = &read_ts;
|
||||
std::unique_ptr<Iterator> it(db_->NewIterator(read_opts));
|
||||
int count = 0;
|
||||
uint64_t key = 0;
|
||||
// Forward iterate.
|
||||
for (it->Seek(Key1(0)), key = start_keys[i]; it->Valid();
|
||||
it->Next(), ++count, ++key) {
|
||||
CheckIterUserEntry(it.get(), Key1(key), kTypeValue,
|
||||
"value" + std::to_string(i), write_timestamps[i]);
|
||||
get_value_and_check(db_, read_opts, it->key(), it->value(),
|
||||
write_timestamps[i]);
|
||||
}
|
||||
size_t expected_count = kMaxKey - start_keys[i] + 1;
|
||||
ASSERT_EQ(expected_count, count);
|
||||
|
||||
// Backward iterate.
|
||||
count = 0;
|
||||
for (it->SeekForPrev(Key1(kMaxKey)), key = kMaxKey; it->Valid();
|
||||
it->Prev(), ++count, --key) {
|
||||
CheckIterUserEntry(it.get(), Key1(key), kTypeValue,
|
||||
"value" + std::to_string(i), write_timestamps[i]);
|
||||
get_value_and_check(db_, read_opts, it->key(), it->value(),
|
||||
write_timestamps[i]);
|
||||
}
|
||||
ASSERT_EQ(static_cast<size_t>(kMaxKey) - start_keys[i] + 1, count);
|
||||
|
||||
// SeekToFirst()/SeekToLast() with lower/upper bounds.
|
||||
// Then iter with lower and upper bounds.
|
||||
uint64_t l = 0;
|
||||
uint64_t r = kMaxKey + 1;
|
||||
while (l < r) {
|
||||
std::string lb_str = Key1(l);
|
||||
Slice lb = lb_str;
|
||||
std::string ub_str = Key1(r);
|
||||
Slice ub = ub_str;
|
||||
read_opts.iterate_lower_bound = &lb;
|
||||
read_opts.iterate_upper_bound = &ub;
|
||||
it.reset(db_->NewIterator(read_opts));
|
||||
for (it->SeekToFirst(), key = std::max(l, start_keys[i]), count = 0;
|
||||
it->Valid(); it->Next(), ++key, ++count) {
|
||||
CheckIterUserEntry(it.get(), Key1(key), kTypeValue,
|
||||
"value" + std::to_string(i), write_timestamps[i]);
|
||||
get_value_and_check(db_, read_opts, it->key(), it->value(),
|
||||
write_timestamps[i]);
|
||||
}
|
||||
ASSERT_EQ(r - std::max(l, start_keys[i]), count);
|
||||
|
||||
for (it->SeekToLast(), key = std::min(r, kMaxKey + 1), count = 0;
|
||||
it->Valid(); it->Prev(), --key, ++count) {
|
||||
CheckIterUserEntry(it.get(), Key1(key - 1), kTypeValue,
|
||||
"value" + std::to_string(i), write_timestamps[i]);
|
||||
get_value_and_check(db_, read_opts, it->key(), it->value(),
|
||||
write_timestamps[i]);
|
||||
}
|
||||
l += (kMaxKey / 100);
|
||||
r -= (kMaxKey / 100);
|
||||
}
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBReadOnlyTestWithTimestamp, Iterators) {
|
||||
const int kNumKeysPerFile = 128;
|
||||
const uint64_t kMaxKey = 1024;
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
const std::string write_timestamp = Timestamp(1, 0);
|
||||
const std::string read_timestamp = Timestamp(2, 0);
|
||||
WriteOptions write_opts;
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
Status s = db_->Put(write_opts, Key1(key), write_timestamp,
|
||||
"value" + std::to_string(key));
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
|
||||
// Reopen the database in read only mode to test its timestamp support.
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
ReadOptions read_opts;
|
||||
Slice read_ts = read_timestamp;
|
||||
read_opts.timestamp = &read_ts;
|
||||
std::vector<Iterator*> iters;
|
||||
ASSERT_OK(db_->NewIterators(read_opts, {db_->DefaultColumnFamily()}, &iters));
|
||||
ASSERT_EQ(static_cast<uint64_t>(1), iters.size());
|
||||
|
||||
int count = 0;
|
||||
uint64_t key = 0;
|
||||
// Forward iterate.
|
||||
for (iters[0]->Seek(Key1(0)), key = 0; iters[0]->Valid();
|
||||
iters[0]->Next(), ++count, ++key) {
|
||||
CheckIterUserEntry(iters[0], Key1(key), kTypeValue,
|
||||
"value" + std::to_string(key), write_timestamp);
|
||||
}
|
||||
|
||||
size_t expected_count = kMaxKey - 0 + 1;
|
||||
ASSERT_EQ(expected_count, count);
|
||||
delete iters[0];
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBReadOnlyTestWithTimestamp, IteratorsReadTimestampSizeMismatch) {
|
||||
const int kNumKeysPerFile = 128;
|
||||
const uint64_t kMaxKey = 1024;
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||
TestComparator test_cmp(kTimestampSize);
|
||||
options.comparator = &test_cmp;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
const std::string write_timestamp = Timestamp(1, 0);
|
||||
WriteOptions write_opts;
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
Status s = db_->Put(write_opts, Key1(key), write_timestamp,
|
||||
"value" + std::to_string(key));
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
|
||||
// Reopen the database in read only mode to test its timestamp support.
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
ReadOptions read_opts;
|
||||
std::string different_size_read_timestamp;
|
||||
PutFixed32(&different_size_read_timestamp, 2);
|
||||
Slice different_size_read_ts = different_size_read_timestamp;
|
||||
read_opts.timestamp = &different_size_read_ts;
|
||||
{
|
||||
std::vector<Iterator*> iters;
|
||||
ASSERT_TRUE(
|
||||
db_->NewIterators(read_opts, {db_->DefaultColumnFamily()}, &iters)
|
||||
.IsInvalidArgument());
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBReadOnlyTestWithTimestamp,
|
||||
IteratorsReadTimestampSpecifiedWithoutWriteTimestamp) {
|
||||
const int kNumKeysPerFile = 128;
|
||||
const uint64_t kMaxKey = 1024;
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
options.memtable_factory.reset(
|
||||
test::NewSpecialSkipListFactory(kNumKeysPerFile));
|
||||
DestroyAndReopen(options);
|
||||
WriteOptions write_opts;
|
||||
for (uint64_t key = 0; key <= kMaxKey; ++key) {
|
||||
Status s = db_->Put(write_opts, Key1(key), "value" + std::to_string(key));
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
|
||||
// Reopen the database in read only mode to test its timestamp support.
|
||||
Close();
|
||||
ASSERT_OK(ReadOnlyReopen(options));
|
||||
ReadOptions read_opts;
|
||||
const std::string read_timestamp = Timestamp(2, 0);
|
||||
Slice read_ts = read_timestamp;
|
||||
read_opts.timestamp = &read_ts;
|
||||
{
|
||||
std::vector<Iterator*> iters;
|
||||
ASSERT_TRUE(
|
||||
db_->NewIterators(read_opts, {db_->DefaultColumnFamily()}, &iters)
|
||||
.IsInvalidArgument());
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
RegisterCustomObjects(argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
+6
-11
@@ -181,7 +181,6 @@ TEST_F(DBSecondaryTest, SimpleInternalCompaction) {
|
||||
ASSERT_EQ(input.input_files.size(), 3);
|
||||
|
||||
input.output_level = 1;
|
||||
ASSERT_OK(db_->GetDbIdentity(input.db_id));
|
||||
Close();
|
||||
|
||||
options.max_open_files = -1;
|
||||
@@ -213,20 +212,20 @@ TEST_F(DBSecondaryTest, InternalCompactionMultiLevels) {
|
||||
const int kRangeL2 = 10;
|
||||
const int kRangeL1 = 30;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(Put(Key(i * kRangeL2), "value" + std::to_string(i)));
|
||||
ASSERT_OK(Put(Key((i + 1) * kRangeL2 - 1), "value" + std::to_string(i)));
|
||||
ASSERT_OK(Put(Key(i * kRangeL2), "value" + ToString(i)));
|
||||
ASSERT_OK(Put(Key((i + 1) * kRangeL2 - 1), "value" + ToString(i)));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
MoveFilesToLevel(2);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ASSERT_OK(Put(Key(i * kRangeL1), "value" + std::to_string(i)));
|
||||
ASSERT_OK(Put(Key((i + 1) * kRangeL1 - 1), "value" + std::to_string(i)));
|
||||
ASSERT_OK(Put(Key(i * kRangeL1), "value" + ToString(i)));
|
||||
ASSERT_OK(Put(Key((i + 1) * kRangeL1 - 1), "value" + ToString(i)));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
MoveFilesToLevel(1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ASSERT_OK(Put(Key(i * 30), "value" + std::to_string(i)));
|
||||
ASSERT_OK(Put(Key(i * 30 + 50), "value" + std::to_string(i)));
|
||||
ASSERT_OK(Put(Key(i * 30), "value" + ToString(i)));
|
||||
ASSERT_OK(Put(Key(i * 30 + 50), "value" + ToString(i)));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
@@ -242,7 +241,6 @@ TEST_F(DBSecondaryTest, InternalCompactionMultiLevels) {
|
||||
input1.input_files.push_back(meta.levels[1].files[2].name);
|
||||
|
||||
input1.output_level = 1;
|
||||
ASSERT_OK(db_->GetDbIdentity(input1.db_id));
|
||||
|
||||
options.max_open_files = -1;
|
||||
Close();
|
||||
@@ -263,7 +261,6 @@ TEST_F(DBSecondaryTest, InternalCompactionMultiLevels) {
|
||||
}
|
||||
|
||||
input2.output_level = 2;
|
||||
input2.db_id = input1.db_id;
|
||||
ASSERT_OK(db_secondary_full()->TEST_CompactWithoutInstallation(
|
||||
OpenAndCompactOptions(), cfh, input2, &result));
|
||||
ASSERT_OK(result.status);
|
||||
@@ -308,7 +305,6 @@ TEST_F(DBSecondaryTest, InternalCompactionCompactedFiles) {
|
||||
ASSERT_EQ(input.input_files.size(), 3);
|
||||
|
||||
input.output_level = 1;
|
||||
ASSERT_OK(db_->GetDbIdentity(input.db_id));
|
||||
|
||||
// trigger compaction to delete the files for secondary instance compaction
|
||||
ASSERT_OK(Put("foo", "foo_value" + std::to_string(3)));
|
||||
@@ -350,7 +346,6 @@ TEST_F(DBSecondaryTest, InternalCompactionMissingFiles) {
|
||||
ASSERT_EQ(input.input_files.size(), 3);
|
||||
|
||||
input.output_level = 1;
|
||||
ASSERT_OK(db_->GetDbIdentity(input.db_id));
|
||||
|
||||
Close();
|
||||
|
||||
|
||||
+7
-68
@@ -280,58 +280,6 @@ TEST_F(DBSSTTest, DeleteObsoleteFilesPendingOutputs) {
|
||||
listener->VerifyMatchedCount(1);
|
||||
}
|
||||
|
||||
// Test that producing an empty .sst file does not write it out to
|
||||
// disk, and that the DeleteFile() env method is not called for
|
||||
// removing the non-existing file later.
|
||||
TEST_F(DBSSTTest, DeleteFileNotCalledForNotCreatedSSTFile) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
|
||||
OnFileDeletionListener* listener = new OnFileDeletionListener();
|
||||
options.listeners.emplace_back(listener);
|
||||
|
||||
Reopen(options);
|
||||
|
||||
// Flush the empty database.
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("", FilesPerLevel(0));
|
||||
|
||||
// We expect no .sst files.
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
db_->GetLiveFilesMetaData(&metadata);
|
||||
ASSERT_EQ(metadata.size(), 0U);
|
||||
|
||||
// We expect no file deletions.
|
||||
listener->VerifyMatchedCount(0);
|
||||
}
|
||||
|
||||
// Test that producing a non-empty .sst file does write it out to
|
||||
// disk, and that the DeleteFile() env method is not called for removing
|
||||
// the file later.
|
||||
TEST_F(DBSSTTest, DeleteFileNotCalledForCreatedSSTFile) {
|
||||
Options options = CurrentOptions();
|
||||
options.env = env_;
|
||||
|
||||
OnFileDeletionListener* listener = new OnFileDeletionListener();
|
||||
options.listeners.emplace_back(listener);
|
||||
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put("pika", "choo"));
|
||||
|
||||
// Flush the non-empty database.
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("1", FilesPerLevel(0));
|
||||
|
||||
// We expect 1 .sst files.
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
db_->GetLiveFilesMetaData(&metadata);
|
||||
ASSERT_EQ(metadata.size(), 1U);
|
||||
|
||||
// We expect no file deletions.
|
||||
listener->VerifyMatchedCount(0);
|
||||
}
|
||||
|
||||
TEST_F(DBSSTTest, DBWithSstFileManager) {
|
||||
std::shared_ptr<SstFileManager> sst_file_manager(NewSstFileManager(env_));
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(sst_file_manager.get());
|
||||
@@ -999,7 +947,7 @@ TEST_F(DBSSTTest, DeleteSchedulerMultipleDBPaths) {
|
||||
|
||||
// Create 4 files in L0
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ASSERT_OK(Put("Key" + std::to_string(i), DummyString(1024, 'A'), wo));
|
||||
ASSERT_OK(Put("Key" + ToString(i), DummyString(1024, 'A'), wo));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
// We created 4 sst files in L0
|
||||
@@ -1015,7 +963,7 @@ TEST_F(DBSSTTest, DeleteSchedulerMultipleDBPaths) {
|
||||
|
||||
// Create 4 files in L0
|
||||
for (int i = 4; i < 8; i++) {
|
||||
ASSERT_OK(Put("Key" + std::to_string(i), DummyString(1024, 'B'), wo));
|
||||
ASSERT_OK(Put("Key" + ToString(i), DummyString(1024, 'B'), wo));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ("4,1", FilesPerLevel(0));
|
||||
@@ -1061,7 +1009,7 @@ TEST_F(DBSSTTest, DestroyDBWithRateLimitedDelete) {
|
||||
|
||||
// Create 4 files in L0
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ASSERT_OK(Put("Key" + std::to_string(i), DummyString(1024, 'A')));
|
||||
ASSERT_OK(Put("Key" + ToString(i), DummyString(1024, 'A')));
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
// We created 4 sst files in L0
|
||||
@@ -1448,9 +1396,7 @@ TEST_F(DBSSTTest, OpenDBWithInfiniteMaxOpenFiles) {
|
||||
}
|
||||
|
||||
TEST_F(DBSSTTest, OpenDBWithInfiniteMaxOpenFilesSubjectToMemoryLimit) {
|
||||
for (CacheEntryRoleOptions::Decision charge_table_reader :
|
||||
{CacheEntryRoleOptions::Decision::kEnabled,
|
||||
CacheEntryRoleOptions::Decision::kDisabled}) {
|
||||
for (bool reserve_table_builder_memory : {true, false}) {
|
||||
// Open DB with infinite max open files
|
||||
// - First iteration use 1 thread to open files
|
||||
// - Second iteration use 5 threads to open files
|
||||
@@ -1490,9 +1436,7 @@ TEST_F(DBSSTTest, OpenDBWithInfiniteMaxOpenFilesSubjectToMemoryLimit) {
|
||||
}
|
||||
Close();
|
||||
|
||||
table_options.cache_usage_options.options_overrides.insert(
|
||||
{CacheEntryRole::kBlockBasedTableReader,
|
||||
{/*.charged = */ charge_table_reader}});
|
||||
table_options.reserve_table_reader_memory = reserve_table_builder_memory;
|
||||
table_options.block_cache =
|
||||
NewLRUCache(1024 /* capacity */, 0 /* num_shard_bits */,
|
||||
true /* strict_capacity_limit */);
|
||||
@@ -1501,13 +1445,8 @@ TEST_F(DBSSTTest, OpenDBWithInfiniteMaxOpenFilesSubjectToMemoryLimit) {
|
||||
// Reopening the DB will try to load all existing files, conditionally
|
||||
// subject to memory limit
|
||||
Status s = TryReopen(options);
|
||||
|
||||
if (charge_table_reader == CacheEntryRoleOptions::Decision::kEnabled) {
|
||||
if (table_options.reserve_table_reader_memory) {
|
||||
EXPECT_TRUE(s.IsMemoryLimit());
|
||||
EXPECT_TRUE(s.ToString().find(
|
||||
kCacheEntryRoleToCamelString[static_cast<std::uint32_t>(
|
||||
CacheEntryRole::kBlockBasedTableReader)]) !=
|
||||
std::string::npos);
|
||||
EXPECT_TRUE(s.ToString().find("memory limit based on cache capacity") !=
|
||||
std::string::npos);
|
||||
|
||||
@@ -1539,7 +1478,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
// Generate 5 files in L0
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
std::string val = "val_file_" + std::to_string(i);
|
||||
std::string val = "val_file_" + ToString(i);
|
||||
ASSERT_OK(Put(Key(j), val));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
@@ -84,8 +84,7 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfAllTablesTest) {
|
||||
}
|
||||
// Build file
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(
|
||||
db_->Put(WriteOptions(), std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), ToString(table * 100 + i), "val"));
|
||||
}
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
}
|
||||
@@ -114,7 +113,7 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfAllTablesTest) {
|
||||
// fetch key from 1st and 2nd table, which will internally place that table to
|
||||
// the table cache.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
Get(std::to_string(i * 100 + 0));
|
||||
Get(ToString(i * 100 + 0));
|
||||
}
|
||||
|
||||
VerifyTableProperties(db_, 10 + 11 + 12 + 13);
|
||||
@@ -123,7 +122,7 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfAllTablesTest) {
|
||||
Reopen(options);
|
||||
// fetch key from all tables, which will place them in table cache.
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Get(std::to_string(i * 100 + 0));
|
||||
Get(ToString(i * 100 + 0));
|
||||
}
|
||||
VerifyTableProperties(db_, 10 + 11 + 12 + 13);
|
||||
|
||||
@@ -157,7 +156,7 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfAllTablesTest) {
|
||||
} else {
|
||||
bool found_corruption = false;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
std::string result = Get(std::to_string(i * 100 + 0));
|
||||
std::string result = Get(ToString(i * 100 + 0));
|
||||
if (result.find_first_of("Corruption: block checksum mismatch") !=
|
||||
std::string::npos) {
|
||||
found_corruption = true;
|
||||
@@ -188,7 +187,7 @@ TEST_F(DBTablePropertiesTest, InvalidIgnored) {
|
||||
|
||||
// Build file
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
ASSERT_OK(db_->Put(WriteOptions(), std::to_string(i), "val"));
|
||||
ASSERT_OK(db_->Put(WriteOptions(), ToString(i), "val"));
|
||||
}
|
||||
ASSERT_OK(db_->Flush(FlushOptions()));
|
||||
|
||||
|
||||
+42
-44
@@ -2427,8 +2427,8 @@ TEST_F(DBTest, SnapshotFiles) {
|
||||
|
||||
// Also test GetLiveFilesStorageInfo
|
||||
std::vector<LiveFileStorageInfo> new_infos;
|
||||
ASSERT_OK(db_->GetLiveFilesStorageInfo(LiveFilesStorageInfoOptions(),
|
||||
&new_infos));
|
||||
ASSERT_OK(dbfull()->GetLiveFilesStorageInfo(LiveFilesStorageInfoOptions(),
|
||||
&new_infos));
|
||||
|
||||
// Close DB (while deletions disabled)
|
||||
Close();
|
||||
@@ -2734,7 +2734,7 @@ TEST_P(MultiThreadedDBTest, MultiThreaded) {
|
||||
Options options = CurrentOptions(options_override);
|
||||
std::vector<std::string> cfs;
|
||||
for (int i = 1; i < kColumnFamilies; ++i) {
|
||||
cfs.push_back(std::to_string(i));
|
||||
cfs.push_back(ToString(i));
|
||||
}
|
||||
Reopen(options);
|
||||
CreateAndReopenWithCF(cfs, options);
|
||||
@@ -2786,7 +2786,7 @@ static void GCThreadBody(void* arg) {
|
||||
WriteOptions wo;
|
||||
|
||||
for (int i = 0; i < kGCNumKeys; ++i) {
|
||||
std::string kv(std::to_string(i + id * kGCNumKeys));
|
||||
std::string kv(ToString(i + id * kGCNumKeys));
|
||||
ASSERT_OK(db->Put(wo, kv, kv));
|
||||
}
|
||||
t->done = true;
|
||||
@@ -2822,7 +2822,7 @@ TEST_F(DBTest, GroupCommitTest) {
|
||||
|
||||
std::vector<std::string> expected_db;
|
||||
for (int i = 0; i < kGCNumThreads * kGCNumKeys; ++i) {
|
||||
expected_db.push_back(std::to_string(i));
|
||||
expected_db.push_back(ToString(i));
|
||||
}
|
||||
std::sort(expected_db.begin(), expected_db.end());
|
||||
|
||||
@@ -3591,7 +3591,7 @@ TEST_P(DBTestWithParam, FIFOCompactionTest) {
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int j = 0; j < 110; ++j) {
|
||||
ASSERT_OK(Put(std::to_string(i * 100 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 100 + j), rnd.RandomString(980)));
|
||||
}
|
||||
// flush should happen here
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
|
||||
@@ -3607,7 +3607,7 @@ TEST_P(DBTestWithParam, FIFOCompactionTest) {
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 5);
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
// these keys should be deleted in previous compaction
|
||||
ASSERT_EQ("NOT_FOUND", Get(std::to_string(i)));
|
||||
ASSERT_EQ("NOT_FOUND", Get(ToString(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3629,7 +3629,7 @@ TEST_F(DBTest, FIFOCompactionTestWithCompaction) {
|
||||
for (int i = 0; i < 60; i++) {
|
||||
// Generate and flush a file about 20KB.
|
||||
for (int j = 0; j < 20; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3640,7 +3640,7 @@ TEST_F(DBTest, FIFOCompactionTestWithCompaction) {
|
||||
for (int i = 0; i < 60; i++) {
|
||||
// Generate and flush a file about 20KB.
|
||||
for (int j = 0; j < 20; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j + 2000), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j + 2000), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3670,27 +3670,27 @@ TEST_F(DBTest, FIFOCompactionStyleWithCompactionAndDelete) {
|
||||
Random rnd(301);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Each file contains a different key which will be dropped later.
|
||||
ASSERT_OK(Put("a" + std::to_string(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Put("key" + std::to_string(i), ""));
|
||||
ASSERT_OK(Put("z" + std::to_string(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Put("a" + ToString(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Put("key" + ToString(i), ""));
|
||||
ASSERT_OK(Put("z" + ToString(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 1);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ASSERT_EQ("", Get("key" + std::to_string(i)));
|
||||
ASSERT_EQ("", Get("key" + ToString(i)));
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Each file contains a different key which will be dropped later.
|
||||
ASSERT_OK(Put("a" + std::to_string(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Delete("key" + std::to_string(i)));
|
||||
ASSERT_OK(Put("z" + std::to_string(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Put("a" + ToString(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Delete("key" + ToString(i)));
|
||||
ASSERT_OK(Put("z" + ToString(i), rnd.RandomString(500)));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
}
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 2);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ASSERT_EQ("NOT_FOUND", Get("key" + std::to_string(i)));
|
||||
ASSERT_EQ("NOT_FOUND", Get("key" + ToString(i)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3759,7 +3759,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3791,7 +3791,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3807,7 +3807,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
// Create 1 more file to trigger TTL compaction. The old files are dropped.
|
||||
for (int i = 0; i < 1; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
@@ -3833,7 +3833,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3848,7 +3848,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int j = 0; j < 140; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3871,7 +3871,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// Generate and flush a file about 10KB.
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3890,7 +3890,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
// Create 10 more files. The old 5 files are dropped as their ttl expired.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
for (int j = 0; j < 10; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3915,7 +3915,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
for (int i = 0; i < 60; i++) {
|
||||
// Generate and flush a file about 20KB.
|
||||
for (int j = 0; j < 20; j++) {
|
||||
ASSERT_OK(Put(std::to_string(i * 20 + j), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -3926,8 +3926,7 @@ TEST_F(DBTest, FIFOCompactionWithTTLTest) {
|
||||
for (int i = 0; i < 60; i++) {
|
||||
// Generate and flush a file about 20KB.
|
||||
for (int j = 0; j < 20; j++) {
|
||||
ASSERT_OK(
|
||||
Put(std::to_string(i * 20 + j + 2000), rnd.RandomString(980)));
|
||||
ASSERT_OK(Put(ToString(i * 20 + j + 2000), rnd.RandomString(980)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
@@ -4208,7 +4207,7 @@ TEST_F(DBTest, ConcurrentFlushWAL) {
|
||||
std::vector<port::Thread> threads;
|
||||
threads.emplace_back([&] {
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
auto istr = std::to_string(i);
|
||||
auto istr = ToString(i);
|
||||
ASSERT_OK(db_->Put(wopt, db_->DefaultColumnFamily(), "a" + istr,
|
||||
"b" + istr));
|
||||
}
|
||||
@@ -4216,7 +4215,7 @@ TEST_F(DBTest, ConcurrentFlushWAL) {
|
||||
if (two_write_queues) {
|
||||
threads.emplace_back([&] {
|
||||
for (size_t i = cnt; i < 2 * cnt; i++) {
|
||||
auto istr = std::to_string(i);
|
||||
auto istr = ToString(i);
|
||||
WriteBatch batch;
|
||||
ASSERT_OK(batch.Put("a" + istr, "b" + istr));
|
||||
ASSERT_OK(
|
||||
@@ -4237,7 +4236,7 @@ TEST_F(DBTest, ConcurrentFlushWAL) {
|
||||
Reopen(options);
|
||||
for (size_t i = 0; i < cnt; i++) {
|
||||
PinnableSlice pval;
|
||||
auto istr = std::to_string(i);
|
||||
auto istr = ToString(i);
|
||||
ASSERT_OK(
|
||||
db_->Get(ropt, db_->DefaultColumnFamily(), "a" + istr, &pval));
|
||||
ASSERT_TRUE(pval == ("b" + istr));
|
||||
@@ -4260,7 +4259,7 @@ TEST_F(DBTest, ManualFlushWalAndWriteRace) {
|
||||
|
||||
port::Thread writeThread([&]() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
auto istr = std::to_string(i);
|
||||
auto istr = ToString(i);
|
||||
ASSERT_OK(dbfull()->Put(wopts, "key_" + istr, "value_" + istr));
|
||||
}
|
||||
});
|
||||
@@ -4608,7 +4607,7 @@ TEST_P(DBTestWithParam, ThreadStatusSingleCompaction) {
|
||||
// The Put Phase.
|
||||
for (int file = 0; file < kNumL0Files; ++file) {
|
||||
for (int key = 0; key < kEntriesPerBuffer; ++key) {
|
||||
ASSERT_OK(Put(std::to_string(key + file * kEntriesPerBuffer),
|
||||
ASSERT_OK(Put(ToString(key + file * kEntriesPerBuffer),
|
||||
rnd.RandomString(kTestValueSize)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
@@ -4759,7 +4758,7 @@ TEST_P(DBTestWithParam, PreShutdownMultipleCompaction) {
|
||||
int operation_count[ThreadStatus::NUM_OP_TYPES] = {0};
|
||||
for (int file = 0; file < 16 * kNumL0Files; ++file) {
|
||||
for (int k = 0; k < kEntriesPerBuffer; ++k) {
|
||||
ASSERT_OK(Put(std::to_string(key++), rnd.RandomString(kTestValueSize)));
|
||||
ASSERT_OK(Put(ToString(key++), rnd.RandomString(kTestValueSize)));
|
||||
}
|
||||
|
||||
ASSERT_OK(env_->GetThreadList(&thread_list));
|
||||
@@ -4846,7 +4845,7 @@ TEST_P(DBTestWithParam, PreShutdownCompactionMiddle) {
|
||||
int operation_count[ThreadStatus::NUM_OP_TYPES] = {0};
|
||||
for (int file = 0; file < 16 * kNumL0Files; ++file) {
|
||||
for (int k = 0; k < kEntriesPerBuffer; ++k) {
|
||||
ASSERT_OK(Put(std::to_string(key++), rnd.RandomString(kTestValueSize)));
|
||||
ASSERT_OK(Put(ToString(key++), rnd.RandomString(kTestValueSize)));
|
||||
}
|
||||
|
||||
ASSERT_OK(env_->GetThreadList(&thread_list));
|
||||
@@ -5157,9 +5156,8 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
// Writing to 64KB L0 files should trigger a compaction. Since these
|
||||
// 2 L0 files have the same key range, compaction merge them and should
|
||||
// result in 2 32KB L1 files.
|
||||
ASSERT_OK(
|
||||
dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "2"},
|
||||
{"target_file_size_base", std::to_string(k32KB)}}));
|
||||
ASSERT_OK(dbfull()->SetOptions({{"level0_file_num_compaction_trigger", "2"},
|
||||
{"target_file_size_base", ToString(k32KB)}}));
|
||||
|
||||
gen_l0_kb(0, 64, 1);
|
||||
ASSERT_EQ("1,1", FilesPerLevel());
|
||||
@@ -5178,8 +5176,8 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
// Increase level base size to 256KB and write enough data that will
|
||||
// fill L1 and L2. L1 size should be around 256KB while L2 size should be
|
||||
// around 256KB x 4.
|
||||
ASSERT_OK(dbfull()->SetOptions(
|
||||
{{"max_bytes_for_level_base", std::to_string(k1MB)}}));
|
||||
ASSERT_OK(
|
||||
dbfull()->SetOptions({{"max_bytes_for_level_base", ToString(k1MB)}}));
|
||||
|
||||
// writing 96 x 64KB => 6 * 1024KB
|
||||
// (L1 + L2) = (1 + 4) * 1024KB
|
||||
@@ -5198,9 +5196,9 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
// max_bytes_for_level_base. Now, reduce both mulitplier and level base,
|
||||
// After filling enough data that can fit in L1 - L3, we should see L1 size
|
||||
// reduces to 128KB from 256KB which was asserted previously. Same for L2.
|
||||
ASSERT_OK(dbfull()->SetOptions(
|
||||
{{"max_bytes_for_level_multiplier", "2"},
|
||||
{"max_bytes_for_level_base", std::to_string(k128KB)}}));
|
||||
ASSERT_OK(
|
||||
dbfull()->SetOptions({{"max_bytes_for_level_multiplier", "2"},
|
||||
{"max_bytes_for_level_base", ToString(k128KB)}}));
|
||||
|
||||
// writing 20 x 64KB = 10 x 128KB
|
||||
// (L1 + L2 + L3) = (1 + 2 + 4) * 128KB
|
||||
@@ -5856,7 +5854,7 @@ TEST_P(DBTestWithParam, FilterCompactionTimeTest) {
|
||||
// put some data
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
ASSERT_OK(Put(std::to_string(table * 100 + i), "val"));
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
++n;
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
@@ -6240,7 +6238,7 @@ TEST_F(DBTest, LargeBatchWithColumnFamilies) {
|
||||
(write_size / 1024 / 1024), pass);
|
||||
for (;;) {
|
||||
std::string data(3000, j++ % 127 + 20);
|
||||
data += std::to_string(j);
|
||||
data += ToString(j);
|
||||
ASSERT_OK(batch.Put(handles_[0], Slice(data), Slice(data)));
|
||||
if (batch.GetDataSize() > write_size) {
|
||||
break;
|
||||
|
||||
+111
-244
@@ -38,10 +38,10 @@ class DBTest2 : public DBTestBase {
|
||||
#ifndef ROCKSDB_LITE
|
||||
uint64_t GetSstSizeHelper(Temperature temperature) {
|
||||
std::string prop;
|
||||
EXPECT_TRUE(dbfull()->GetProperty(
|
||||
DB::Properties::kLiveSstFilesSizeAtTemperature +
|
||||
std::to_string(static_cast<uint8_t>(temperature)),
|
||||
&prop));
|
||||
EXPECT_TRUE(
|
||||
dbfull()->GetProperty(DB::Properties::kLiveSstFilesSizeAtTemperature +
|
||||
ToString(static_cast<uint8_t>(temperature)),
|
||||
&prop));
|
||||
return static_cast<uint64_t>(std::atoi(prop.c_str()));
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
@@ -1296,7 +1296,6 @@ TEST_F(DBTest2, PresetCompressionDict) {
|
||||
enum DictionaryTypes : int {
|
||||
kWithoutDict,
|
||||
kWithDict,
|
||||
kWithZSTDfinalizeDict,
|
||||
kWithZSTDTrainedDict,
|
||||
kDictEnd,
|
||||
};
|
||||
@@ -1305,7 +1304,6 @@ TEST_F(DBTest2, PresetCompressionDict) {
|
||||
options.compression = compression_type;
|
||||
size_t bytes_without_dict = 0;
|
||||
size_t bytes_with_dict = 0;
|
||||
size_t bytes_with_zstd_finalize_dict = 0;
|
||||
size_t bytes_with_zstd_trained_dict = 0;
|
||||
for (int i = kWithoutDict; i < kDictEnd; i++) {
|
||||
// First iteration: compress without preset dictionary
|
||||
@@ -1325,21 +1323,12 @@ TEST_F(DBTest2, PresetCompressionDict) {
|
||||
options.compression_opts.max_dict_bytes = kBlockSizeBytes;
|
||||
options.compression_opts.zstd_max_train_bytes = 0;
|
||||
break;
|
||||
case kWithZSTDfinalizeDict:
|
||||
if (compression_type != kZSTD) {
|
||||
continue;
|
||||
}
|
||||
options.compression_opts.max_dict_bytes = kBlockSizeBytes;
|
||||
options.compression_opts.zstd_max_train_bytes = kL0FileBytes;
|
||||
options.compression_opts.use_zstd_dict_trainer = false;
|
||||
break;
|
||||
case kWithZSTDTrainedDict:
|
||||
if (compression_type != kZSTD) {
|
||||
continue;
|
||||
}
|
||||
options.compression_opts.max_dict_bytes = kBlockSizeBytes;
|
||||
options.compression_opts.zstd_max_train_bytes = kL0FileBytes;
|
||||
options.compression_opts.use_zstd_dict_trainer = true;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
@@ -1376,8 +1365,6 @@ TEST_F(DBTest2, PresetCompressionDict) {
|
||||
bytes_without_dict = total_sst_bytes;
|
||||
} else if (i == kWithDict) {
|
||||
bytes_with_dict = total_sst_bytes;
|
||||
} else if (i == kWithZSTDfinalizeDict) {
|
||||
bytes_with_zstd_finalize_dict = total_sst_bytes;
|
||||
} else if (i == kWithZSTDTrainedDict) {
|
||||
bytes_with_zstd_trained_dict = total_sst_bytes;
|
||||
}
|
||||
@@ -1388,13 +1375,6 @@ TEST_F(DBTest2, PresetCompressionDict) {
|
||||
}
|
||||
if (i == kWithDict) {
|
||||
ASSERT_GT(bytes_without_dict, bytes_with_dict);
|
||||
} else if (i == kWithZSTDTrainedDict) {
|
||||
// In zstd compression, it is sometimes possible that using a finalized
|
||||
// dictionary does not get as good a compression ratio as raw content
|
||||
// dictionary. But using a dictionary should always get better
|
||||
// compression ratio than not using one.
|
||||
ASSERT_TRUE(bytes_with_dict > bytes_with_zstd_finalize_dict ||
|
||||
bytes_without_dict > bytes_with_zstd_finalize_dict);
|
||||
} else if (i == kWithZSTDTrainedDict) {
|
||||
// In zstd compression, it is sometimes possible that using a trained
|
||||
// dictionary does not get as good a compression ratio as without
|
||||
@@ -1714,9 +1694,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" + std::to_string(level),
|
||||
&files_at_level));
|
||||
ASSERT_TRUE(db->GetProperty(
|
||||
"rocksdb.num-files-at-level" + ROCKSDB_NAMESPACE::ToString(level),
|
||||
&files_at_level));
|
||||
if (files_at_level != "0") {
|
||||
bottommost_level = level;
|
||||
}
|
||||
@@ -2512,14 +2492,14 @@ TEST_F(DBTest2, TestPerfContextIterCpuTime) {
|
||||
|
||||
const size_t kNumEntries = 10;
|
||||
for (size_t i = 0; i < kNumEntries; ++i) {
|
||||
ASSERT_OK(Put("k" + std::to_string(i), "v" + std::to_string(i)));
|
||||
ASSERT_OK(Put("k" + ToString(i), "v" + ToString(i)));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
for (size_t i = 0; i < kNumEntries; ++i) {
|
||||
ASSERT_EQ("v" + std::to_string(i), Get("k" + std::to_string(i)));
|
||||
ASSERT_EQ("v" + ToString(i), Get("k" + ToString(i)));
|
||||
}
|
||||
std::string last_key = "k" + std::to_string(kNumEntries - 1);
|
||||
std::string last_value = "v" + std::to_string(kNumEntries - 1);
|
||||
std::string last_key = "k" + ToString(kNumEntries - 1);
|
||||
std::string last_value = "v" + ToString(kNumEntries - 1);
|
||||
env_->now_cpu_count_.store(0);
|
||||
env_->SetMockSleep();
|
||||
|
||||
@@ -4007,14 +3987,12 @@ TEST_F(DBTest2, RateLimitedCompactionReads) {
|
||||
|
||||
// should be slightly above 512KB due to non-data blocks read. Arbitrarily
|
||||
// chose 1MB as the upper bound on the total bytes read.
|
||||
size_t rate_limited_bytes = static_cast<size_t>(
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_TOTAL));
|
||||
// The charges can exist for `IO_LOW` and `IO_USER` priorities.
|
||||
size_t rate_limited_bytes_by_pri =
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_LOW) +
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_USER);
|
||||
size_t rate_limited_bytes =
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_TOTAL);
|
||||
// There must be no charges at non-`IO_LOW` priorities.
|
||||
ASSERT_EQ(rate_limited_bytes,
|
||||
static_cast<size_t>(rate_limited_bytes_by_pri));
|
||||
static_cast<size_t>(
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_LOW)));
|
||||
// Include the explicit prefetch of the footer in direct I/O case.
|
||||
size_t direct_io_extra = use_direct_io ? 512 * 1024 : 0;
|
||||
ASSERT_GE(
|
||||
@@ -4032,11 +4010,9 @@ TEST_F(DBTest2, RateLimitedCompactionReads) {
|
||||
}
|
||||
delete iter;
|
||||
// bytes read for user iterator shouldn't count against the rate limit.
|
||||
rate_limited_bytes_by_pri =
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_LOW) +
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_USER);
|
||||
ASSERT_EQ(rate_limited_bytes,
|
||||
static_cast<size_t>(rate_limited_bytes_by_pri));
|
||||
static_cast<size_t>(
|
||||
options.rate_limiter->GetTotalBytesThrough(Env::IO_LOW)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5577,7 +5553,7 @@ TEST_F(DBTest2, MultiDBParallelOpenTest) {
|
||||
Options options = CurrentOptions();
|
||||
std::vector<std::string> dbnames;
|
||||
for (int i = 0; i < kNumDbs; ++i) {
|
||||
dbnames.emplace_back(test::PerThreadDBPath(env_, "db" + std::to_string(i)));
|
||||
dbnames.emplace_back(test::PerThreadDBPath(env_, "db" + ToString(i)));
|
||||
ASSERT_OK(DestroyDB(dbnames.back(), options));
|
||||
}
|
||||
|
||||
@@ -6329,118 +6305,115 @@ TEST_F(DBTest2, BlockBasedTablePrefixGetIndexNotFound) {
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBTest2, AutoPrefixMode1) {
|
||||
do {
|
||||
// create a DB with block prefix index
|
||||
Options options = CurrentOptions();
|
||||
BlockBasedTableOptions table_options =
|
||||
*options.table_factory->GetOptions<BlockBasedTableOptions>();
|
||||
table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
|
||||
options.statistics = CreateDBStatistics();
|
||||
// create a DB with block prefix index
|
||||
BlockBasedTableOptions table_options;
|
||||
Options options = CurrentOptions();
|
||||
table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
|
||||
options.statistics = CreateDBStatistics();
|
||||
|
||||
Reopen(options);
|
||||
Reopen(options);
|
||||
|
||||
Random rnd(301);
|
||||
std::string large_value = rnd.RandomString(500);
|
||||
Random rnd(301);
|
||||
std::string large_value = rnd.RandomString(500);
|
||||
|
||||
ASSERT_OK(Put("a1", large_value));
|
||||
ASSERT_OK(Put("x1", large_value));
|
||||
ASSERT_OK(Put("y1", large_value));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put("a1", large_value));
|
||||
ASSERT_OK(Put("x1", large_value));
|
||||
ASSERT_OK(Put("y1", large_value));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ReadOptions ro;
|
||||
ro.total_order_seek = false;
|
||||
ro.auto_prefix_mode = true;
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("x1", iterator->key().ToString());
|
||||
ASSERT_EQ(0, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
ReadOptions ro;
|
||||
ro.total_order_seek = false;
|
||||
ro.auto_prefix_mode = true;
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("x1", iterator->key().ToString());
|
||||
ASSERT_EQ(0, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
|
||||
std::string ub_str = "b9";
|
||||
Slice ub(ub_str);
|
||||
std::string ub_str = "b9";
|
||||
Slice ub(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(1, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
|
||||
ub_str = "z";
|
||||
ub = Slice(ub_str);
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("x1", iterator->key().ToString());
|
||||
ASSERT_EQ(1, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
|
||||
ub_str = "c";
|
||||
ub = Slice(ub_str);
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(2, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
|
||||
// The same queries without recreating iterator
|
||||
{
|
||||
ub_str = "b9";
|
||||
ub = Slice(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(1, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(3, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
|
||||
ub_str = "z";
|
||||
ub = Slice(ub_str);
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("x1", iterator->key().ToString());
|
||||
ASSERT_EQ(1, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
|
||||
iterator->Seek("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("x1", iterator->key().ToString());
|
||||
ASSERT_EQ(3, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
|
||||
ub_str = "c";
|
||||
ub = Slice(ub_str);
|
||||
{
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(2, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
}
|
||||
|
||||
// The same queries without recreating iterator
|
||||
{
|
||||
ub_str = "b9";
|
||||
ub = Slice(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(4, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
|
||||
std::unique_ptr<Iterator> iterator(db_->NewIterator(ro));
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(3, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
ASSERT_OK(iterator->status());
|
||||
ub_str = "b9";
|
||||
ub = Slice(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
iterator->SeekForPrev("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("a1", iterator->key().ToString());
|
||||
ASSERT_EQ(4, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
|
||||
ub_str = "z";
|
||||
ub = Slice(ub_str);
|
||||
ub_str = "zz";
|
||||
ub = Slice(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
iterator->SeekToLast();
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("y1", iterator->key().ToString());
|
||||
|
||||
iterator->Seek("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("x1", iterator->key().ToString());
|
||||
ASSERT_EQ(3, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
|
||||
ub_str = "c";
|
||||
ub = Slice(ub_str);
|
||||
|
||||
iterator->Seek("b1");
|
||||
ASSERT_FALSE(iterator->Valid());
|
||||
ASSERT_EQ(4, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
|
||||
ub_str = "b9";
|
||||
ub = Slice(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
iterator->SeekForPrev("b1");
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("a1", iterator->key().ToString());
|
||||
ASSERT_EQ(4, TestGetTickerCount(options, BLOOM_FILTER_PREFIX_CHECKED));
|
||||
|
||||
ub_str = "zz";
|
||||
ub = Slice(ub_str);
|
||||
ro.iterate_upper_bound = &ub;
|
||||
iterator->SeekToLast();
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("y1", iterator->key().ToString());
|
||||
|
||||
iterator->SeekToFirst();
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("a1", iterator->key().ToString());
|
||||
}
|
||||
} while (ChangeOptions(kSkipPlainTable));
|
||||
iterator->SeekToFirst();
|
||||
ASSERT_TRUE(iterator->Valid());
|
||||
ASSERT_EQ("a1", iterator->key().ToString());
|
||||
}
|
||||
}
|
||||
|
||||
class RenameCurrentTest : public DBTestBase,
|
||||
@@ -7172,112 +7145,6 @@ TEST_F(DBTest2, RenameDirectory) {
|
||||
dbname_ = old_dbname;
|
||||
}
|
||||
|
||||
TEST_F(DBTest2, SstUniqueIdVerifyBackwardCompatible) {
|
||||
const int kNumSst = 3;
|
||||
const int kLevel0Trigger = 4;
|
||||
auto options = CurrentOptions();
|
||||
options.level0_file_num_compaction_trigger = kLevel0Trigger;
|
||||
options.statistics = CreateDBStatistics();
|
||||
|
||||
// Existing manifest doesn't have unique id
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionEdit::EncodeTo:UniqueId", [&](void* arg) {
|
||||
auto unique_id = static_cast<UniqueId64x2*>(arg);
|
||||
// remove id before writing it to manifest
|
||||
(*unique_id)[0] = 0;
|
||||
(*unique_id)[1] = 0;
|
||||
});
|
||||
std::atomic_int skipped = 0;
|
||||
SyncPoint::GetInstance()->SetCallBack("Version::VerifySstUniqueIds::Skipped",
|
||||
[&](void* /*arg*/) { skipped++; });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// generate a few SSTs
|
||||
for (int i = 0; i < kNumSst; i++) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
ASSERT_OK(Put(Key(i * 10 + j), "value"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
// Reopen without verification
|
||||
Reopen(options);
|
||||
|
||||
// Reopen with verification, but it's skipped because manifest doesn't have id
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
Reopen(options);
|
||||
ASSERT_EQ(skipped, kNumSst);
|
||||
|
||||
// test compaction generated Sst
|
||||
for (int i = kNumSst; i < kLevel0Trigger; i++) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
ASSERT_OK(Put(Key(i * 10 + j), "value"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ("0,1", FilesPerLevel(0));
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Reopen with verification should fail
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
skipped = 0;
|
||||
Reopen(options);
|
||||
ASSERT_EQ(skipped, 1);
|
||||
}
|
||||
|
||||
TEST_F(DBTest2, SstUniqueIdVerify) {
|
||||
const int kNumSst = 3;
|
||||
const int kLevel0Trigger = 4;
|
||||
auto options = CurrentOptions();
|
||||
options.level0_file_num_compaction_trigger = kLevel0Trigger;
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"PropertyBlockBuilder::AddTableProperty:Start", [&](void* props_vs) {
|
||||
auto props = static_cast<TableProperties*>(props_vs);
|
||||
// update table property session_id to a different one
|
||||
props->db_session_id = DBImpl::GenerateDbSessionId(nullptr);
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// generate a few SSTs
|
||||
for (int i = 0; i < kNumSst; i++) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
ASSERT_OK(Put(Key(i * 10 + j), "value"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
// Reopen with verification should report corruption
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
auto s = TryReopen(options);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
|
||||
// Reopen without verification should be fine
|
||||
options.verify_sst_unique_id_in_manifest = false;
|
||||
Reopen(options);
|
||||
|
||||
// test compaction generated Sst
|
||||
for (int i = kNumSst; i < kLevel0Trigger; i++) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
ASSERT_OK(Put(Key(i * 10 + j), "value"));
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
ASSERT_EQ("0,1", FilesPerLevel(0));
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Reopen with verification should fail
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
s = TryReopen(options);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
TEST_F(DBTest2, GetLatestSeqAndTsForKey) {
|
||||
Destroy(last_options_);
|
||||
|
||||
+19
-101
@@ -9,11 +9,8 @@
|
||||
|
||||
#include "db/db_test_util.h"
|
||||
|
||||
#include "cache/cache_reservation_manager.h"
|
||||
#include "db/forward_iterator.h"
|
||||
#include "env/mock_env.h"
|
||||
#include "port/lang.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/env_encryption.h"
|
||||
#include "rocksdb/unique_id.h"
|
||||
@@ -363,17 +360,6 @@ Options DBTestBase::GetOptions(
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearCallBack(
|
||||
"NewWritableFile:O_DIRECT");
|
||||
#endif
|
||||
// kMustFreeHeapAllocations -> indicates ASAN build
|
||||
if (kMustFreeHeapAllocations && !options_override.full_block_cache) {
|
||||
// Detecting block cache use-after-free is normally difficult in unit
|
||||
// tests, because as a cache, it tends to keep unreferenced entries in
|
||||
// memory, and we normally want unit tests to take advantage of block
|
||||
// cache for speed. However, we also want a strong chance of detecting
|
||||
// block cache use-after-free in unit tests in ASAN builds, so for ASAN
|
||||
// builds we use a trivially small block cache to which entries can be
|
||||
// added but are immediately freed on no more references.
|
||||
table_options.block_cache = NewLRUCache(/* too small */ 1);
|
||||
}
|
||||
|
||||
bool can_allow_mmap = IsMemoryMappedAccessSupported();
|
||||
switch (option_config) {
|
||||
@@ -830,12 +816,10 @@ std::string DBTestBase::Get(int cf, const std::string& k,
|
||||
std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
|
||||
const std::vector<std::string>& k,
|
||||
const Snapshot* snapshot,
|
||||
const bool batched,
|
||||
const bool async) {
|
||||
const bool batched) {
|
||||
ReadOptions options;
|
||||
options.verify_checksums = true;
|
||||
options.snapshot = snapshot;
|
||||
options.async_io = async;
|
||||
std::vector<ColumnFamilyHandle*> handles;
|
||||
std::vector<Slice> keys;
|
||||
std::vector<std::string> result;
|
||||
@@ -847,7 +831,7 @@ std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
|
||||
std::vector<Status> s;
|
||||
if (!batched) {
|
||||
s = db_->MultiGet(options, handles, keys, &result);
|
||||
for (size_t i = 0; i < s.size(); ++i) {
|
||||
for (unsigned int i = 0; i < s.size(); ++i) {
|
||||
if (s[i].IsNotFound()) {
|
||||
result[i] = "NOT_FOUND";
|
||||
} else if (!s[i].ok()) {
|
||||
@@ -860,16 +844,13 @@ std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
|
||||
s.resize(cfs.size());
|
||||
db_->MultiGet(options, cfs.size(), handles.data(), keys.data(),
|
||||
pin_values.data(), s.data());
|
||||
for (size_t i = 0; i < s.size(); ++i) {
|
||||
for (unsigned int i = 0; i < s.size(); ++i) {
|
||||
if (s[i].IsNotFound()) {
|
||||
result[i] = "NOT_FOUND";
|
||||
} else if (!s[i].ok()) {
|
||||
result[i] = s[i].ToString();
|
||||
} else {
|
||||
result[i].assign(pin_values[i].data(), pin_values[i].size());
|
||||
// Increase likelihood of detecting potential use-after-free bugs with
|
||||
// PinnableSlices tracking the same resource
|
||||
pin_values[i].Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -877,32 +858,28 @@ std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
|
||||
}
|
||||
|
||||
std::vector<std::string> DBTestBase::MultiGet(const std::vector<std::string>& k,
|
||||
const Snapshot* snapshot,
|
||||
const bool async) {
|
||||
const Snapshot* snapshot) {
|
||||
ReadOptions options;
|
||||
options.verify_checksums = true;
|
||||
options.snapshot = snapshot;
|
||||
options.async_io = async;
|
||||
std::vector<Slice> keys;
|
||||
std::vector<std::string> result(k.size());
|
||||
std::vector<std::string> result;
|
||||
std::vector<Status> statuses(k.size());
|
||||
std::vector<PinnableSlice> pin_values(k.size());
|
||||
|
||||
for (size_t i = 0; i < k.size(); ++i) {
|
||||
for (unsigned int i = 0; i < k.size(); ++i) {
|
||||
keys.push_back(k[i]);
|
||||
}
|
||||
db_->MultiGet(options, dbfull()->DefaultColumnFamily(), keys.size(),
|
||||
keys.data(), pin_values.data(), statuses.data());
|
||||
for (size_t i = 0; i < statuses.size(); ++i) {
|
||||
result.resize(k.size());
|
||||
for (auto iter = result.begin(); iter != result.end(); ++iter) {
|
||||
iter->assign(pin_values[iter - result.begin()].data(),
|
||||
pin_values[iter - result.begin()].size());
|
||||
}
|
||||
for (unsigned int i = 0; i < statuses.size(); ++i) {
|
||||
if (statuses[i].IsNotFound()) {
|
||||
result[i] = "NOT_FOUND";
|
||||
} else if (!statuses[i].ok()) {
|
||||
result[i] = statuses[i].ToString();
|
||||
} else {
|
||||
result[i].assign(pin_values[i].data(), pin_values[i].size());
|
||||
// Increase likelihood of detecting potential use-after-free bugs with
|
||||
// PinnableSlices tracking the same resource
|
||||
pin_values[i].Reset();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -1091,12 +1068,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" + std::to_string(level), &property));
|
||||
EXPECT_TRUE(db_->GetProperty("rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
} else {
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
handles_[cf], "rocksdb.num-files-at-level" + std::to_string(level),
|
||||
&property));
|
||||
EXPECT_TRUE(db_->GetProperty(handles_[cf],
|
||||
"rocksdb.num-files-at-level" + ToString(level),
|
||||
&property));
|
||||
}
|
||||
return atoi(property.c_str());
|
||||
}
|
||||
@@ -1106,12 +1083,10 @@ double DBTestBase::CompressionRatioAtLevel(int level, int cf) {
|
||||
if (cf == 0) {
|
||||
// default cfd
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
"rocksdb.compression-ratio-at-level" + std::to_string(level),
|
||||
&property));
|
||||
"rocksdb.compression-ratio-at-level" + ToString(level), &property));
|
||||
} else {
|
||||
EXPECT_TRUE(db_->GetProperty(
|
||||
handles_[cf],
|
||||
"rocksdb.compression-ratio-at-level" + std::to_string(level),
|
||||
handles_[cf], "rocksdb.compression-ratio-at-level" + ToString(level),
|
||||
&property));
|
||||
}
|
||||
return std::stod(property);
|
||||
@@ -1688,61 +1663,4 @@ void VerifySstUniqueIds(const TablePropertiesCollection& props) {
|
||||
}
|
||||
}
|
||||
|
||||
template <CacheEntryRole R>
|
||||
TargetCacheChargeTrackingCache<R>::TargetCacheChargeTrackingCache(
|
||||
std::shared_ptr<Cache> target)
|
||||
: CacheWrapper(std::move(target)),
|
||||
cur_cache_charge_(0),
|
||||
cache_charge_peak_(0),
|
||||
cache_charge_increment_(0),
|
||||
last_peak_tracked_(false),
|
||||
cache_charge_increments_sum_(0) {}
|
||||
|
||||
template <CacheEntryRole R>
|
||||
Status TargetCacheChargeTrackingCache<R>::Insert(
|
||||
const Slice& key, void* value, size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value), Handle** handle,
|
||||
Priority priority) {
|
||||
Status s = target_->Insert(key, value, charge, deleter, handle, priority);
|
||||
if (deleter == kNoopDeleter) {
|
||||
if (last_peak_tracked_) {
|
||||
cache_charge_peak_ = 0;
|
||||
cache_charge_increment_ = 0;
|
||||
last_peak_tracked_ = false;
|
||||
}
|
||||
if (s.ok()) {
|
||||
cur_cache_charge_ += charge;
|
||||
}
|
||||
cache_charge_peak_ = std::max(cache_charge_peak_, cur_cache_charge_);
|
||||
cache_charge_increment_ += charge;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
template <CacheEntryRole R>
|
||||
bool TargetCacheChargeTrackingCache<R>::Release(Handle* handle,
|
||||
bool erase_if_last_ref) {
|
||||
auto deleter = GetDeleter(handle);
|
||||
if (deleter == kNoopDeleter) {
|
||||
if (!last_peak_tracked_) {
|
||||
cache_charge_peaks_.push_back(cache_charge_peak_);
|
||||
cache_charge_increments_sum_ += cache_charge_increment_;
|
||||
last_peak_tracked_ = true;
|
||||
}
|
||||
cur_cache_charge_ -= GetCharge(handle);
|
||||
}
|
||||
bool is_successful = target_->Release(handle, erase_if_last_ref);
|
||||
return is_successful;
|
||||
}
|
||||
|
||||
template <CacheEntryRole R>
|
||||
const Cache::DeleterFn TargetCacheChargeTrackingCache<R>::kNoopDeleter =
|
||||
CacheReservationManagerImpl<R>::TEST_GetNoopDeleterForRole();
|
||||
|
||||
template class TargetCacheChargeTrackingCache<
|
||||
CacheEntryRole::kFilterConstruction>;
|
||||
template class TargetCacheChargeTrackingCache<
|
||||
CacheEntryRole::kBlockBasedTableReader>;
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+2
-52
@@ -104,9 +104,6 @@ struct OptionsOverride {
|
||||
std::shared_ptr<const FilterPolicy> filter_policy = nullptr;
|
||||
// These will be used only if filter_policy is set
|
||||
bool partition_filters = false;
|
||||
// Force using a default block cache. (Setting to false allows ASAN build
|
||||
// use a trivially small block cache for better UAF error detection.)
|
||||
bool full_block_cache = false;
|
||||
uint64_t metadata_block_size = 1024;
|
||||
|
||||
// Used as a bit mask of individual enums in which to skip an XF test point
|
||||
@@ -952,51 +949,6 @@ class CacheWrapper : public Cache {
|
||||
std::shared_ptr<Cache> target_;
|
||||
};
|
||||
|
||||
/*
|
||||
* A cache wrapper that tracks certain CacheEntryRole's cache charge, its
|
||||
* peaks and increments
|
||||
*
|
||||
* p0
|
||||
* / \ p1
|
||||
* / \ /\
|
||||
* / \/ \
|
||||
* a / b \
|
||||
* peaks = {p0, p1}
|
||||
* increments = {p1-a, p2-b}
|
||||
*/
|
||||
template <CacheEntryRole R>
|
||||
class TargetCacheChargeTrackingCache : public CacheWrapper {
|
||||
public:
|
||||
explicit TargetCacheChargeTrackingCache(std::shared_ptr<Cache> target);
|
||||
|
||||
using Cache::Insert;
|
||||
Status Insert(const Slice& key, void* value, size_t charge,
|
||||
void (*deleter)(const Slice& key, void* value),
|
||||
Handle** handle = nullptr,
|
||||
Priority priority = Priority::LOW) override;
|
||||
|
||||
using Cache::Release;
|
||||
bool Release(Handle* handle, bool erase_if_last_ref = false) override;
|
||||
|
||||
std::size_t GetCacheCharge() { return cur_cache_charge_; }
|
||||
|
||||
std::deque<std::size_t> GetChargedCachePeaks() { return cache_charge_peaks_; }
|
||||
|
||||
std::size_t GetChargedCacheIncrementSum() {
|
||||
return cache_charge_increments_sum_;
|
||||
}
|
||||
|
||||
private:
|
||||
static const Cache::DeleterFn kNoopDeleter;
|
||||
|
||||
std::size_t cur_cache_charge_;
|
||||
std::size_t cache_charge_peak_;
|
||||
std::size_t cache_charge_increment_;
|
||||
bool last_peak_tracked_;
|
||||
std::deque<std::size_t> cache_charge_peaks_;
|
||||
std::size_t cache_charge_increments_sum_;
|
||||
};
|
||||
|
||||
class DBTestBase : public testing::Test {
|
||||
public:
|
||||
// Sequence of option configurations to try
|
||||
@@ -1199,12 +1151,10 @@ class DBTestBase : public testing::Test {
|
||||
std::vector<std::string> MultiGet(std::vector<int> cfs,
|
||||
const std::vector<std::string>& k,
|
||||
const Snapshot* snapshot,
|
||||
const bool batched,
|
||||
const bool async = false);
|
||||
const bool batched);
|
||||
|
||||
std::vector<std::string> MultiGet(const std::vector<std::string>& k,
|
||||
const Snapshot* snapshot = nullptr,
|
||||
const bool async = false);
|
||||
const Snapshot* snapshot = nullptr);
|
||||
|
||||
uint64_t GetNumSnapshots();
|
||||
|
||||
|
||||
@@ -549,7 +549,7 @@ TEST_P(DBTestUniversalCompaction, CompactFilesOnUniversalCompaction) {
|
||||
ASSERT_EQ(options.compaction_style, kCompactionStyleUniversal);
|
||||
Random rnd(301);
|
||||
for (int key = 1024 * kEntriesPerBuffer; key >= 0; --key) {
|
||||
ASSERT_OK(Put(1, std::to_string(key), rnd.RandomString(kTestValueSize)));
|
||||
ASSERT_OK(Put(1, ToString(key), rnd.RandomString(kTestValueSize)));
|
||||
}
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(handles_[1]));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
+7
-60
@@ -1009,7 +1009,7 @@ TEST_F(DBWALTest, RecoveryWithLogDataForSomeCFs) {
|
||||
if (log_files.size() > 0) {
|
||||
earliest_log_nums[i] = log_files[0]->LogNumber();
|
||||
} else {
|
||||
earliest_log_nums[i] = std::numeric_limits<uint64_t>::max();
|
||||
earliest_log_nums[i] = port::kMaxUint64;
|
||||
}
|
||||
}
|
||||
// Check at least the first WAL was cleaned up during the recovery.
|
||||
@@ -1288,7 +1288,7 @@ class RecoveryTestHelper {
|
||||
|
||||
WriteBatch batch;
|
||||
for (int i = 0; i < kKeysPerWALFile; i++) {
|
||||
std::string key = "key" + std::to_string((*count)++);
|
||||
std::string key = "key" + ToString((*count)++);
|
||||
std::string value = test->DummyString(kValueSize);
|
||||
ASSERT_NE(current_log_writer.get(), nullptr);
|
||||
uint64_t seq = versions->LastSequence() + 1;
|
||||
@@ -1319,7 +1319,7 @@ class RecoveryTestHelper {
|
||||
static size_t GetData(DBWALTestBase* test) {
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < kWALFilesCount * kKeysPerWALFile; i++) {
|
||||
if (test->Get("key" + std::to_string(i)) != "NOT_FOUND") {
|
||||
if (test->Get("key" + ToString(i)) != "NOT_FOUND") {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
@@ -1616,7 +1616,7 @@ TEST_P(DBWALTestWithParams, kPointInTimeRecovery) {
|
||||
if (!trunc || corrupt_offset != 0) {
|
||||
bool expect_data = true;
|
||||
for (size_t k = 0; k < maxkeys; ++k) {
|
||||
bool found = Get("key" + std::to_string(k)) != "NOT_FOUND";
|
||||
bool found = Get("key" + ToString(k)) != "NOT_FOUND";
|
||||
if (expect_data && !found) {
|
||||
expect_data = false;
|
||||
}
|
||||
@@ -1752,7 +1752,7 @@ TEST_F(DBWALTest, RecoverWithoutFlush) {
|
||||
size_t count = RecoveryTestHelper::FillData(this, &options);
|
||||
auto validateData = [this, count]() {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
ASSERT_NE(Get("key" + std::to_string(i)), "NOT_FOUND");
|
||||
ASSERT_NE(Get("key" + ToString(i)), "NOT_FOUND");
|
||||
}
|
||||
};
|
||||
Reopen(options);
|
||||
@@ -1891,7 +1891,7 @@ TEST_P(DBWALTestWithParamsVaryingRecoveryMode,
|
||||
ASSERT_OK(TryReopen(options));
|
||||
// Append some more data.
|
||||
for (int k = 0; k < kAppendKeys; k++) {
|
||||
std::string key = "extra_key" + std::to_string(k);
|
||||
std::string key = "extra_key" + ToString(k);
|
||||
std::string value = DummyString(RecoveryTestHelper::kValueSize);
|
||||
ASSERT_OK(Put(key, value));
|
||||
}
|
||||
@@ -1925,7 +1925,7 @@ TEST_F(DBWALTest, RestoreTotalLogSizeAfterRecoverWithoutFlush) {
|
||||
std::string value_300k(300 * kKB, 'v');
|
||||
ASSERT_OK(Put(0, "foo", "v1"));
|
||||
for (int i = 0; i < 9; i++) {
|
||||
ASSERT_OK(Put(1, "key" + std::to_string(i), value_100k));
|
||||
ASSERT_OK(Put(1, "key" + ToString(i), value_100k));
|
||||
}
|
||||
// Get log files before reopen.
|
||||
VectorLogPtr log_files_before;
|
||||
@@ -2165,59 +2165,6 @@ TEST_F(DBWALTest, ReadOnlyRecoveryNoTruncate) {
|
||||
#endif // ROCKSDB_FALLOCATE_PRESENT
|
||||
#endif // ROCKSDB_PLATFORM_POSIX
|
||||
|
||||
TEST_F(DBWALTest, WalInManifestButNotInSortedWals) {
|
||||
Options options = CurrentOptions();
|
||||
options.track_and_verify_wals_in_manifest = true;
|
||||
options.wal_recovery_mode = WALRecoveryMode::kAbsoluteConsistency;
|
||||
|
||||
// Build a way to make wal files selectively go missing
|
||||
bool wals_go_missing = false;
|
||||
struct MissingWalFs : public FileSystemWrapper {
|
||||
MissingWalFs(const std::shared_ptr<FileSystem>& t,
|
||||
bool* _wals_go_missing_flag)
|
||||
: FileSystemWrapper(t), wals_go_missing_flag(_wals_go_missing_flag) {}
|
||||
bool* wals_go_missing_flag;
|
||||
IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts,
|
||||
std::vector<std::string>* r,
|
||||
IODebugContext* dbg) override {
|
||||
IOStatus s = target_->GetChildren(dir, io_opts, r, dbg);
|
||||
if (s.ok() && *wals_go_missing_flag) {
|
||||
for (size_t i = 0; i < r->size();) {
|
||||
if (EndsWith(r->at(i), ".log")) {
|
||||
r->erase(r->begin() + i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
const char* Name() const override { return "MissingWalFs"; }
|
||||
};
|
||||
auto my_fs =
|
||||
std::make_shared<MissingWalFs>(env_->GetFileSystem(), &wals_go_missing);
|
||||
std::unique_ptr<Env> my_env(NewCompositeEnv(my_fs));
|
||||
options.env = my_env.get();
|
||||
|
||||
CreateAndReopenWithCF({"blah"}, options);
|
||||
|
||||
// Currently necessary to get a WAL tracked in manifest; see
|
||||
// https://github.com/facebook/rocksdb/issues/10080
|
||||
ASSERT_OK(Put(0, "x", "y"));
|
||||
ASSERT_OK(db_->SyncWAL());
|
||||
ASSERT_OK(Put(1, "x", "y"));
|
||||
ASSERT_OK(db_->SyncWAL());
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
ASSERT_FALSE(dbfull()->GetVersionSet()->GetWalSet().GetWals().empty());
|
||||
std::vector<std::unique_ptr<LogFile>> wals;
|
||||
ASSERT_OK(db_->GetSortedWalFiles(wals));
|
||||
wals_go_missing = true;
|
||||
ASSERT_NOK(db_->GetSortedWalFiles(wals));
|
||||
wals_go_missing = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
TEST_F(DBWALTest, WalTermTest) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// 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 "db/db_with_timestamp_test_util.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "rocksdb/utilities/debug.h"
|
||||
@@ -20,6 +20,176 @@
|
||||
#include "utilities/fault_injection_env.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class DBBasicTestWithTimestampBase : public DBTestBase {
|
||||
public:
|
||||
explicit DBBasicTestWithTimestampBase(const std::string& dbname)
|
||||
: DBTestBase(dbname, /*env_do_fsync=*/true) {}
|
||||
|
||||
protected:
|
||||
static std::string Key1(uint64_t k) {
|
||||
std::string ret;
|
||||
PutFixed64(&ret, k);
|
||||
std::reverse(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::string KeyWithPrefix(std::string prefix, uint64_t k) {
|
||||
std::string ret;
|
||||
PutFixed64(&ret, k);
|
||||
std::reverse(ret.begin(), ret.end());
|
||||
return prefix + ret;
|
||||
}
|
||||
|
||||
static std::vector<Slice> ConvertStrToSlice(
|
||||
std::vector<std::string>& strings) {
|
||||
std::vector<Slice> ret;
|
||||
for (const auto& s : strings) {
|
||||
ret.emplace_back(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
class TestComparator : public Comparator {
|
||||
private:
|
||||
const Comparator* cmp_without_ts_;
|
||||
|
||||
public:
|
||||
explicit TestComparator(size_t ts_sz)
|
||||
: Comparator(ts_sz), cmp_without_ts_(nullptr) {
|
||||
cmp_without_ts_ = BytewiseComparator();
|
||||
}
|
||||
|
||||
const char* Name() const override { return "TestComparator"; }
|
||||
|
||||
void FindShortSuccessor(std::string*) const override {}
|
||||
|
||||
void FindShortestSeparator(std::string*, const Slice&) const override {}
|
||||
|
||||
int Compare(const Slice& a, const Slice& b) const override {
|
||||
int r = CompareWithoutTimestamp(a, b);
|
||||
if (r != 0 || 0 == timestamp_size()) {
|
||||
return r;
|
||||
}
|
||||
return -CompareTimestamp(
|
||||
Slice(a.data() + a.size() - timestamp_size(), timestamp_size()),
|
||||
Slice(b.data() + b.size() - timestamp_size(), timestamp_size()));
|
||||
}
|
||||
|
||||
using Comparator::CompareWithoutTimestamp;
|
||||
int CompareWithoutTimestamp(const Slice& a, bool a_has_ts, const Slice& b,
|
||||
bool b_has_ts) const override {
|
||||
if (a_has_ts) {
|
||||
assert(a.size() >= timestamp_size());
|
||||
}
|
||||
if (b_has_ts) {
|
||||
assert(b.size() >= timestamp_size());
|
||||
}
|
||||
Slice lhs = a_has_ts ? StripTimestampFromUserKey(a, timestamp_size()) : a;
|
||||
Slice rhs = b_has_ts ? StripTimestampFromUserKey(b, timestamp_size()) : b;
|
||||
return cmp_without_ts_->Compare(lhs, rhs);
|
||||
}
|
||||
|
||||
int CompareTimestamp(const Slice& ts1, const Slice& ts2) const override {
|
||||
if (!ts1.data() && !ts2.data()) {
|
||||
return 0;
|
||||
} else if (ts1.data() && !ts2.data()) {
|
||||
return 1;
|
||||
} else if (!ts1.data() && ts2.data()) {
|
||||
return -1;
|
||||
}
|
||||
assert(ts1.size() == ts2.size());
|
||||
uint64_t low1 = 0;
|
||||
uint64_t low2 = 0;
|
||||
uint64_t high1 = 0;
|
||||
uint64_t high2 = 0;
|
||||
const size_t kSize = ts1.size();
|
||||
std::unique_ptr<char[]> ts1_buf(new char[kSize]);
|
||||
memcpy(ts1_buf.get(), ts1.data(), ts1.size());
|
||||
std::unique_ptr<char[]> ts2_buf(new char[kSize]);
|
||||
memcpy(ts2_buf.get(), ts2.data(), ts2.size());
|
||||
Slice ts1_copy = Slice(ts1_buf.get(), kSize);
|
||||
Slice ts2_copy = Slice(ts2_buf.get(), kSize);
|
||||
auto* ptr1 = const_cast<Slice*>(&ts1_copy);
|
||||
auto* ptr2 = const_cast<Slice*>(&ts2_copy);
|
||||
if (!GetFixed64(ptr1, &low1) || !GetFixed64(ptr1, &high1) ||
|
||||
!GetFixed64(ptr2, &low2) || !GetFixed64(ptr2, &high2)) {
|
||||
assert(false);
|
||||
}
|
||||
if (high1 < high2) {
|
||||
return -1;
|
||||
} else if (high1 > high2) {
|
||||
return 1;
|
||||
}
|
||||
if (low1 < low2) {
|
||||
return -1;
|
||||
} else if (low1 > low2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
std::string Timestamp(uint64_t low, uint64_t high) {
|
||||
std::string ts;
|
||||
PutFixed64(&ts, low);
|
||||
PutFixed64(&ts, high);
|
||||
return ts;
|
||||
}
|
||||
|
||||
void CheckIterUserEntry(const Iterator* it, const Slice& expected_key,
|
||||
ValueType expected_value_type,
|
||||
const Slice& expected_value,
|
||||
const Slice& expected_ts) const {
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
ASSERT_EQ(expected_key, it->key());
|
||||
if (kTypeValue == expected_value_type) {
|
||||
ASSERT_EQ(expected_value, it->value());
|
||||
}
|
||||
ASSERT_EQ(expected_ts, it->timestamp());
|
||||
}
|
||||
|
||||
void CheckIterEntry(const Iterator* it, const Slice& expected_ukey,
|
||||
SequenceNumber expected_seq, ValueType expected_val_type,
|
||||
const Slice& expected_value, const Slice& expected_ts) {
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
std::string ukey_and_ts;
|
||||
ukey_and_ts.assign(expected_ukey.data(), expected_ukey.size());
|
||||
ukey_and_ts.append(expected_ts.data(), expected_ts.size());
|
||||
ParsedInternalKey parsed_ikey;
|
||||
ASSERT_OK(
|
||||
ParseInternalKey(it->key(), &parsed_ikey, true /* log_err_key */));
|
||||
ASSERT_EQ(ukey_and_ts, parsed_ikey.user_key);
|
||||
ASSERT_EQ(expected_val_type, parsed_ikey.type);
|
||||
ASSERT_EQ(expected_seq, parsed_ikey.sequence);
|
||||
if (expected_val_type == kTypeValue) {
|
||||
ASSERT_EQ(expected_value, it->value());
|
||||
}
|
||||
ASSERT_EQ(expected_ts, it->timestamp());
|
||||
}
|
||||
|
||||
void CheckIterEntry(const Iterator* it, const Slice& expected_ukey,
|
||||
ValueType expected_val_type, const Slice& expected_value,
|
||||
const Slice& expected_ts) {
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
std::string ukey_and_ts;
|
||||
ukey_and_ts.assign(expected_ukey.data(), expected_ukey.size());
|
||||
ukey_and_ts.append(expected_ts.data(), expected_ts.size());
|
||||
|
||||
ParsedInternalKey parsed_ikey;
|
||||
ASSERT_OK(
|
||||
ParseInternalKey(it->key(), &parsed_ikey, true /* log_err_key */));
|
||||
ASSERT_EQ(expected_val_type, parsed_ikey.type);
|
||||
ASSERT_EQ(Slice(ukey_and_ts), parsed_ikey.user_key);
|
||||
if (expected_val_type == kTypeValue) {
|
||||
ASSERT_EQ(expected_value, it->value());
|
||||
}
|
||||
ASSERT_EQ(expected_ts, it->timestamp());
|
||||
}
|
||||
};
|
||||
|
||||
class DBBasicTestWithTimestamp : public DBBasicTestWithTimestampBase {
|
||||
public:
|
||||
DBBasicTestWithTimestamp()
|
||||
@@ -1322,8 +1492,8 @@ TEST_F(DBBasicTestWithTimestamp, MultiGetRangeFiltering) {
|
||||
|
||||
// random data
|
||||
for (int i = 0; i < 3; i++) {
|
||||
auto key = std::to_string(i * 10);
|
||||
auto value = std::to_string(i * 10);
|
||||
auto key = ToString(i * 10);
|
||||
auto value = ToString(i * 10);
|
||||
Slice key_slice = key;
|
||||
Slice value_slice = value;
|
||||
ASSERT_OK(db_->Put(write_opts, key_slice, ts, value_slice));
|
||||
@@ -1654,8 +1824,8 @@ class DataVisibilityTest : public DBBasicTestWithTimestampBase {
|
||||
DataVisibilityTest() : DBBasicTestWithTimestampBase("data_visibility_test") {
|
||||
// Initialize test data
|
||||
for (int i = 0; i < kTestDataSize; i++) {
|
||||
test_data_[i].key = "key" + std::to_string(i);
|
||||
test_data_[i].value = "value" + std::to_string(i);
|
||||
test_data_[i].key = "key" + ToString(i);
|
||||
test_data_[i].value = "value" + ToString(i);
|
||||
test_data_[i].timestamp = Timestamp(i, 0);
|
||||
test_data_[i].ts = i;
|
||||
test_data_[i].seq_num = kMaxSequenceNumber;
|
||||
|
||||
@@ -1,96 +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 "db/db_with_timestamp_test_util.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
std::string DBBasicTestWithTimestampBase::Key1(uint64_t k) {
|
||||
std::string ret;
|
||||
PutFixed64(&ret, k);
|
||||
std::reverse(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string DBBasicTestWithTimestampBase::KeyWithPrefix(std::string prefix,
|
||||
uint64_t k) {
|
||||
std::string ret;
|
||||
PutFixed64(&ret, k);
|
||||
std::reverse(ret.begin(), ret.end());
|
||||
return prefix + ret;
|
||||
}
|
||||
|
||||
std::vector<Slice> DBBasicTestWithTimestampBase::ConvertStrToSlice(
|
||||
std::vector<std::string>& strings) {
|
||||
std::vector<Slice> ret;
|
||||
for (const auto& s : strings) {
|
||||
ret.emplace_back(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string DBBasicTestWithTimestampBase::Timestamp(uint64_t low,
|
||||
uint64_t high) {
|
||||
std::string ts;
|
||||
PutFixed64(&ts, low);
|
||||
PutFixed64(&ts, high);
|
||||
return ts;
|
||||
}
|
||||
|
||||
void DBBasicTestWithTimestampBase::CheckIterUserEntry(
|
||||
const Iterator* it, const Slice& expected_key,
|
||||
ValueType expected_value_type, const Slice& expected_value,
|
||||
const Slice& expected_ts) const {
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
ASSERT_EQ(expected_key, it->key());
|
||||
if (kTypeValue == expected_value_type) {
|
||||
ASSERT_EQ(expected_value, it->value());
|
||||
}
|
||||
ASSERT_EQ(expected_ts, it->timestamp());
|
||||
}
|
||||
|
||||
void DBBasicTestWithTimestampBase::CheckIterEntry(
|
||||
const Iterator* it, const Slice& expected_ukey, SequenceNumber expected_seq,
|
||||
ValueType expected_val_type, const Slice& expected_value,
|
||||
const Slice& expected_ts) const {
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
std::string ukey_and_ts;
|
||||
ukey_and_ts.assign(expected_ukey.data(), expected_ukey.size());
|
||||
ukey_and_ts.append(expected_ts.data(), expected_ts.size());
|
||||
ParsedInternalKey parsed_ikey;
|
||||
ASSERT_OK(ParseInternalKey(it->key(), &parsed_ikey, true /* log_err_key */));
|
||||
ASSERT_EQ(ukey_and_ts, parsed_ikey.user_key);
|
||||
ASSERT_EQ(expected_val_type, parsed_ikey.type);
|
||||
ASSERT_EQ(expected_seq, parsed_ikey.sequence);
|
||||
if (expected_val_type == kTypeValue) {
|
||||
ASSERT_EQ(expected_value, it->value());
|
||||
}
|
||||
ASSERT_EQ(expected_ts, it->timestamp());
|
||||
}
|
||||
|
||||
void DBBasicTestWithTimestampBase::CheckIterEntry(
|
||||
const Iterator* it, const Slice& expected_ukey, ValueType expected_val_type,
|
||||
const Slice& expected_value, const Slice& expected_ts) const {
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_OK(it->status());
|
||||
std::string ukey_and_ts;
|
||||
ukey_and_ts.assign(expected_ukey.data(), expected_ukey.size());
|
||||
ukey_and_ts.append(expected_ts.data(), expected_ts.size());
|
||||
|
||||
ParsedInternalKey parsed_ikey;
|
||||
ASSERT_OK(ParseInternalKey(it->key(), &parsed_ikey, true /* log_err_key */));
|
||||
ASSERT_EQ(expected_val_type, parsed_ikey.type);
|
||||
ASSERT_EQ(Slice(ukey_and_ts), parsed_ikey.user_key);
|
||||
if (expected_val_type == kTypeValue) {
|
||||
ASSERT_EQ(expected_value, it->value());
|
||||
}
|
||||
ASSERT_EQ(expected_ts, it->timestamp());
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -1,126 +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 "db/db_test_util.h"
|
||||
#include "port/stack_trace.h"
|
||||
#include "test_util/testutil.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class DBBasicTestWithTimestampBase : public DBTestBase {
|
||||
public:
|
||||
explicit DBBasicTestWithTimestampBase(const std::string& dbname)
|
||||
: DBTestBase(dbname, /*env_do_fsync=*/true) {}
|
||||
|
||||
protected:
|
||||
static std::string Key1(uint64_t k);
|
||||
|
||||
static std::string KeyWithPrefix(std::string prefix, uint64_t k);
|
||||
|
||||
static std::vector<Slice> ConvertStrToSlice(
|
||||
std::vector<std::string>& strings);
|
||||
|
||||
class TestComparator : public Comparator {
|
||||
private:
|
||||
const Comparator* cmp_without_ts_;
|
||||
|
||||
public:
|
||||
explicit TestComparator(size_t ts_sz)
|
||||
: Comparator(ts_sz), cmp_without_ts_(nullptr) {
|
||||
cmp_without_ts_ = BytewiseComparator();
|
||||
}
|
||||
|
||||
const char* Name() const override { return "TestComparator"; }
|
||||
|
||||
void FindShortSuccessor(std::string*) const override {}
|
||||
|
||||
void FindShortestSeparator(std::string*, const Slice&) const override {}
|
||||
|
||||
int Compare(const Slice& a, const Slice& b) const override {
|
||||
int r = CompareWithoutTimestamp(a, b);
|
||||
if (r != 0 || 0 == timestamp_size()) {
|
||||
return r;
|
||||
}
|
||||
return -CompareTimestamp(
|
||||
Slice(a.data() + a.size() - timestamp_size(), timestamp_size()),
|
||||
Slice(b.data() + b.size() - timestamp_size(), timestamp_size()));
|
||||
}
|
||||
|
||||
using Comparator::CompareWithoutTimestamp;
|
||||
int CompareWithoutTimestamp(const Slice& a, bool a_has_ts, const Slice& b,
|
||||
bool b_has_ts) const override {
|
||||
if (a_has_ts) {
|
||||
assert(a.size() >= timestamp_size());
|
||||
}
|
||||
if (b_has_ts) {
|
||||
assert(b.size() >= timestamp_size());
|
||||
}
|
||||
Slice lhs = a_has_ts ? StripTimestampFromUserKey(a, timestamp_size()) : a;
|
||||
Slice rhs = b_has_ts ? StripTimestampFromUserKey(b, timestamp_size()) : b;
|
||||
return cmp_without_ts_->Compare(lhs, rhs);
|
||||
}
|
||||
|
||||
int CompareTimestamp(const Slice& ts1, const Slice& ts2) const override {
|
||||
if (!ts1.data() && !ts2.data()) {
|
||||
return 0;
|
||||
} else if (ts1.data() && !ts2.data()) {
|
||||
return 1;
|
||||
} else if (!ts1.data() && ts2.data()) {
|
||||
return -1;
|
||||
}
|
||||
assert(ts1.size() == ts2.size());
|
||||
uint64_t low1 = 0;
|
||||
uint64_t low2 = 0;
|
||||
uint64_t high1 = 0;
|
||||
uint64_t high2 = 0;
|
||||
const size_t kSize = ts1.size();
|
||||
std::unique_ptr<char[]> ts1_buf(new char[kSize]);
|
||||
memcpy(ts1_buf.get(), ts1.data(), ts1.size());
|
||||
std::unique_ptr<char[]> ts2_buf(new char[kSize]);
|
||||
memcpy(ts2_buf.get(), ts2.data(), ts2.size());
|
||||
Slice ts1_copy = Slice(ts1_buf.get(), kSize);
|
||||
Slice ts2_copy = Slice(ts2_buf.get(), kSize);
|
||||
auto* ptr1 = const_cast<Slice*>(&ts1_copy);
|
||||
auto* ptr2 = const_cast<Slice*>(&ts2_copy);
|
||||
if (!GetFixed64(ptr1, &low1) || !GetFixed64(ptr1, &high1) ||
|
||||
!GetFixed64(ptr2, &low2) || !GetFixed64(ptr2, &high2)) {
|
||||
assert(false);
|
||||
}
|
||||
if (high1 < high2) {
|
||||
return -1;
|
||||
} else if (high1 > high2) {
|
||||
return 1;
|
||||
}
|
||||
if (low1 < low2) {
|
||||
return -1;
|
||||
} else if (low1 > low2) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
std::string Timestamp(uint64_t low, uint64_t high);
|
||||
|
||||
void CheckIterUserEntry(const Iterator* it, const Slice& expected_key,
|
||||
ValueType expected_value_type,
|
||||
const Slice& expected_value,
|
||||
const Slice& expected_ts) const;
|
||||
|
||||
void CheckIterEntry(const Iterator* it, const Slice& expected_ukey,
|
||||
SequenceNumber expected_seq, ValueType expected_val_type,
|
||||
const Slice& expected_value,
|
||||
const Slice& expected_ts) const;
|
||||
|
||||
void CheckIterEntry(const Iterator* it, const Slice& expected_ukey,
|
||||
ValueType expected_val_type, const Slice& expected_value,
|
||||
const Slice& expected_ts) const;
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
+6
-41
@@ -289,7 +289,7 @@ TEST_P(DBWriteTest, IOErrorOnWALWritePropagateToWriteThreadFollower) {
|
||||
threads.push_back(port::Thread(
|
||||
[&](int index) {
|
||||
// All threads should fail.
|
||||
auto res = Put("key" + std::to_string(index), "value");
|
||||
auto res = Put("key" + ToString(index), "value");
|
||||
if (options.manual_wal_flush) {
|
||||
ASSERT_TRUE(res.ok());
|
||||
// we should see fs error when we do the flush
|
||||
@@ -322,53 +322,18 @@ TEST_P(DBWriteTest, ManualWalFlushInEffect) {
|
||||
Options options = GetOptions();
|
||||
Reopen(options);
|
||||
// try the 1st WAL created during open
|
||||
ASSERT_TRUE(Put("key" + std::to_string(0), "value").ok());
|
||||
ASSERT_TRUE(Put("key" + ToString(0), "value").ok());
|
||||
ASSERT_TRUE(options.manual_wal_flush != dbfull()->TEST_WALBufferIsEmpty());
|
||||
ASSERT_TRUE(dbfull()->FlushWAL(false).ok());
|
||||
ASSERT_TRUE(dbfull()->TEST_WALBufferIsEmpty());
|
||||
// try the 2nd wal created during SwitchWAL
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
ASSERT_TRUE(Put("key" + std::to_string(0), "value").ok());
|
||||
ASSERT_TRUE(Put("key" + ToString(0), "value").ok());
|
||||
ASSERT_TRUE(options.manual_wal_flush != dbfull()->TEST_WALBufferIsEmpty());
|
||||
ASSERT_TRUE(dbfull()->FlushWAL(false).ok());
|
||||
ASSERT_TRUE(dbfull()->TEST_WALBufferIsEmpty());
|
||||
}
|
||||
|
||||
TEST_P(DBWriteTest, UnflushedPutRaceWithTrackedWalSync) {
|
||||
// Repro race condition bug where unflushed WAL data extended the synced size
|
||||
// recorded to MANIFEST despite being unrecoverable.
|
||||
Options options = GetOptions();
|
||||
std::unique_ptr<FaultInjectionTestEnv> fault_env(
|
||||
new FaultInjectionTestEnv(env_));
|
||||
options.env = fault_env.get();
|
||||
options.manual_wal_flush = true;
|
||||
options.track_and_verify_wals_in_manifest = true;
|
||||
Reopen(options);
|
||||
|
||||
ASSERT_OK(Put("key1", "val1"));
|
||||
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::SyncWAL:Begin",
|
||||
[this](void* /* arg */) { ASSERT_OK(Put("key2", "val2")); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(db_->FlushWAL(true /* sync */));
|
||||
|
||||
// Ensure callback ran.
|
||||
ASSERT_EQ("val2", Get("key2"));
|
||||
|
||||
Close();
|
||||
|
||||
// Simulate full loss of unsynced data. This drops "key2" -> "val2" from the
|
||||
// DB WAL.
|
||||
fault_env->DropUnsyncedFileData();
|
||||
|
||||
Reopen(options);
|
||||
|
||||
// Need to close before `fault_env` goes out of scope.
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_P(DBWriteTest, IOErrorOnWALWriteTriggersReadOnlyMode) {
|
||||
std::unique_ptr<FaultInjectionTestEnv> mock_env(
|
||||
new FaultInjectionTestEnv(env_));
|
||||
@@ -379,7 +344,7 @@ TEST_P(DBWriteTest, IOErrorOnWALWriteTriggersReadOnlyMode) {
|
||||
// Forcibly fail WAL write for the first Put only. Subsequent Puts should
|
||||
// fail due to read-only mode
|
||||
mock_env->SetFilesystemActive(i != 0);
|
||||
auto res = Put("key" + std::to_string(i), "value");
|
||||
auto res = Put("key" + ToString(i), "value");
|
||||
// TSAN reports a false alarm for lock-order-inversion but Open and
|
||||
// FlushWAL are not run concurrently. Disabling this until TSAN is
|
||||
// fixed.
|
||||
@@ -433,14 +398,14 @@ TEST_P(DBWriteTest, LockWalInEffect) {
|
||||
Options options = GetOptions();
|
||||
Reopen(options);
|
||||
// try the 1st WAL created during open
|
||||
ASSERT_OK(Put("key" + std::to_string(0), "value"));
|
||||
ASSERT_OK(Put("key" + ToString(0), "value"));
|
||||
ASSERT_TRUE(options.manual_wal_flush != dbfull()->TEST_WALBufferIsEmpty());
|
||||
ASSERT_OK(dbfull()->LockWAL());
|
||||
ASSERT_TRUE(dbfull()->TEST_WALBufferIsEmpty(false));
|
||||
ASSERT_OK(dbfull()->UnlockWAL());
|
||||
// try the 2nd wal created during SwitchWAL
|
||||
ASSERT_OK(dbfull()->TEST_SwitchWAL());
|
||||
ASSERT_OK(Put("key" + std::to_string(0), "value"));
|
||||
ASSERT_OK(Put("key" + ToString(0), "value"));
|
||||
ASSERT_TRUE(options.manual_wal_flush != dbfull()->TEST_WALBufferIsEmpty());
|
||||
ASSERT_OK(dbfull()->LockWAL());
|
||||
ASSERT_TRUE(dbfull()->TEST_WALBufferIsEmpty(false));
|
||||
|
||||
+1
-2
@@ -90,8 +90,7 @@ inline bool IsExtendedValueType(ValueType t) {
|
||||
// can be packed together into 64-bits.
|
||||
static const SequenceNumber kMaxSequenceNumber = ((0x1ull << 56) - 1);
|
||||
|
||||
static const SequenceNumber kDisableGlobalSequenceNumber =
|
||||
std::numeric_limits<uint64_t>::max();
|
||||
static const SequenceNumber kDisableGlobalSequenceNumber = port::kMaxUint64;
|
||||
|
||||
constexpr uint64_t kNumInternalBytes = 8;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class DeleteFileTest : public DBTestBase {
|
||||
options.sync = false;
|
||||
ReadOptions roptions;
|
||||
for (int i = startkey; i < (numkeys + startkey) ; i++) {
|
||||
std::string temp = std::to_string(i);
|
||||
std::string temp = ToString(i);
|
||||
Slice key(temp);
|
||||
Slice value(temp);
|
||||
ASSERT_OK(db_->Put(options, key, value));
|
||||
|
||||
@@ -1583,11 +1583,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" + std::to_string(0), &prop));
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(0), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 0);
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + std::to_string(1), &prop));
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(1), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 1);
|
||||
}
|
||||
|
||||
@@ -1720,11 +1720,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" + std::to_string(0), &prop));
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(0), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 0);
|
||||
EXPECT_TRUE(db[i]->GetProperty(
|
||||
"rocksdb.num-files-at-level" + std::to_string(1), &prop));
|
||||
EXPECT_TRUE(
|
||||
db[i]->GetProperty("rocksdb.num-files-at-level" + ToString(1), &prop));
|
||||
EXPECT_EQ(atoi(prop.c_str()), 1);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ Status UpdateManifestForFilesState(
|
||||
lf->oldest_blob_file_number,
|
||||
lf->oldest_ancester_time, lf->file_creation_time,
|
||||
lf->file_checksum, lf->file_checksum_func_name,
|
||||
lf->min_timestamp, lf->max_timestamp, lf->unique_id);
|
||||
lf->min_timestamp, lf->max_timestamp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -91,7 +91,7 @@ class ExternalSSTFileBasicTest
|
||||
bool write_global_seqno, bool verify_checksums_before_ingest,
|
||||
std::map<std::string, std::string>* true_data) {
|
||||
assert(value_types.size() == 1 || keys.size() == value_types.size());
|
||||
std::string file_path = sst_files_dir_ + std::to_string(file_id);
|
||||
std::string file_path = sst_files_dir_ + ToString(file_id);
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options);
|
||||
|
||||
Status s = sst_file_writer.Open(file_path);
|
||||
@@ -123,7 +123,7 @@ class ExternalSSTFileBasicTest
|
||||
}
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
std::string key = Key(keys[i]);
|
||||
std::string value = Key(keys[i]) + std::to_string(file_id);
|
||||
std::string value = Key(keys[i]) + ToString(file_id);
|
||||
ValueType value_type =
|
||||
(value_types.size() == 1 ? value_types[0] : value_types[i]);
|
||||
switch (value_type) {
|
||||
@@ -190,10 +190,10 @@ class ExternalSSTFileBasicTest
|
||||
#ifndef ROCKSDB_LITE
|
||||
uint64_t GetSstSizeHelper(Temperature temperature) {
|
||||
std::string prop;
|
||||
EXPECT_TRUE(dbfull()->GetProperty(
|
||||
DB::Properties::kLiveSstFilesSizeAtTemperature +
|
||||
std::to_string(static_cast<uint8_t>(temperature)),
|
||||
&prop));
|
||||
EXPECT_TRUE(
|
||||
dbfull()->GetProperty(DB::Properties::kLiveSstFilesSizeAtTemperature +
|
||||
ToString(static_cast<uint8_t>(temperature)),
|
||||
&prop));
|
||||
return static_cast<uint64_t>(std::atoi(prop.c_str()));
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
@@ -1184,7 +1184,7 @@ TEST_F(ExternalSSTFileBasicTest, SyncFailure) {
|
||||
std::unique_ptr<SstFileWriter> sst_file_writer(
|
||||
new SstFileWriter(EnvOptions(), sst_file_writer_options));
|
||||
std::string file_name =
|
||||
sst_files_dir_ + "sync_failure_test_" + std::to_string(i) + ".sst";
|
||||
sst_files_dir_ + "sync_failure_test_" + ToString(i) + ".sst";
|
||||
ASSERT_OK(sst_file_writer->Open(file_name));
|
||||
ASSERT_OK(sst_file_writer->Put("bar", "v2"));
|
||||
ASSERT_OK(sst_file_writer->Finish());
|
||||
@@ -1514,13 +1514,13 @@ TEST_P(ExternalSSTFileBasicTest, IngestFileWithFirstByteTampered) {
|
||||
EnvOptions env_options;
|
||||
do {
|
||||
Options options = CurrentOptions();
|
||||
std::string file_path = sst_files_dir_ + std::to_string(file_id++);
|
||||
std::string file_path = sst_files_dir_ + ToString(file_id++);
|
||||
SstFileWriter sst_file_writer(env_options, options);
|
||||
Status s = sst_file_writer.Open(file_path);
|
||||
ASSERT_OK(s);
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
std::string key = Key(i);
|
||||
std::string value = Key(i) + std::to_string(0);
|
||||
std::string value = Key(i) + ToString(0);
|
||||
ASSERT_OK(sst_file_writer.Put(key, value));
|
||||
}
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
@@ -1585,14 +1585,14 @@ TEST_P(ExternalSSTFileBasicTest, IngestExternalFileWithCorruptedPropsBlock) {
|
||||
int file_id = 0;
|
||||
Random64 rand(time(nullptr));
|
||||
do {
|
||||
std::string file_path = sst_files_dir_ + std::to_string(file_id++);
|
||||
std::string file_path = sst_files_dir_ + ToString(file_id++);
|
||||
Options options = CurrentOptions();
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options);
|
||||
Status s = sst_file_writer.Open(file_path);
|
||||
ASSERT_OK(s);
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
std::string key = Key(i);
|
||||
std::string value = Key(i) + std::to_string(0);
|
||||
std::string value = Key(i) + ToString(0);
|
||||
ASSERT_OK(sst_file_writer.Put(key, value));
|
||||
}
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
@@ -1799,7 +1799,7 @@ TEST_F(ExternalSSTFileBasicTest, IngestWithTemperature) {
|
||||
TEST_F(ExternalSSTFileBasicTest, FailIfNotBottommostLevel) {
|
||||
Options options = GetDefaultOptions();
|
||||
|
||||
std::string file_path = sst_files_dir_ + std::to_string(1);
|
||||
std::string file_path = sst_files_dir_ + ToString(1);
|
||||
SstFileWriter sfw(EnvOptions(), options);
|
||||
|
||||
ASSERT_OK(sfw.Open(file_path));
|
||||
@@ -1844,85 +1844,6 @@ TEST_F(ExternalSSTFileBasicTest, FailIfNotBottommostLevel) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExternalSSTFileBasicTest, VerifyChecksum) {
|
||||
const std::string kPutVal = "put_val";
|
||||
const std::string kIngestedVal = "ingested_val";
|
||||
|
||||
ASSERT_OK(Put("k", kPutVal, WriteOptions()));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::string external_file = sst_files_dir_ + "/file_to_ingest.sst";
|
||||
{
|
||||
SstFileWriter sst_file_writer{EnvOptions(), CurrentOptions()};
|
||||
|
||||
ASSERT_OK(sst_file_writer.Open(external_file));
|
||||
ASSERT_OK(sst_file_writer.Put("k", kIngestedVal));
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
}
|
||||
|
||||
ASSERT_OK(db_->IngestExternalFile(db_->DefaultColumnFamily(), {external_file},
|
||||
IngestExternalFileOptions()));
|
||||
|
||||
ASSERT_OK(db_->VerifyChecksum());
|
||||
}
|
||||
|
||||
TEST_F(ExternalSSTFileBasicTest, VerifySstUniqueId) {
|
||||
const std::string kPutVal = "put_val";
|
||||
const std::string kIngestedVal = "ingested_val";
|
||||
|
||||
ASSERT_OK(Put("k", kPutVal, WriteOptions()));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::string external_file = sst_files_dir_ + "/file_to_ingest.sst";
|
||||
{
|
||||
SstFileWriter sst_file_writer{EnvOptions(), CurrentOptions()};
|
||||
|
||||
ASSERT_OK(sst_file_writer.Open(external_file));
|
||||
ASSERT_OK(sst_file_writer.Put("k", kIngestedVal));
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
}
|
||||
|
||||
ASSERT_OK(db_->IngestExternalFile(db_->DefaultColumnFamily(), {external_file},
|
||||
IngestExternalFileOptions()));
|
||||
auto options = CurrentOptions();
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
Reopen(options);
|
||||
|
||||
// Test ingest file without session_id and db_id (for example generated by an
|
||||
// older version of sst_writer)
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"PropertyBlockBuilder::AddTableProperty:Start", [&](void* props_vs) {
|
||||
auto props = static_cast<TableProperties*>(props_vs);
|
||||
// update table property session_id to a different one
|
||||
props->db_session_id = "";
|
||||
props->db_id = "";
|
||||
});
|
||||
std::atomic_int skipped = 0;
|
||||
SyncPoint::GetInstance()->SetCallBack("Version::VerifySstUniqueIds::Skipped",
|
||||
[&](void* /*arg*/) { skipped++; });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
external_file = sst_files_dir_ + "/file_to_ingest2.sst";
|
||||
{
|
||||
SstFileWriter sst_file_writer{EnvOptions(), CurrentOptions()};
|
||||
|
||||
ASSERT_OK(sst_file_writer.Open(external_file));
|
||||
ASSERT_OK(sst_file_writer.Put("k", kIngestedVal));
|
||||
ASSERT_OK(sst_file_writer.Finish());
|
||||
}
|
||||
|
||||
ASSERT_OK(db_->IngestExternalFile(db_->DefaultColumnFamily(), {external_file},
|
||||
IngestExternalFileOptions()));
|
||||
|
||||
options.statistics = CreateDBStatistics();
|
||||
options.verify_sst_unique_id_in_manifest = true;
|
||||
ASSERT_EQ(skipped, 0);
|
||||
Reopen(options);
|
||||
// only one sst file is not verified because of missing unique_id
|
||||
ASSERT_EQ(skipped, 1);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExternalSSTFileBasicTest, ExternalSSTFileBasicTest,
|
||||
testing::Values(std::make_tuple(true, true),
|
||||
std::make_tuple(true, false),
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "table/scoped_arena_iterator.h"
|
||||
#include "table/sst_file_writer_collectors.h"
|
||||
#include "table/table_builder.h"
|
||||
#include "table/unique_id_impl.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/stop_watch.h"
|
||||
|
||||
@@ -143,9 +142,6 @@ Status ExternalSstFileIngestionJob::Prepare(
|
||||
ingestion_options_.failed_move_fall_back_to_copy) {
|
||||
// Original file is on a different FS, use copy instead of hard linking.
|
||||
f.copy_file = true;
|
||||
ROCKS_LOG_INFO(db_options_.info_log,
|
||||
"Triy to link file %s but it's not supported : %s",
|
||||
path_outside_db.c_str(), status.ToString().c_str());
|
||||
}
|
||||
} else {
|
||||
f.copy_file = true;
|
||||
@@ -450,8 +446,8 @@ Status ExternalSstFileIngestionJob::Run() {
|
||||
f.smallest_internal_key, f.largest_internal_key, f.assigned_seqno,
|
||||
f.assigned_seqno, false, f.file_temperature, kInvalidBlobFileNumber,
|
||||
oldest_ancester_time, current_time, f.file_checksum,
|
||||
f.file_checksum_func_name, kDisableUserTimestamp, kDisableUserTimestamp,
|
||||
f.unique_id);
|
||||
f.file_checksum_func_name, kDisableUserTimestamp,
|
||||
kDisableUserTimestamp);
|
||||
f_metadata.temperature = f.file_temperature;
|
||||
edit_.AddFile(f.picked_level, f_metadata);
|
||||
}
|
||||
@@ -731,16 +727,6 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
|
||||
|
||||
file_to_ingest->table_properties = *props;
|
||||
|
||||
auto s = GetSstInternalUniqueId(props->db_id, props->db_session_id,
|
||||
props->orig_file_number,
|
||||
&(file_to_ingest->unique_id));
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_WARN(db_options_.info_log,
|
||||
"Failed to get SST unique id for file %s",
|
||||
file_to_ingest->internal_file_path.c_str());
|
||||
file_to_ingest->unique_id = kNullUniqueId64x2;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,8 +70,6 @@ struct IngestedFileInfo {
|
||||
std::string file_checksum_func_name;
|
||||
// The temperature of the file to be ingested
|
||||
Temperature file_temperature = Temperature::kUnknown;
|
||||
// Unique id of the file to be ingested
|
||||
UniqueId64x2 unique_id{};
|
||||
};
|
||||
|
||||
class ExternalSstFileIngestionJob {
|
||||
|
||||
@@ -118,7 +118,7 @@ class ExternalSSTFileTest
|
||||
});
|
||||
data.resize(uniq_iter - data.begin());
|
||||
}
|
||||
std::string file_path = sst_files_dir_ + std::to_string(file_id);
|
||||
std::string file_path = sst_files_dir_ + ToString(file_id);
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options, cfh);
|
||||
Status s = sst_file_writer.Open(file_path);
|
||||
if (!s.ok()) {
|
||||
@@ -172,7 +172,7 @@ class ExternalSSTFileTest
|
||||
});
|
||||
data.resize(uniq_iter - data.begin());
|
||||
}
|
||||
std::string file_path = sst_files_dir_ + std::to_string(file_id);
|
||||
std::string file_path = sst_files_dir_ + ToString(file_id);
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options, cfh);
|
||||
|
||||
Status s = sst_file_writer.Open(file_path);
|
||||
@@ -270,7 +270,7 @@ class ExternalSSTFileTest
|
||||
ColumnFamilyHandle* cfh = nullptr) {
|
||||
std::vector<std::pair<std::string, std::string>> file_data;
|
||||
for (auto& k : keys) {
|
||||
file_data.emplace_back(Key(k), Key(k) + std::to_string(file_id));
|
||||
file_data.emplace_back(Key(k), Key(k) + ToString(file_id));
|
||||
}
|
||||
return GenerateAndAddExternalFile(options, file_data, file_id,
|
||||
allow_global_seqno, write_global_seqno,
|
||||
@@ -966,7 +966,7 @@ TEST_F(ExternalSSTFileTest, MultiThreaded) {
|
||||
// Generate file names
|
||||
std::vector<std::string> file_names;
|
||||
for (int i = 0; i < num_files; i++) {
|
||||
std::string file_name = "file_" + std::to_string(i) + ".sst";
|
||||
std::string file_name = "file_" + ToString(i) + ".sst";
|
||||
file_names.push_back(sst_files_dir_ + file_name);
|
||||
}
|
||||
|
||||
@@ -1116,7 +1116,7 @@ TEST_F(ExternalSSTFileTest, OverlappingRanges) {
|
||||
int range_end = key_ranges[i].second;
|
||||
|
||||
Status s;
|
||||
std::string range_val = "range_" + std::to_string(i);
|
||||
std::string range_val = "range_" + ToString(i);
|
||||
|
||||
// For 20% of ranges we use DB::Put, for 80% we use DB::AddFile
|
||||
if (i && i % 5 == 0) {
|
||||
@@ -1456,7 +1456,7 @@ TEST_F(ExternalSSTFileTest, CompactDuringAddFileRandom) {
|
||||
ASSERT_EQ(Get(Key(range_start)), Key(range_start)) << rid;
|
||||
ASSERT_EQ(Get(Key(range_end)), Key(range_end)) << rid;
|
||||
for (int k = range_start + 1; k < range_end; k++) {
|
||||
std::string v = Key(k) + std::to_string(rid);
|
||||
std::string v = Key(k) + ToString(rid);
|
||||
ASSERT_EQ(Get(Key(k)), v) << rid;
|
||||
}
|
||||
}
|
||||
@@ -2405,7 +2405,7 @@ TEST_P(ExternalSSTBlockChecksumTest, DISABLED_HugeBlockChecksum) {
|
||||
SstFileWriter sst_file_writer(EnvOptions(), options);
|
||||
|
||||
// 2^32 - 1, will lead to data block with more than 2^32 bytes
|
||||
size_t huge_size = std::numeric_limits<uint32_t>::max();
|
||||
size_t huge_size = port::kMaxUint32;
|
||||
|
||||
std::string f = sst_files_dir_ + "f.sst";
|
||||
ASSERT_OK(sst_file_writer.Open(f));
|
||||
|
||||
+4
-1
@@ -58,7 +58,10 @@ class FileIndexer {
|
||||
void UpdateIndex(Arena* arena, const size_t num_levels,
|
||||
std::vector<FileMetaData*>* const files);
|
||||
|
||||
enum { kLevelMaxIndex = std::numeric_limits<int32_t>::max() };
|
||||
enum {
|
||||
// MSVC version 1800 still does not have constexpr for ::max()
|
||||
kLevelMaxIndex = ROCKSDB_NAMESPACE::port::kMaxInt32
|
||||
};
|
||||
|
||||
private:
|
||||
size_t num_levels_;
|
||||
|
||||
+15
-28
@@ -9,8 +9,9 @@
|
||||
|
||||
#include "db/flush_job.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "db/builder.h"
|
||||
@@ -463,7 +464,6 @@ Status FlushJob::MemPurge() {
|
||||
env, ShouldReportDetailedTime(env, ioptions->stats),
|
||||
true /* internal key corruption is not ok */, range_del_agg.get(),
|
||||
nullptr, ioptions->allow_data_in_errors,
|
||||
ioptions->enforce_single_del_contracts,
|
||||
/*compaction=*/nullptr, compaction_filter.get(),
|
||||
/*shutting_down=*/nullptr,
|
||||
/*manual_compaction_paused=*/nullptr,
|
||||
@@ -809,7 +809,6 @@ Status FlushJob::WriteLevel0Table() {
|
||||
|
||||
{
|
||||
auto write_hint = cfd_->CalculateSSTWriteHint(0);
|
||||
Env::IOPriority io_priority = GetRateLimiterPriorityForWrite();
|
||||
db_mutex_->Unlock();
|
||||
if (log_buffer_) {
|
||||
log_buffer_->FlushBufferToLog();
|
||||
@@ -925,16 +924,16 @@ Status FlushJob::WriteLevel0Table() {
|
||||
snapshot_checker_, mutable_cf_options_.paranoid_file_checks,
|
||||
cfd_->internal_stats(), &io_s, io_tracer_,
|
||||
BlobFileCreationReason::kFlush, event_logger_, job_context_->job_id,
|
||||
io_priority, &table_properties_, write_hint, full_history_ts_low,
|
||||
Env::IO_HIGH, &table_properties_, write_hint, full_history_ts_low,
|
||||
blob_callback_, &num_input_entries, &memtable_payload_bytes,
|
||||
&memtable_garbage_bytes);
|
||||
// TODO: Cleanup io_status in BuildTable and table builders
|
||||
assert(!s.ok() || io_s.ok());
|
||||
io_s.PermitUncheckedError();
|
||||
if (num_input_entries != total_num_entries && s.ok()) {
|
||||
std::string msg = "Expected " + std::to_string(total_num_entries) +
|
||||
std::string msg = "Expected " + ToString(total_num_entries) +
|
||||
" entries in memtables, but read " +
|
||||
std::to_string(num_input_entries);
|
||||
ToString(num_input_entries);
|
||||
ROCKS_LOG_WARN(db_options_.info_log, "[%s] [JOB %d] Level-0 flush %s",
|
||||
cfd_->GetName().c_str(), job_context_->job_id,
|
||||
msg.c_str());
|
||||
@@ -951,14 +950,14 @@ Status FlushJob::WriteLevel0Table() {
|
||||
}
|
||||
LogFlush(db_options_.info_log);
|
||||
}
|
||||
ROCKS_LOG_BUFFER(log_buffer_,
|
||||
"[%s] [JOB %d] Level-0 flush table #%" PRIu64 ": %" PRIu64
|
||||
" bytes %s"
|
||||
"%s",
|
||||
cfd_->GetName().c_str(), job_context_->job_id,
|
||||
meta_.fd.GetNumber(), meta_.fd.GetFileSize(),
|
||||
s.ToString().c_str(),
|
||||
meta_.marked_for_compaction ? " (needs compaction)" : "");
|
||||
ROCKS_LOG_INFO(db_options_.info_log,
|
||||
"[%s] [JOB %d] Level-0 flush table #%" PRIu64 ": %" PRIu64
|
||||
" bytes %s"
|
||||
"%s",
|
||||
cfd_->GetName().c_str(), job_context_->job_id,
|
||||
meta_.fd.GetNumber(), meta_.fd.GetFileSize(),
|
||||
s.ToString().c_str(),
|
||||
meta_.marked_for_compaction ? " (needs compaction)" : "");
|
||||
|
||||
if (s.ok() && output_file_directory_ != nullptr && sync_output_directory_) {
|
||||
s = output_file_directory_->FsyncWithDirOptions(
|
||||
@@ -988,7 +987,7 @@ Status FlushJob::WriteLevel0Table() {
|
||||
meta_.oldest_blob_file_number, meta_.oldest_ancester_time,
|
||||
meta_.file_creation_time, meta_.file_checksum,
|
||||
meta_.file_checksum_func_name, meta_.min_timestamp,
|
||||
meta_.max_timestamp, meta_.unique_id);
|
||||
meta_.max_timestamp);
|
||||
|
||||
edit_->SetBlobFileAdditions(std::move(blob_file_additions));
|
||||
}
|
||||
@@ -1032,19 +1031,6 @@ Status FlushJob::WriteLevel0Table() {
|
||||
return s;
|
||||
}
|
||||
|
||||
Env::IOPriority FlushJob::GetRateLimiterPriorityForWrite() {
|
||||
if (versions_ && versions_->GetColumnFamilySet() &&
|
||||
versions_->GetColumnFamilySet()->write_controller()) {
|
||||
WriteController* write_controller =
|
||||
versions_->GetColumnFamilySet()->write_controller();
|
||||
if (write_controller->IsStopped() || write_controller->NeedsDelay()) {
|
||||
return Env::IO_USER;
|
||||
}
|
||||
}
|
||||
|
||||
return Env::IO_HIGH;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
std::unique_ptr<FlushJobInfo> FlushJob::GetFlushJobInfo() const {
|
||||
db_mutex_->AssertHeld();
|
||||
@@ -1077,6 +1063,7 @@ std::unique_ptr<FlushJobInfo> FlushJob::GetFlushJobInfo() const {
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -94,8 +94,6 @@ class FlushJob {
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
private:
|
||||
friend class FlushJobTest_GetRateLimiterPriorityForWrite_Test;
|
||||
|
||||
void ReportStartedFlush();
|
||||
void ReportFlushInputSize(const autovector<MemTable*>& mems);
|
||||
void RecordFlushIOStats();
|
||||
@@ -123,8 +121,6 @@ class FlushJob {
|
||||
// process has not matured yet.
|
||||
Status MemPurge();
|
||||
bool MemPurgeDecider();
|
||||
// The rate limiter priority (io_priority) is determined dynamically here.
|
||||
Env::IOPriority GetRateLimiterPriorityForWrite();
|
||||
#ifndef ROCKSDB_LITE
|
||||
std::unique_ptr<FlushJobInfo> GetFlushJobInfo() const;
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
Loaded 100 of 382 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user