mirror of
https://github.com/facebook/rocksdb.git
synced 2026-11-07 11:32:34 -05:00
Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be84166d2f | ||
|
|
23e0a29a0e | ||
|
|
60c1321db1 | ||
|
|
09c7e96eac | ||
|
|
9ef7f70c11 | ||
|
|
553aafaf8e | ||
|
|
1315375542 | ||
|
|
a471d31e04 | ||
|
|
8797aea803 | ||
|
|
9092ebed39 | ||
|
|
675f351cc8 | ||
|
|
11b42f92b1 | ||
|
|
14d173ec81 | ||
|
|
8b30b8d2a0 | ||
|
|
b6471f8a5c | ||
|
|
3dd5bc2a25 | ||
|
|
48edcfc17d | ||
|
|
ffe4906192 | ||
|
|
d76a8eeef7 | ||
|
|
1001bc01c9 | ||
|
|
2fb6d9337f | ||
|
|
ac956f2bea | ||
|
|
7189ea8fb7 | ||
|
|
3e6ee9f82e | ||
|
|
0426d4a4ee | ||
|
|
8e7b068ecc | ||
|
|
77b4bfe511 | ||
|
|
fdbebdf484 | ||
|
|
e4bdf9e0cb | ||
|
|
edfcce39da | ||
|
|
0a9f78d2c8 | ||
|
|
eccc47e81c | ||
|
|
a3066ee75c | ||
|
|
4926b33742 | ||
|
|
8ed680bdb0 | ||
|
|
b2e30bdb67 | ||
|
|
c22e619f7e | ||
|
|
48c0843e69 | ||
|
|
cc2a180d00 | ||
|
|
8f7b6c8339 | ||
|
|
6e0f62f2b6 | ||
|
|
5792b73fdc | ||
|
|
e628f59e87 | ||
|
|
c1a65a4de4 | ||
|
|
58660bf21a | ||
|
|
225abffd8f | ||
|
|
159ea4702c | ||
|
|
b8c01ed38a | ||
|
|
0bad2b4308 | ||
|
|
61e324422e | ||
|
|
bb0f781da0 | ||
|
|
81367a4616 | ||
|
|
30cd38c687 |
No files matched your search
+24
-7
@@ -62,6 +62,14 @@ commands:
|
||||
path: /tmp/test-results
|
||||
- store_artifacts: # store LOG for debugging if there's any
|
||||
path: LOG
|
||||
- run: # on fail, compress Test Logs for diagnosing the issue
|
||||
name: Compress Test Logs
|
||||
command: tar -cvzf t.tar.gz t
|
||||
when: on_fail
|
||||
- store_artifacts: # on fail, store Test Logs for diagnosing the issue
|
||||
path: t.tar.gz
|
||||
destination: test_logs
|
||||
when: on_fail
|
||||
|
||||
install-clang-10:
|
||||
steps:
|
||||
@@ -356,9 +364,13 @@ jobs:
|
||||
- run:
|
||||
name: "Setup VS"
|
||||
command: |
|
||||
if [[ "${VS_YEAR}" == "2017" ]]; then
|
||||
if [[ "${VS_YEAR}" == "2019" ]]; then
|
||||
echo "VS2019 already present."
|
||||
elif [[ "${VS_YEAR}" == "2017" ]]; then
|
||||
echo "Installing VS2017..."
|
||||
powershell .circleci/vs2017_install.ps1
|
||||
elif [[ "${VS_YEAR}" == "2015" ]]; then
|
||||
echo "Installing VS2015..."
|
||||
powershell .circleci/vs2015_install.ps1
|
||||
fi
|
||||
- run:
|
||||
@@ -384,6 +396,7 @@ jobs:
|
||||
cd build
|
||||
${CMAKE_BIN} -G "${CMAKE_GENERATOR}" -DCMAKE_BUILD_TYPE=Debug -DOPTDBG=1 -DPORTABLE=1 -DSNAPPY=1 -DJNI=1 << parameters.extra_cmake_opt >> ..
|
||||
cd ..
|
||||
echo "Building with VS version: ${CMAKE_GENERATOR}"
|
||||
msbuild.exe build/rocksdb.sln -maxCpuCount -property:Configuration=Debug -property:Platform=x64
|
||||
- run:
|
||||
name: "Test RocksDB"
|
||||
@@ -592,23 +605,27 @@ workflows:
|
||||
build-linux-unity:
|
||||
jobs:
|
||||
- build-linux-unity
|
||||
build-windows:
|
||||
build-windows-vs2019:
|
||||
jobs:
|
||||
- build-windows
|
||||
- build-windows:
|
||||
name: "build-windows-vs2019"
|
||||
build-windows-vs2019-cxx20:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2019-cxx20"
|
||||
extra_cmake_opt: -DCMAKE_CXX_STANDARD=20
|
||||
build-windows-vs2017:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2017"
|
||||
vs_year: "2017"
|
||||
cmake_generator: "Visual Studio 15 Win64"
|
||||
build-windows-vs2015:
|
||||
jobs:
|
||||
- build-windows:
|
||||
name: "build-windows-vs2015"
|
||||
vs_year: "2015"
|
||||
cmake_generator: "Visual Studio 14 Win64"
|
||||
build-windows-cxx20:
|
||||
jobs:
|
||||
- build-windows:
|
||||
extra_cmake_opt: -DCMAKE_CXX_STANDARD=20
|
||||
build-java:
|
||||
jobs:
|
||||
- build-linux-java
|
||||
|
||||
@@ -21,3 +21,4 @@ if (($exitCode -ne 0) -and ($exitCode -ne 3010)) {
|
||||
Copy-Item -Path "C:\Users\circleci\AppData\Local\Temp\vslogs.zip" -Destination "C:\w\build-results\"
|
||||
exit 1
|
||||
}
|
||||
echo "VS 2015 installed."
|
||||
@@ -32,3 +32,4 @@ if (($exitCode -ne 0) -and ($exitCode -ne 3010)) {
|
||||
Copy-Item -Path "C:\Users\circleci\AppData\Local\Temp\vslogs.zip" -Destination "C:\w\build-results\"
|
||||
exit 1
|
||||
}
|
||||
echo "VS 2017 installed."
|
||||
+12
-84
@@ -2,20 +2,18 @@ dist: xenial
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
osx_image: xcode9.4
|
||||
cache:
|
||||
- ccache
|
||||
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
@@ -26,15 +24,6 @@ addons:
|
||||
- liblzma-dev # xv
|
||||
- libzstd-dev
|
||||
- zlib1g-dev
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- ccache
|
||||
- gflags
|
||||
- lz4
|
||||
- snappy
|
||||
- xz
|
||||
- zstd
|
||||
|
||||
env:
|
||||
- TEST_GROUP=platform_dependent # 16-18 minutes
|
||||
@@ -58,20 +47,6 @@ env:
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc8
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc9
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-gcc9-c++20
|
||||
- os: osx
|
||||
env: JOB_NAME=cmake-mingw
|
||||
- os: osx
|
||||
env: JOB_NAME=make-gcc4.8
|
||||
- os: osx
|
||||
arch: ppc64le
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os : linux
|
||||
arch: arm64
|
||||
env: JOB_NAME=cmake-mingw
|
||||
@@ -86,28 +61,6 @@ matrix:
|
||||
env: JOB_NAME=make-gcc4.8
|
||||
- os: linux
|
||||
compiler: clang
|
||||
# With migration to CircleCI, exclude Linux/amd64 for pull requests
|
||||
# (but build in branches for now)
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: amd64
|
||||
# Exclude most osx, arm64 and ppc64le tests for pull requests, but build in branches
|
||||
# Temporarily disable ppc64le cmake test while snapd is broken
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake
|
||||
# Exclude all osx since it should be covered by CircleCI
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=platform_dependent
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: JOB_NAME=cmake
|
||||
# NB: the cmake build is a partial java test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=1
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -116,9 +69,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=1
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=2
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -127,9 +77,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=2
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=3
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -138,9 +85,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=3
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os: osx
|
||||
env: TEST_GROUP=4
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -149,9 +93,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: TEST_GROUP=4
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/ AND commit_message !~ /java/
|
||||
os : osx
|
||||
env: JOB_NAME=java_test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/ AND commit_message !~ /java/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -160,9 +101,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=java_test
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : osx
|
||||
env: JOB_NAME=lite_build
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -171,9 +109,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=lite_build
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : osx
|
||||
env: JOB_NAME=examples
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -206,9 +141,6 @@ matrix:
|
||||
os: linux
|
||||
arch: ppc64le
|
||||
env: JOB_NAME=cmake-gcc9-c++20
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : osx
|
||||
env: JOB_NAME=status_checked
|
||||
- if: type = pull_request AND commit_message !~ /FULL_CI/
|
||||
os : linux
|
||||
arch: arm64
|
||||
@@ -219,9 +151,6 @@ matrix:
|
||||
env: JOB_NAME=status_checked
|
||||
|
||||
install:
|
||||
- if [ "${TRAVIS_OS_NAME}" == osx ]; then
|
||||
PATH=$PATH:/usr/local/opt/ccache/libexec;
|
||||
fi
|
||||
- if [ "${JOB_NAME}" == cmake-gcc8 ]; then
|
||||
sudo apt-get install -y g++-8 || exit $?;
|
||||
CC=gcc-8 && CXX=g++-8;
|
||||
@@ -237,22 +166,21 @@ install:
|
||||
sudo apt-get install -y g++-4.8 || exit $?;
|
||||
CC=gcc-4.8 && CXX=g++-4.8;
|
||||
fi
|
||||
- if [[ "${JOB_NAME}" == cmake* ]] && [ "${TRAVIS_OS_NAME}" == linux ]; then
|
||||
sudo apt-get install snapd && sudo snap install cmake --beta --classic || exit $?;
|
||||
export PATH=/snap/bin:$PATH;
|
||||
- |
|
||||
if [[ "${JOB_NAME}" == cmake* ]]; then
|
||||
sudo apt-get remove -y cmake cmake-data
|
||||
export CMAKE_DEB="cmake-3.14.5-Linux-$(uname -m).deb"
|
||||
export CMAKE_DEB_URL="https://rocksdb-deps.s3-us-west-2.amazonaws.com/cmake/${CMAKE_DEB}"
|
||||
curl --silent --fail --show-error --location --output "${CMAKE_DEB}" "${CMAKE_DEB_URL}" || exit $?
|
||||
sudo dpkg -i "${CMAKE_DEB}" || exit $?
|
||||
which cmake && cmake --version
|
||||
fi
|
||||
- |
|
||||
if [[ "${JOB_NAME}" == java_test || "${JOB_NAME}" == cmake* ]]; then
|
||||
# Ensure JDK 8
|
||||
if [ "${TRAVIS_OS_NAME}" == osx ]; then
|
||||
brew tap AdoptOpenJDK/openjdk || exit $?
|
||||
brew cask install adoptopenjdk8 || exit $?
|
||||
export JAVA_HOME=$(/usr/libexec/java_home)
|
||||
else
|
||||
sudo apt-get install -y openjdk-8-jdk || exit $?
|
||||
export PATH=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)/bin:$PATH
|
||||
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)
|
||||
fi
|
||||
sudo apt-get install -y openjdk-8-jdk || exit $?
|
||||
export PATH=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)/bin:$PATH
|
||||
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-$(dpkg --print-architecture)
|
||||
echo "JAVA_HOME=${JAVA_HOME}"
|
||||
which java && java -version
|
||||
which javac && javac -version
|
||||
|
||||
+31
-1
@@ -1,4 +1,29 @@
|
||||
# Rocksdb Change Log
|
||||
## 6.17.3 (02/18/2021)
|
||||
### Bug Fixes
|
||||
* Fix `WRITE_PREPARED`, `WRITE_UNPREPARED` TransactionDB `MultiGet()` may return uncommitted data with snapshot.
|
||||
|
||||
## 6.17.2 (02/05/2021)
|
||||
### Bug Fixes
|
||||
* Since 6.15.0, `TransactionDB` returns error `Status`es from calls to `DeleteRange()` and calls to `Write()` where the `WriteBatch` contains a range deletion. Previously such operations may have succeeded while not providing the expected transactional guarantees. There are certain cases where range deletion can still be used on such DBs; see the API doc on `TransactionDB::DeleteRange()` for details.
|
||||
* `OptimisticTransactionDB` now returns error `Status`es from calls to `DeleteRange()` and calls to `Write()` where the `WriteBatch` contains a range deletion. Previously such operations may have succeeded while not providing the expected transactional guarantees.
|
||||
|
||||
## 6.17.1 (01/28/2021)
|
||||
### Behavior Changes
|
||||
* When retryable IO error occurs during compaction, it is mapped to soft error and set the BG error. However, auto resume is not called to clean the soft error since compaction will reschedule by itself. In this change, When retryable IO error occurs during compaction, BG error is not set. User will be informed the error via EventHelper.
|
||||
|
||||
## 6.17.0 (01/15/2021)
|
||||
### Behavior Changes
|
||||
* When verifying full file checksum with `DB::VerifyFileChecksums()`, we now fail with `Status::InvalidArgument` if the name of the checksum generator used for verification does not match the name of the checksum generator used for protecting the file when it was created.
|
||||
* Since RocksDB does not continue write the same file if a file write fails for any reason, the file scope write IO error is treated the same as retryable IO error. More information about error handling of file scope IO error is included in `ErrorHandler::SetBGError`.
|
||||
|
||||
### Bug Fixes
|
||||
* Version older than 6.15 cannot decode VersionEdits `WalAddition` and `WalDeletion`, fixed this by changing the encoded format of them to be ignorable by older versions.
|
||||
* Fix a race condition between DB startups and shutdowns in managing the periodic background worker threads. One effect of this race condition could be the process being terminated.
|
||||
|
||||
### Public API Change
|
||||
* Add a public API WriteBufferManager::dummy_entries_in_cache_usage() which reports the size of dummy entries stored in cache (passed to WriteBufferManager). Dummy entries are used to account for DataBlocks.
|
||||
|
||||
## 6.16.0 (12/18/2020)
|
||||
### Behavior Changes
|
||||
* Attempting to write a merge operand without explicitly configuring `merge_operator` now fails immediately, causing the DB to enter read-only mode. Previously, failure was deferred until the `merge_operator` was needed by a user read or a background operation.
|
||||
@@ -10,6 +35,8 @@
|
||||
* Fixed the logic of populating native data structure for `read_amp_bytes_per_bit` during OPTIONS file parsing on big-endian architecture. Without this fix, original code introduced in PR7659, when running on big-endian machine, can mistakenly store read_amp_bytes_per_bit (an uint32) in little endian format. Future access to `read_amp_bytes_per_bit` will give wrong values. Little endian architecture is not affected.
|
||||
* Fixed prefix extractor with timestamp issues.
|
||||
* Fixed a bug in atomic flush: in two-phase commit mode, the minimum WAL log number to keep is incorrect.
|
||||
* Fixed a bug related to checkpoint in PR7789: if there are multiple column families, and the checkpoint is not opened as read only, then in rare cases, data loss may happen in the checkpoint. Since backup engine relies on checkpoint, it may also be affected.
|
||||
* When ldb --try_load_options is used with the --column_family option, the ColumnFamilyOptions for the specified column family was not loaded from the OPTIONS file. Fix it so its loaded from OPTIONS and then overridden with command line overrides.
|
||||
|
||||
### New Features
|
||||
* User defined timestamp feature supports `CompactRange` and `GetApproximateSizes`.
|
||||
@@ -18,6 +45,10 @@
|
||||
|
||||
### Public API Change
|
||||
* Deprecated public but rarely-used FilterBitsBuilder::CalculateNumEntry, which is replaced with ApproximateNumEntries taking a size_t parameter and returning size_t.
|
||||
* To improve portability the functions `Env::GetChildren` and `Env::GetChildrenFileAttributes` will no longer return entries for the special directories `.` or `..`.
|
||||
* Added a new option `track_and_verify_wals_in_manifest`. If `true`, the log numbers and sizes of the synced WALs are tracked in MANIFEST, then during DB recovery, if a synced WAL is missing from disk, or the WAL's size does not match the recorded size in MANIFEST, an error will be reported and the recovery will be aborted. Note that this option does not work with secondary instance.
|
||||
* `rocksdb_approximate_sizes` and `rocksdb_approximate_sizes_cf` in the C API now requires an error pointer (`char** errptr`) for receiving any error.
|
||||
* All overloads of DB::GetApproximateSizes now return Status, so that any failure to obtain the sizes is indicated to the caller.
|
||||
|
||||
## 6.15.0 (11/13/2020)
|
||||
### Bug Fixes
|
||||
@@ -39,7 +70,6 @@
|
||||
### Public API Change
|
||||
* Deprecate `BlockBasedTableOptions::pin_l0_filter_and_index_blocks_in_cache` and `BlockBasedTableOptions::pin_top_level_index_and_filter`. These options still take effect until users migrate to the replacement APIs in `BlockBasedTableOptions::metadata_cache_options`. Migration guidance can be found in the API comments on the deprecated options.
|
||||
* Add new API `DB::VerifyFileChecksums` to verify SST file checksum with corresponding entries in the MANIFEST if present. Current implementation requires scanning and recomputing file checksums.
|
||||
* Added a new option `track_and_verify_wals_in_manifest`. If `true`, the log numbers and sizes of the synced WALs are tracked in MANIFEST, then during DB recovery, if a synced WAL is missing from disk, or the WAL's size does not match the recorded size in MANIFEST, an error will be reported and the recovery will be aborted. Note that this option does not work with secondary instance.
|
||||
|
||||
### Behavior Changes
|
||||
* The dictionary compression settings specified in `ColumnFamilyOptions::compression_opts` now additionally affect files generated by flush and compaction to non-bottommost level. Previously those settings at most affected files generated by compaction to bottommost level, depending on whether `ColumnFamilyOptions::bottommost_compression_opts` overrode them. Users who relied on dictionary compression settings in `ColumnFamilyOptions::compression_opts` affecting only the bottommost level can keep the behavior by moving their dictionary settings to `ColumnFamilyOptions::bottommost_compression_opts` and setting its `enabled` flag.
|
||||
|
||||
@@ -515,6 +515,12 @@ ifeq ($(USE_FOLLY_DISTRIBUTED_MUTEX),1)
|
||||
LIB_OBJECTS += $(patsubst %.cpp, $(OBJ_DIR)/%.o, $(FOLLY_SOURCES))
|
||||
endif
|
||||
|
||||
# range_tree is not compatible with non GNU libc on ppc64
|
||||
# see https://jira.percona.com/browse/PS-7559
|
||||
ifneq ($(PPC_LIBC_IS_GNU),0)
|
||||
LIB_OBJECTS += $(patsubst %.cc, $(OBJ_DIR)/%.o, $(RANGE_TREE_SOURCES))
|
||||
endif
|
||||
|
||||
GTEST = $(OBJ_DIR)/$(GTEST_DIR)/gtest/gtest-all.o
|
||||
TESTUTIL = $(OBJ_DIR)/test_util/testutil.o
|
||||
TESTHARNESS = $(OBJ_DIR)/test_util/testharness.o $(TESTUTIL) $(GTEST)
|
||||
@@ -612,7 +618,12 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
db_blob_basic_test \
|
||||
db_blob_index_test \
|
||||
db_block_cache_test \
|
||||
db_compaction_test \
|
||||
db_compaction_filter_test \
|
||||
db_dynamic_level_test \
|
||||
db_flush_test \
|
||||
db_inplace_update_test \
|
||||
db_io_failure_test \
|
||||
db_iterator_test \
|
||||
db_logical_block_size_cache_test \
|
||||
db_memtable_test \
|
||||
@@ -629,6 +640,7 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
deletefile_test \
|
||||
external_sst_file_test \
|
||||
options_file_test \
|
||||
db_sst_test \
|
||||
db_statistics_test \
|
||||
db_table_properties_test \
|
||||
db_tailing_iter_test \
|
||||
@@ -653,6 +665,7 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
external_sst_file_basic_test \
|
||||
auto_roll_logger_test \
|
||||
file_indexer_test \
|
||||
delete_scheduler_test \
|
||||
flush_job_test \
|
||||
hash_table_test \
|
||||
hash_test \
|
||||
@@ -741,6 +754,9 @@ ifdef ASSERT_STATUS_CHECKED
|
||||
cuckoo_table_reader_test \
|
||||
memory_test \
|
||||
table_test \
|
||||
backupable_db_test \
|
||||
blob_db_test \
|
||||
ttl_test \
|
||||
write_batch_test \
|
||||
write_batch_with_index_test \
|
||||
|
||||
@@ -2139,11 +2155,11 @@ BZIP2_DOWNLOAD_BASE ?= https://sourceware.org/pub/bzip2
|
||||
SNAPPY_VER ?= 1.1.8
|
||||
SNAPPY_SHA256 ?= 16b677f07832a612b0836178db7f374e414f94657c138e6993cbfc5dcc58651f
|
||||
SNAPPY_DOWNLOAD_BASE ?= https://github.com/google/snappy/archive
|
||||
LZ4_VER ?= 1.9.2
|
||||
LZ4_SHA256 ?= 658ba6191fa44c92280d4aa2c271b0f4fbc0e34d249578dd05e50e76d0e5efcc
|
||||
LZ4_VER ?= 1.9.3
|
||||
LZ4_SHA256 ?= 030644df4611007ff7dc962d981f390361e6c97a34e5cbc393ddfbe019ffe2c1
|
||||
LZ4_DOWNLOAD_BASE ?= https://github.com/lz4/lz4/archive
|
||||
ZSTD_VER ?= 1.4.5
|
||||
ZSTD_SHA256 ?= 734d1f565c42f691f8420c8d06783ad818060fc390dee43ae0a89f86d0a4f8c2
|
||||
ZSTD_VER ?= 1.4.9
|
||||
ZSTD_SHA256 ?= acf714d98e3db7b876e5b540cbf6dee298f60eb3c0723104f6d3f065cd60d6a8
|
||||
ZSTD_DOWNLOAD_BASE ?= https://github.com/facebook/zstd/archive
|
||||
CURL_SSL_OPTS ?= --tlsv1
|
||||
|
||||
@@ -2272,7 +2288,7 @@ endif
|
||||
$(MAKE) rocksdbjavastatic_javalib
|
||||
|
||||
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) $(JNI_NATIVE_SOURCES) \
|
||||
@@ -2366,7 +2382,7 @@ rocksdbjava: $(LIB_OBJECTS)
|
||||
ifeq ($(JAVA_HOME),)
|
||||
$(error JAVA_HOME is not set)
|
||||
endif
|
||||
$(AM_V_GEN)cd java;$(MAKE) javalib;
|
||||
$(AM_V_GEN)cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) javalib;
|
||||
$(AM_V_at)rm -f ./java/target/$(ROCKSDBJNILIB)
|
||||
$(AM_V_at)$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC -o ./java/target/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) $(LIB_OBJECTS) $(JAVA_LDFLAGS) $(COVERAGEFLAGS)
|
||||
$(AM_V_at)cd java;jar -cf target/$(ROCKSDB_JAR) HISTORY*.md
|
||||
@@ -2378,13 +2394,13 @@ jclean:
|
||||
cd java;$(MAKE) clean;
|
||||
|
||||
jtest_compile: rocksdbjava
|
||||
cd java;$(MAKE) java_test
|
||||
cd java; SHA256_CMD='$(SHA256_CMD)' $(MAKE) java_test
|
||||
|
||||
jtest_run:
|
||||
cd java;$(MAKE) run_test
|
||||
|
||||
jtest: rocksdbjava
|
||||
cd java;$(MAKE) sample;$(MAKE) test;
|
||||
cd java;$(MAKE) sample; SHA256_CMD='$(SHA256_CMD)' $(MAKE) test;
|
||||
$(PYTHON) tools/check_all_python.py # TODO peterd: find a better place for this check in CI targets
|
||||
|
||||
jdb_bench:
|
||||
|
||||
@@ -135,11 +135,15 @@ def generate_targets(repo_path, deps_map):
|
||||
TARGETS.add_library(
|
||||
"rocksdb_lib",
|
||||
src_mk["LIB_SOURCES"] +
|
||||
# always add range_tree, it's only excluded on ppc64, which we don't use internally
|
||||
src_mk["RANGE_TREE_SOURCES"] +
|
||||
src_mk["TOOL_LIB_SOURCES"])
|
||||
# rocksdb_whole_archive_lib
|
||||
TARGETS.add_library(
|
||||
"rocksdb_whole_archive_lib",
|
||||
src_mk["LIB_SOURCES"] +
|
||||
# always add range_tree, it's only excluded on ppc64, which we don't use internally
|
||||
src_mk["RANGE_TREE_SOURCES"] +
|
||||
src_mk["TOOL_LIB_SOURCES"],
|
||||
deps=None,
|
||||
headers=None,
|
||||
|
||||
@@ -668,6 +668,23 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "`echo $TARGET_ARCHITECTURE | grep ^ppc64`"; then
|
||||
# check for GNU libc on ppc64
|
||||
$CXX -x c++ - -o /dev/null 2>/dev/null <<EOF
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <gnu/libc-version.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("GNU libc version: %s\n", gnu_get_libc_version());
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if [ "$?" != 0 ]; then
|
||||
PPC_LIBC_IS_GNU=0
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$TRY_SSE_ETC"; then
|
||||
# The USE_SSE flag now means "attempt to compile with widely-available
|
||||
# Intel architecture extensions utilized by specific optimizations in the
|
||||
@@ -861,3 +878,6 @@ echo "LUA_PATH=$LUA_PATH" >> "$OUTPUT"
|
||||
if test -n "$USE_FOLLY_DISTRIBUTED_MUTEX"; then
|
||||
echo "USE_FOLLY_DISTRIBUTED_MUTEX=$USE_FOLLY_DISTRIBUTED_MUTEX" >> "$OUTPUT"
|
||||
fi
|
||||
if test -n "$PPC_LIBC_IS_GNU"; then
|
||||
echo "PPC_LIBC_IS_GNU=$PPC_LIBC_IS_GNU" >> "$OUTPUT"
|
||||
fi
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "db/blob/blob_index.h"
|
||||
#include "db/blob/blob_log_format.h"
|
||||
#include "db/blob/blob_log_sequential_reader.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "env/mock_env.h"
|
||||
#include "file/filename.h"
|
||||
#include "file/random_access_file_reader.h"
|
||||
@@ -40,7 +39,9 @@ class TestFileNumberGenerator {
|
||||
|
||||
class BlobFileBuilderTest : public testing::Test {
|
||||
protected:
|
||||
BlobFileBuilderTest() : mock_env_(Env::Default()), fs_(&mock_env_) {}
|
||||
BlobFileBuilderTest() : mock_env_(Env::Default()) {
|
||||
fs_ = mock_env_.GetFileSystem();
|
||||
}
|
||||
|
||||
void VerifyBlobFile(uint64_t blob_file_number,
|
||||
const std::string& blob_file_path,
|
||||
@@ -54,7 +55,7 @@ class BlobFileBuilderTest : public testing::Test {
|
||||
std::unique_ptr<FSRandomAccessFile> file;
|
||||
constexpr IODebugContext* dbg = nullptr;
|
||||
ASSERT_OK(
|
||||
fs_.NewRandomAccessFile(blob_file_path, file_options_, &file, dbg));
|
||||
fs_->NewRandomAccessFile(blob_file_path, file_options_, &file, dbg));
|
||||
|
||||
std::unique_ptr<RandomAccessFileReader> file_reader(
|
||||
new RandomAccessFileReader(std::move(file), blob_file_path,
|
||||
@@ -108,7 +109,7 @@ class BlobFileBuilderTest : public testing::Test {
|
||||
}
|
||||
|
||||
MockEnv mock_env_;
|
||||
LegacyFileSystemWrapper fs_;
|
||||
std::shared_ptr<FileSystem> fs_;
|
||||
FileOptions file_options_;
|
||||
};
|
||||
|
||||
@@ -138,7 +139,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckOneFile) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(),
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
@@ -221,7 +222,7 @@ TEST_F(BlobFileBuilderTest, BuildAndCheckMultipleFiles) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(),
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
@@ -306,7 +307,7 @@ TEST_F(BlobFileBuilderTest, InlinedValues) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(),
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
@@ -358,7 +359,7 @@ TEST_F(BlobFileBuilderTest, Compression) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(),
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
@@ -440,7 +441,7 @@ TEST_F(BlobFileBuilderTest, CompressionError) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(),
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
@@ -517,7 +518,7 @@ TEST_F(BlobFileBuilderTest, Checksum) {
|
||||
std::vector<std::string> blob_file_paths;
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, &fs_,
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &mock_env_, fs_.get(),
|
||||
&immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
@@ -571,12 +572,12 @@ class BlobFileBuilderIOErrorTest
|
||||
BlobFileBuilderIOErrorTest()
|
||||
: mock_env_(Env::Default()),
|
||||
fault_injection_env_(&mock_env_),
|
||||
fs_(&fault_injection_env_),
|
||||
fs_(fault_injection_env_.GetFileSystem()),
|
||||
sync_point_(GetParam()) {}
|
||||
|
||||
MockEnv mock_env_;
|
||||
FaultInjectionTestEnv fault_injection_env_;
|
||||
LegacyFileSystemWrapper fs_;
|
||||
std::shared_ptr<FileSystem> fs_;
|
||||
FileOptions file_options_;
|
||||
std::string sync_point_;
|
||||
};
|
||||
@@ -616,7 +617,7 @@ TEST_P(BlobFileBuilderIOErrorTest, IOError) {
|
||||
std::vector<BlobFileAddition> blob_file_additions;
|
||||
|
||||
BlobFileBuilder builder(TestFileNumberGenerator(), &fault_injection_env_,
|
||||
&fs_, &immutable_cf_options, &mutable_cf_options,
|
||||
fs_.get(), &immutable_cf_options, &mutable_cf_options,
|
||||
&file_options_, job_id, column_family_id,
|
||||
column_family_name, io_priority, write_hint,
|
||||
&blob_file_paths, &blob_file_additions);
|
||||
|
||||
@@ -1388,34 +1388,39 @@ char* rocksdb_property_value_cf(
|
||||
}
|
||||
}
|
||||
|
||||
void rocksdb_approximate_sizes(
|
||||
rocksdb_t* db,
|
||||
int num_ranges,
|
||||
const char* const* range_start_key, const size_t* range_start_key_len,
|
||||
const char* const* range_limit_key, const size_t* range_limit_key_len,
|
||||
uint64_t* sizes) {
|
||||
void rocksdb_approximate_sizes(rocksdb_t* db, int num_ranges,
|
||||
const char* const* range_start_key,
|
||||
const size_t* range_start_key_len,
|
||||
const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len,
|
||||
uint64_t* sizes, char** errptr) {
|
||||
Range* ranges = new Range[num_ranges];
|
||||
for (int i = 0; i < num_ranges; i++) {
|
||||
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);
|
||||
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);
|
||||
}
|
||||
db->rep->GetApproximateSizes(ranges, num_ranges, sizes);
|
||||
Status s = db->rep->GetApproximateSizes(ranges, num_ranges, sizes);
|
||||
if (!s.ok()) {
|
||||
SaveError(errptr, s);
|
||||
}
|
||||
delete[] ranges;
|
||||
}
|
||||
|
||||
void rocksdb_approximate_sizes_cf(
|
||||
rocksdb_t* db,
|
||||
rocksdb_column_family_handle_t* column_family,
|
||||
int num_ranges,
|
||||
const char* const* range_start_key, const size_t* range_start_key_len,
|
||||
const char* const* range_limit_key, const size_t* range_limit_key_len,
|
||||
uint64_t* sizes) {
|
||||
rocksdb_t* db, rocksdb_column_family_handle_t* column_family,
|
||||
int num_ranges, const char* const* range_start_key,
|
||||
const size_t* range_start_key_len, const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len, uint64_t* sizes, char** errptr) {
|
||||
Range* ranges = new Range[num_ranges];
|
||||
for (int i = 0; i < num_ranges; i++) {
|
||||
ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]);
|
||||
ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]);
|
||||
}
|
||||
db->rep->GetApproximateSizes(column_family->rep, ranges, num_ranges, sizes);
|
||||
Status s = db->rep->GetApproximateSizes(column_family->rep, ranges,
|
||||
num_ranges, sizes);
|
||||
if (!s.ok()) {
|
||||
SaveError(errptr, s);
|
||||
}
|
||||
delete[] ranges;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -988,7 +988,9 @@ int main(int argc, char** argv) {
|
||||
&err);
|
||||
CheckNoError(err);
|
||||
}
|
||||
rocksdb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);
|
||||
rocksdb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes,
|
||||
&err);
|
||||
CheckNoError(err);
|
||||
CheckCondition(sizes[0] > 0);
|
||||
CheckCondition(sizes[1] > 0);
|
||||
}
|
||||
|
||||
@@ -187,8 +187,8 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
names_.clear();
|
||||
for (size_t i = 0; i < cf.size(); ++i) {
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]));
|
||||
column_families.emplace_back(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]);
|
||||
names_.push_back(cf[i]);
|
||||
}
|
||||
return DB::Open(db_options_, dbname_, column_families, &handles_, &db_);
|
||||
@@ -199,8 +199,8 @@ class ColumnFamilyTestBase : public testing::Test {
|
||||
std::vector<ColumnFamilyDescriptor> column_families;
|
||||
names_.clear();
|
||||
for (size_t i = 0; i < cf.size(); ++i) {
|
||||
column_families.push_back(ColumnFamilyDescriptor(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]));
|
||||
column_families.emplace_back(
|
||||
cf[i], options.size() == 0 ? column_family_options_ : options[i]);
|
||||
names_.push_back(cf[i]);
|
||||
}
|
||||
return DB::OpenForReadOnly(db_options_, dbname_, column_families, &handles_,
|
||||
@@ -898,9 +898,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> old_files;
|
||||
ASSERT_OK(env_->GetChildren(backup_logs, &old_files));
|
||||
for (auto& file : old_files) {
|
||||
if (file != "." && file != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
|
||||
column_family_options_.merge_operator =
|
||||
@@ -929,9 +927,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> logs;
|
||||
ASSERT_OK(env_->GetChildren(db_options_.wal_dir, &logs));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(db_options_.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
CopyFile(db_options_.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
|
||||
// recover the DB
|
||||
@@ -956,9 +952,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
|
||||
if (iter == 0) {
|
||||
// copy the logs from backup back to wal dir
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, db_options_.wal_dir + "/" + log);
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, db_options_.wal_dir + "/" + log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1449,8 +1449,9 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
} else {
|
||||
sub_compact->builder->Abandon();
|
||||
}
|
||||
IOStatus io_s = sub_compact->builder->io_status();
|
||||
if (s.ok()) {
|
||||
s = sub_compact->builder->io_status();
|
||||
s = io_s;
|
||||
}
|
||||
const uint64_t current_bytes = sub_compact->builder->FileSize();
|
||||
if (s.ok()) {
|
||||
@@ -1461,7 +1462,6 @@ Status CompactionJob::FinishCompactionOutputFile(
|
||||
sub_compact->total_bytes += current_bytes;
|
||||
|
||||
// Finish and check for file errors
|
||||
IOStatus io_s;
|
||||
if (s.ok()) {
|
||||
StopWatch sw(env_, stats_, COMPACTION_OUTFILE_SYNC_MICROS);
|
||||
io_s = sub_compact->outfile->Sync(db_options_.use_fsync);
|
||||
|
||||
@@ -297,15 +297,14 @@ class CompactionJobStatsTest : public testing::Test,
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t Size(const Slice& start, const Slice& limit, int cf = 0) {
|
||||
Status Size(uint64_t* size, const Slice& start, const Slice& limit,
|
||||
int cf = 0) {
|
||||
Range r(start, limit);
|
||||
uint64_t size;
|
||||
if (cf == 0) {
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
return db_->GetApproximateSizes(&r, 1, size);
|
||||
} else {
|
||||
db_->GetApproximateSizes(handles_[1], &r, 1, &size);
|
||||
return db_->GetApproximateSizes(handles_[1], &r, 1, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void Compact(int cf, const Slice& start, const Slice& limit,
|
||||
|
||||
@@ -72,7 +72,7 @@ class CompactionJobTestBase : public testing::Test {
|
||||
CompactionJobTestBase(std::string dbname, const Comparator* ucmp,
|
||||
std::function<std::string(uint64_t)> encode_u64_ts)
|
||||
: env_(Env::Default()),
|
||||
fs_(std::make_shared<LegacyFileSystemWrapper>(env_)),
|
||||
fs_(env_->GetFileSystem()),
|
||||
dbname_(std::move(dbname)),
|
||||
ucmp_(ucmp),
|
||||
db_options_(),
|
||||
|
||||
+27
-1
@@ -21,6 +21,7 @@
|
||||
#if !defined(ROCKSDB_LITE)
|
||||
#include "test_util/sync_point.h"
|
||||
#endif
|
||||
#include "util/file_checksum_helper.h"
|
||||
#include "util/random.h"
|
||||
#include "utilities/fault_injection_env.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
@@ -3273,7 +3274,9 @@ class DeadlineFS : public FileSystemWrapper {
|
||||
|
||||
// Increment the IO counter and return a delay in microseconds
|
||||
IOStatus ShouldDelay(const IOOptions& opts) {
|
||||
if (!deadline_.count() && !io_timeout_.count()) {
|
||||
if (timedout_) {
|
||||
return IOStatus::TimedOut();
|
||||
} else if (!deadline_.count() && !io_timeout_.count()) {
|
||||
return IOStatus::OK();
|
||||
}
|
||||
if (!ignore_deadline_ && delay_trigger_ == io_count_++) {
|
||||
@@ -3580,6 +3583,29 @@ TEST_F(DBBasicTest, VerifyFileChecksums) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_OK(db_->VerifyFileChecksums(ReadOptions()));
|
||||
|
||||
// Does the right thing but with the wrong name -- using it should lead to an
|
||||
// error.
|
||||
class MisnamedFileChecksumGenerator : public FileChecksumGenCrc32c {
|
||||
public:
|
||||
MisnamedFileChecksumGenerator(const FileChecksumGenContext& context)
|
||||
: FileChecksumGenCrc32c(context) {}
|
||||
|
||||
const char* Name() const override { return "sha1"; }
|
||||
};
|
||||
|
||||
class MisnamedFileChecksumGenFactory : public FileChecksumGenCrc32cFactory {
|
||||
public:
|
||||
std::unique_ptr<FileChecksumGenerator> CreateFileChecksumGenerator(
|
||||
const FileChecksumGenContext& context) override {
|
||||
return std::unique_ptr<FileChecksumGenerator>(
|
||||
new MisnamedFileChecksumGenerator(context));
|
||||
}
|
||||
};
|
||||
|
||||
options.file_checksum_gen_factory.reset(new MisnamedFileChecksumGenFactory());
|
||||
Reopen(options);
|
||||
ASSERT_TRUE(db_->VerifyFileChecksums(ReadOptions()).IsInvalidArgument());
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class DBTestCompactionFilterWithCompactParam
|
||||
option_config_ == kUniversalSubcompactions) {
|
||||
assert(options.max_subcompactions > 1);
|
||||
}
|
||||
TryReopen(options);
|
||||
Reopen(options);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -276,7 +276,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
ASSERT_OK(Flush(1));
|
||||
|
||||
@@ -284,10 +284,10 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
// the compaction is each level invokes the filter for
|
||||
// all the keys in that level.
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
@@ -321,6 +321,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
}
|
||||
iter->Next();
|
||||
}
|
||||
ASSERT_OK(iter->status());
|
||||
}
|
||||
ASSERT_EQ(total, 100000);
|
||||
ASSERT_EQ(count, 0);
|
||||
@@ -337,10 +338,10 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
// means that all keys should pass at least once
|
||||
// via the compaction filter
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1, 1), 0);
|
||||
@@ -369,10 +370,10 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
// verify that at the end of the compaction process,
|
||||
// nothing is left.
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 100000);
|
||||
cfilter_count = 0;
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_EQ(cfilter_count, 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1, 1), 0);
|
||||
@@ -387,6 +388,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilter) {
|
||||
count++;
|
||||
iter->Next();
|
||||
}
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_EQ(count, 0);
|
||||
}
|
||||
|
||||
@@ -427,9 +429,9 @@ TEST_F(DBTestCompactionFilter, CompactionFilterDeletesAll) {
|
||||
// put some data
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10 + table; ++i) {
|
||||
Put(ToString(table * 100 + i), "val");
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
// this will produce empty file (delete compaction filter)
|
||||
@@ -440,6 +442,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterDeletesAll) {
|
||||
|
||||
Iterator* itr = db_->NewIterator(ReadOptions());
|
||||
itr->SeekToFirst();
|
||||
ASSERT_OK(itr->status());
|
||||
// empty db
|
||||
ASSERT_TRUE(!itr->Valid());
|
||||
|
||||
@@ -463,25 +466,25 @@ TEST_P(DBTestCompactionFilterWithCompactParam,
|
||||
for (int i = 0; i < 100001; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
|
||||
// push all files to lower levels
|
||||
ASSERT_OK(Flush(1));
|
||||
if (option_config_ != kUniversalCompactionMultiLevel &&
|
||||
option_config_ != kUniversalSubcompactions) {
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
} else {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), handles_[1], nullptr,
|
||||
nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), handles_[1],
|
||||
nullptr, nullptr));
|
||||
}
|
||||
|
||||
// re-write all data again
|
||||
for (int i = 0; i < 100001; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%010d", i);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
|
||||
// push all files to lower levels. This should
|
||||
@@ -489,11 +492,11 @@ TEST_P(DBTestCompactionFilterWithCompactParam,
|
||||
ASSERT_OK(Flush(1));
|
||||
if (option_config_ != kUniversalCompactionMultiLevel &&
|
||||
option_config_ != kUniversalSubcompactions) {
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]);
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]));
|
||||
ASSERT_OK(dbfull()->TEST_CompactRange(1, nullptr, nullptr, handles_[1]));
|
||||
} else {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), handles_[1], nullptr,
|
||||
nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), handles_[1],
|
||||
nullptr, nullptr));
|
||||
}
|
||||
|
||||
// verify that all keys now have the new value that
|
||||
@@ -531,7 +534,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
ASSERT_OK(Flush());
|
||||
std::string newvalue = Get("foo");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("foo");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
|
||||
@@ -539,12 +542,12 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
// merge keys.
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "bar", two));
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("bar");
|
||||
ASSERT_EQ("NOT_FOUND", newvalue);
|
||||
ASSERT_OK(db_->Merge(WriteOptions(), "bar", two));
|
||||
ASSERT_OK(Flush());
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("bar");
|
||||
ASSERT_EQ(two, two);
|
||||
|
||||
@@ -555,7 +558,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
ASSERT_OK(Flush());
|
||||
newvalue = Get("foobar");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("foobar");
|
||||
ASSERT_EQ(newvalue, three);
|
||||
|
||||
@@ -568,7 +571,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterWithMergeOperator) {
|
||||
ASSERT_OK(Flush());
|
||||
newvalue = Get("barfoo");
|
||||
ASSERT_EQ(newvalue, four);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
newvalue = Get("barfoo");
|
||||
ASSERT_EQ(newvalue, four);
|
||||
}
|
||||
@@ -590,21 +593,21 @@ TEST_F(DBTestCompactionFilter, CompactionFilterContextManual) {
|
||||
for (int i = 0; i < num_keys_per_file; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%02d", i, j);
|
||||
Put(key, value);
|
||||
ASSERT_OK(Put(key, value));
|
||||
}
|
||||
dbfull()->TEST_FlushMemTable();
|
||||
ASSERT_OK(dbfull()->TEST_FlushMemTable());
|
||||
// Make sure next file is much smaller so automatic compaction will not
|
||||
// be triggered.
|
||||
num_keys_per_file /= 2;
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
// Force a manual compaction
|
||||
cfilter_count = 0;
|
||||
filter->expect_manual_compaction_.store(true);
|
||||
filter->expect_full_compaction_.store(true);
|
||||
filter->expect_cf_id_.store(0);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(cfilter_count, 700);
|
||||
ASSERT_EQ(NumSortedRuns(0), 1);
|
||||
ASSERT_TRUE(filter->compaction_filter_created());
|
||||
@@ -654,14 +657,14 @@ TEST_F(DBTestCompactionFilter, CompactionFilterContextCfId) {
|
||||
for (int i = 0; i < num_keys_per_file; i++) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "B%08d%02d", i, j);
|
||||
Put(1, key, value);
|
||||
ASSERT_OK(Put(1, key, value));
|
||||
}
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
// Make sure next file is much smaller so automatic compaction will not
|
||||
// be triggered.
|
||||
num_keys_per_file /= 2;
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
ASSERT_TRUE(filter->compaction_filter_created());
|
||||
}
|
||||
@@ -680,9 +683,9 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
const Snapshot* snapshot = nullptr;
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Put(ToString(table * 100 + i), "val");
|
||||
ASSERT_OK(Put(ToString(table * 100 + i), "val"));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
if (table == 0) {
|
||||
snapshot = db_->GetSnapshot();
|
||||
@@ -702,6 +705,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
read_options.snapshot = snapshot;
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
iter->SeekToFirst();
|
||||
ASSERT_OK(iter->status());
|
||||
int count = 0;
|
||||
while (iter->Valid()) {
|
||||
count++;
|
||||
@@ -710,6 +714,7 @@ TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
ASSERT_EQ(count, 6);
|
||||
read_options.snapshot = nullptr;
|
||||
std::unique_ptr<Iterator> iter1(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter1->status());
|
||||
iter1->SeekToFirst();
|
||||
count = 0;
|
||||
while (iter1->Valid()) {
|
||||
@@ -740,9 +745,9 @@ TEST_F(DBTestCompactionFilter, SkipUntil) {
|
||||
for (int i = table * 6; i < 39 + table * 11; ++i) {
|
||||
char key[100];
|
||||
snprintf(key, sizeof(key), "%010d", table * 100 + i);
|
||||
Put(key, std::to_string(table * 1000 + i));
|
||||
ASSERT_OK(Put(key, std::to_string(table * 1000 + i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
cfilter_skips = 0;
|
||||
@@ -781,10 +786,10 @@ TEST_F(DBTestCompactionFilter, SkipUntilWithBloomFilter) {
|
||||
options.create_if_missing = true;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Put("0000000010", "v10");
|
||||
Put("0000000020", "v20"); // skipped
|
||||
Put("0000000050", "v50");
|
||||
Flush();
|
||||
ASSERT_OK(Put("0000000010", "v10"));
|
||||
ASSERT_OK(Put("0000000020", "v20")); // skipped
|
||||
ASSERT_OK(Put("0000000050", "v50"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
cfilter_skips = 0;
|
||||
EXPECT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
@@ -822,13 +827,13 @@ TEST_F(DBTestCompactionFilter, IgnoreSnapshotsFalse) {
|
||||
options.compaction_filter = new TestNotSupportedFilter();
|
||||
DestroyAndReopen(options);
|
||||
|
||||
Put("a", "v10");
|
||||
Put("z", "v20");
|
||||
Flush();
|
||||
ASSERT_OK(Put("a", "v10"));
|
||||
ASSERT_OK(Put("z", "v20"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
Put("a", "v10");
|
||||
Put("z", "v20");
|
||||
Flush();
|
||||
ASSERT_OK(Put("a", "v10"));
|
||||
ASSERT_OK(Put("z", "v20"));
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// Comapction should fail because IgnoreSnapshots() = false
|
||||
EXPECT_TRUE(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr)
|
||||
|
||||
+311
-311
File diff suppressed because it is too large.
Load diff
+21
-20
@@ -102,7 +102,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase) {
|
||||
}
|
||||
|
||||
// Test compact range works
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
// All data should be in the last level.
|
||||
ColumnFamilyMetaData cf_meta;
|
||||
db_->GetColumnFamilyMetaData(&cf_meta);
|
||||
@@ -166,8 +167,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(4U, int_prop);
|
||||
|
||||
@@ -184,8 +185,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(3U, int_prop);
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.num-files-at-level1", &str_prop));
|
||||
@@ -205,8 +206,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(3U, int_prop);
|
||||
|
||||
@@ -234,8 +235,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
}));
|
||||
|
||||
TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:0");
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
ASSERT_EQ(2U, int_prop);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
@@ -264,7 +265,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBase2) {
|
||||
}
|
||||
TEST_SYNC_POINT("DynamicLevelMaxBytesBase2:2");
|
||||
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
thread.join();
|
||||
|
||||
@@ -302,7 +303,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// Compact against empty DB
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
|
||||
uint64_t int_prop;
|
||||
std::string str_prop;
|
||||
@@ -316,13 +317,13 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
ASSERT_OK(
|
||||
Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))), rnd.RandomString(80)));
|
||||
}
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
if (NumTableFilesAtLevel(0) == 0) {
|
||||
// Make sure level 0 is not empty
|
||||
ASSERT_OK(
|
||||
Put(Key(static_cast<int>(rnd.Uniform(kMaxKey))), rnd.RandomString(80)));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(db_->GetIntProperty("rocksdb.base-level", &int_prop));
|
||||
@@ -343,7 +344,7 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesCompactRange) {
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(output_levels.size(), 2);
|
||||
ASSERT_TRUE(output_levels.find(3) != output_levels.end());
|
||||
ASSERT_TRUE(output_levels.find(4) != output_levels.end());
|
||||
@@ -389,8 +390,8 @@ TEST_F(DBTestDynamicLevel, DynamicLevelMaxBytesBaseInc) {
|
||||
PutFixed32(&value, static_cast<uint32_t>(i));
|
||||
ASSERT_OK(Put(Key(i), value));
|
||||
}
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
ASSERT_EQ(non_trivial, 0);
|
||||
@@ -449,7 +450,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
ASSERT_OK(Delete(Key(i / 10)));
|
||||
}
|
||||
verify_func(total_keys, false);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
options.level_compaction_dynamic_level_bytes = true;
|
||||
options.disable_auto_compactions = true;
|
||||
@@ -464,7 +465,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = options.num_levels - 1;
|
||||
dbfull()->CompactRange(compact_options, nullptr, nullptr);
|
||||
ASSERT_OK(dbfull()->CompactRange(compact_options, nullptr, nullptr));
|
||||
compaction_finished.store(true);
|
||||
});
|
||||
do {
|
||||
@@ -484,7 +485,7 @@ TEST_F(DBTestDynamicLevel, DISABLED_MigrateToDynamicLevelMaxBytesBase) {
|
||||
}
|
||||
|
||||
verify_func(total_keys2, false);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
verify_func(total_keys2, false);
|
||||
|
||||
// Base level is not level 1
|
||||
|
||||
@@ -44,7 +44,7 @@ TEST_F(DBEncryptionTest, CheckEncrypted) {
|
||||
Env* target = GetTargetEnv();
|
||||
int hits = 0;
|
||||
for (auto it = fileNames.begin() ; it != fileNames.end(); ++it) {
|
||||
if ((*it == "..") || (*it == ".") || (*it == "LOCK")) {
|
||||
if (*it == "LOCK") {
|
||||
continue;
|
||||
}
|
||||
auto filePath = dbname_ + "/" + *it;
|
||||
|
||||
+41
-13
@@ -53,7 +53,6 @@
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "db/write_callback.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/file_util.h"
|
||||
#include "file/filename.h"
|
||||
#include "file/random_access_file_reader.h"
|
||||
@@ -307,18 +306,21 @@ Status DBImpl::ResumeImpl(DBRecoverContext context) {
|
||||
mutex_.AssertHeld();
|
||||
WaitForBackgroundWork();
|
||||
|
||||
Status bg_error = error_handler_.GetBGError();
|
||||
Status s;
|
||||
if (shutdown_initiated_) {
|
||||
// Returning shutdown status to SFM during auto recovery will cause it
|
||||
// to abort the recovery and allow the shutdown to progress
|
||||
s = Status::ShutdownInProgress();
|
||||
}
|
||||
if (s.ok() && bg_error.severity() > Status::Severity::kHardError) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"DB resume requested but failed due to Fatal/Unrecoverable error");
|
||||
s = bg_error;
|
||||
|
||||
if (s.ok()) {
|
||||
Status bg_error = error_handler_.GetBGError();
|
||||
if (bg_error.severity() > Status::Severity::kHardError) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"DB resume requested but failed due to Fatal/Unrecoverable error");
|
||||
s = bg_error;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the IO Status stored in version set is set to OK.
|
||||
@@ -393,6 +395,11 @@ Status DBImpl::ResumeImpl(DBRecoverContext context) {
|
||||
FindObsoleteFiles(&job_context, true);
|
||||
if (s.ok()) {
|
||||
s = error_handler_.ClearBGError();
|
||||
} else {
|
||||
// NOTE: this is needed to pass ASSERT_STATUS_CHECKED
|
||||
// in the DBSSTTest.DBWithMaxSpaceAllowedRandomized test.
|
||||
// See https://github.com/facebook/rocksdb/pull/7715#issuecomment-754947952
|
||||
error_handler_.GetRecoveryError().PermitUncheckedError();
|
||||
}
|
||||
mutex_.Unlock();
|
||||
|
||||
@@ -409,6 +416,12 @@ Status DBImpl::ResumeImpl(DBRecoverContext context) {
|
||||
if (file_deletion_disabled) {
|
||||
// Always return ok
|
||||
s = EnableFileDeletions(/*force=*/true);
|
||||
if (!s.ok()) {
|
||||
ROCKS_LOG_INFO(
|
||||
immutable_db_options_.info_log,
|
||||
"DB resume requested but could not enable file deletions [%s]",
|
||||
s.ToString().c_str());
|
||||
}
|
||||
}
|
||||
ROCKS_LOG_INFO(immutable_db_options_.info_log, "Successfully resumed DB");
|
||||
}
|
||||
@@ -690,6 +703,18 @@ void DBImpl::PrintStatistics() {
|
||||
|
||||
void DBImpl::StartPeriodicWorkScheduler() {
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
#ifndef NDEBUG
|
||||
// It only used by test to disable scheduler
|
||||
bool disable_scheduler = false;
|
||||
TEST_SYNC_POINT_CALLBACK(
|
||||
"DBImpl::StartPeriodicWorkScheduler:DisableScheduler",
|
||||
&disable_scheduler);
|
||||
if (disable_scheduler) {
|
||||
return;
|
||||
}
|
||||
#endif // !NDEBUG
|
||||
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
periodic_work_scheduler_ = PeriodicWorkScheduler::Default();
|
||||
@@ -1693,7 +1718,9 @@ Status DBImpl::GetImpl(const ReadOptions& read_options, const Slice& key,
|
||||
}
|
||||
// If timestamp is used, we use read callback to ensure <key,t,s> is returned
|
||||
// only if t <= read_opts.timestamp and s <= snapshot.
|
||||
if (ts_sz > 0 && !get_impl_options.callback) {
|
||||
if (ts_sz > 0) {
|
||||
assert(!get_impl_options
|
||||
.callback); // timestamp with callback is not supported
|
||||
read_cb.Refresh(snapshot);
|
||||
get_impl_options.callback = &read_cb;
|
||||
}
|
||||
@@ -2369,8 +2396,9 @@ void DBImpl::MultiGetWithCallback(
|
||||
}
|
||||
|
||||
GetWithTimestampReadCallback timestamp_read_callback(0);
|
||||
ReadCallback* read_callback = nullptr;
|
||||
ReadCallback* read_callback = callback;
|
||||
if (read_options.timestamp && read_options.timestamp->size() > 0) {
|
||||
assert(!read_callback); // timestamp with callback is not supported
|
||||
timestamp_read_callback.Refresh(consistent_seqnum);
|
||||
read_callback = ×tamp_read_callback;
|
||||
}
|
||||
@@ -3099,8 +3127,8 @@ const std::string& DBImpl::GetName() const { return dbname_; }
|
||||
Env* DBImpl::GetEnv() const { return env_; }
|
||||
|
||||
FileSystem* DB::GetFileSystem() const {
|
||||
static LegacyFileSystemWrapper fs_wrap(GetEnv());
|
||||
return &fs_wrap;
|
||||
const auto& fs = GetEnv()->GetFileSystem();
|
||||
return fs.get();
|
||||
}
|
||||
|
||||
FileSystem* DBImpl::GetFileSystem() const {
|
||||
@@ -3574,7 +3602,7 @@ Status DBImpl::DeleteFile(std::string name) {
|
||||
Status DBImpl::DeleteFilesInRanges(ColumnFamilyHandle* column_family,
|
||||
const RangePtr* ranges, size_t n,
|
||||
bool include_end) {
|
||||
Status status;
|
||||
Status status = Status::OK();
|
||||
auto cfh = static_cast_with_check<ColumnFamilyHandleImpl>(column_family);
|
||||
ColumnFamilyData* cfd = cfh->cfd();
|
||||
VersionEdit edit;
|
||||
@@ -3633,7 +3661,7 @@ Status DBImpl::DeleteFilesInRanges(ColumnFamilyHandle* column_family,
|
||||
}
|
||||
if (edit.GetDeletedFiles().empty()) {
|
||||
job_context.Clean();
|
||||
return Status::OK();
|
||||
return status;
|
||||
}
|
||||
input_version->Ref();
|
||||
status = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
|
||||
@@ -954,6 +954,9 @@ class DBImpl : public DB {
|
||||
// is only for the special test of CancelledCompactions
|
||||
Status TEST_WaitForCompact(bool waitUnscheduled = false);
|
||||
|
||||
// Get the background error status
|
||||
Status TEST_GetBGError();
|
||||
|
||||
// Return the maximum overlapping data (in bytes) at next level for any
|
||||
// file at a level >= 1.
|
||||
int64_t TEST_MaxNextLevelOverlappingBytes(
|
||||
|
||||
@@ -35,8 +35,10 @@ bool DBImpl::EnoughRoomForCompaction(
|
||||
// Pass the current bg_error_ to SFM so it can decide what checks to
|
||||
// perform. If this DB instance hasn't seen any error yet, the SFM can be
|
||||
// optimistic and not do disk space checks
|
||||
enough_room =
|
||||
sfm->EnoughRoomForCompaction(cfd, inputs, error_handler_.GetBGError());
|
||||
Status bg_error = error_handler_.GetBGError();
|
||||
enough_room = sfm->EnoughRoomForCompaction(cfd, inputs, bg_error);
|
||||
bg_error.PermitUncheckedError(); // bg_error is just a copy of the Status
|
||||
// from the error_handler_
|
||||
if (enough_room) {
|
||||
*sfm_reserved_compact_space = true;
|
||||
}
|
||||
@@ -284,7 +286,10 @@ Status DBImpl::FlushMemTableToOutputFile(
|
||||
// Notify sst_file_manager that a new file was added
|
||||
std::string file_path = MakeTableFileName(
|
||||
cfd->ioptions()->cf_paths[0].path, file_meta.fd.GetNumber());
|
||||
s = sfm->OnAddFile(file_path);
|
||||
// TODO (PR7798). We should only add the file to the FileManager if it
|
||||
// exists. Otherwise, some tests may fail. Ignore the error in the
|
||||
// interim.
|
||||
sfm->OnAddFile(file_path).PermitUncheckedError();
|
||||
if (sfm->IsMaxAllowedSpaceReached()) {
|
||||
Status new_bg_error =
|
||||
Status::SpaceLimit("Max allowed space was reached");
|
||||
@@ -627,7 +632,10 @@ Status DBImpl::AtomicFlushMemTablesToOutputFiles(
|
||||
if (sfm) {
|
||||
std::string file_path = MakeTableFileName(
|
||||
cfds[i]->ioptions()->cf_paths[0].path, file_meta[i].fd.GetNumber());
|
||||
s = sfm->OnAddFile(file_path);
|
||||
// TODO (PR7798). We should only add the file to the FileManager if it
|
||||
// exists. Otherwise, some tests may fail. Ignore the error in the
|
||||
// interim.
|
||||
sfm->OnAddFile(file_path).PermitUncheckedError();
|
||||
if (sfm->IsMaxAllowedSpaceReached() &&
|
||||
error_handler_.GetBGError().ok()) {
|
||||
Status new_bg_error =
|
||||
|
||||
@@ -177,6 +177,11 @@ Status DBImpl::TEST_WaitForCompact(bool wait_unscheduled) {
|
||||
return error_handler_.GetBGError();
|
||||
}
|
||||
|
||||
Status DBImpl::TEST_GetBGError() {
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
return error_handler_.GetBGError();
|
||||
}
|
||||
|
||||
void DBImpl::TEST_LockMutex() { mutex_.Lock(); }
|
||||
|
||||
void DBImpl::TEST_UnlockMutex() { mutex_.Unlock(); }
|
||||
|
||||
+68
-46
@@ -43,11 +43,15 @@ TEST_F(DBIOFailureTest, DropWrites) {
|
||||
if (level > 0 && level == dbfull()->NumberLevels() - 1) {
|
||||
break;
|
||||
}
|
||||
dbfull()->TEST_CompactRange(level, nullptr, nullptr, nullptr,
|
||||
true /* disallow trivial move */);
|
||||
Status s =
|
||||
dbfull()->TEST_CompactRange(level, nullptr, nullptr, nullptr,
|
||||
true /* disallow trivial move */);
|
||||
ASSERT_TRUE(s.ok() || s.IsCorruption());
|
||||
}
|
||||
} else {
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
Status s =
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_TRUE(s.ok() || s.IsCorruption());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +60,8 @@ TEST_F(DBIOFailureTest, DropWrites) {
|
||||
ASSERT_EQ("5", property_value);
|
||||
|
||||
env_->drop_writes_.store(false, std::memory_order_release);
|
||||
ASSERT_LT(CountFiles(), num_files + 3);
|
||||
const size_t count = CountFiles();
|
||||
ASSERT_LT(count, num_files + 3);
|
||||
|
||||
// Check that compaction attempts slept after errors
|
||||
// TODO @krad: Figure out why ASSERT_EQ 5 keeps failing in certain compiler
|
||||
@@ -82,7 +87,8 @@ TEST_F(DBIOFailureTest, DropWritesFlush) {
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.background-errors", &property_value));
|
||||
ASSERT_EQ("0", property_value);
|
||||
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
// ASSERT file is too short
|
||||
ASSERT_TRUE(dbfull()->TEST_FlushMemTable(true).IsCorruption());
|
||||
|
||||
ASSERT_TRUE(db_->GetProperty("rocksdb.background-errors", &property_value));
|
||||
ASSERT_EQ("1", property_value);
|
||||
@@ -166,7 +172,7 @@ TEST_F(DBIOFailureTest, ManifestWriteError) {
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
|
||||
// Memtable compaction (will succeed)
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
const int last = 2;
|
||||
MoveFilesToLevel(2);
|
||||
@@ -174,7 +180,8 @@ TEST_F(DBIOFailureTest, ManifestWriteError) {
|
||||
|
||||
// Merging compaction (will fail)
|
||||
error_type->store(true, std::memory_order_release);
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr); // Should fail
|
||||
ASSERT_NOK(
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr)); // Should fail
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
|
||||
error_type->store(false, std::memory_order_release);
|
||||
@@ -192,7 +199,13 @@ TEST_F(DBIOFailureTest, ManifestWriteError) {
|
||||
|
||||
// Merging compaction (will fail)
|
||||
error_type->store(true, std::memory_order_release);
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr); // Should fail
|
||||
Status s =
|
||||
dbfull()->TEST_CompactRange(last, nullptr, nullptr); // Should fail
|
||||
if (iter == 0) {
|
||||
ASSERT_OK(s);
|
||||
} else {
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
}
|
||||
ASSERT_EQ("bar", Get("foo"));
|
||||
|
||||
// Recovery: should not lose data
|
||||
@@ -220,18 +233,15 @@ TEST_F(DBIOFailureTest, PutFailsParanoid) {
|
||||
options.paranoid_checks = true;
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
// simulate error
|
||||
env_->log_write_error_.store(true, std::memory_order_release);
|
||||
s = Put(1, "foo2", "bar2");
|
||||
ASSERT_TRUE(!s.ok());
|
||||
ASSERT_NOK(Put(1, "foo2", "bar2"));
|
||||
env_->log_write_error_.store(false, std::memory_order_release);
|
||||
s = Put(1, "foo3", "bar3");
|
||||
// the next put should fail, too
|
||||
ASSERT_TRUE(!s.ok());
|
||||
ASSERT_NOK(Put(1, "foo3", "bar3"));
|
||||
// but we're still able to read
|
||||
ASSERT_EQ("bar", Get(1, "foo"));
|
||||
|
||||
@@ -244,12 +254,10 @@ TEST_F(DBIOFailureTest, PutFailsParanoid) {
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
// simulate error
|
||||
env_->log_write_error_.store(true, std::memory_order_release);
|
||||
s = Put(1, "foo2", "bar2");
|
||||
ASSERT_TRUE(!s.ok());
|
||||
ASSERT_NOK(Put(1, "foo2", "bar2"));
|
||||
env_->log_write_error_.store(false, std::memory_order_release);
|
||||
s = Put(1, "foo3", "bar3");
|
||||
// the next put should NOT fail
|
||||
ASSERT_TRUE(s.ok());
|
||||
ASSERT_OK(Put(1, "foo3", "bar3"));
|
||||
}
|
||||
#if !(defined NDEBUG) || !defined(OS_WIN)
|
||||
TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
@@ -269,14 +277,14 @@ TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
const char* io_error_msg = "range sync dummy error";
|
||||
std::atomic<int> range_sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::RangeSync", [&](void* arg) {
|
||||
if (range_sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("range sync dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
@@ -298,7 +306,9 @@ TEST_F(DBIOFailureTest, FlushSstRangeSyncError) {
|
||||
ASSERT_OK(Put(1, "foo3_2", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo3_3", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo4", "bar"));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
Status s = dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -328,7 +338,6 @@ TEST_F(DBIOFailureTest, CompactSstRangeSyncError) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
Random rnd(301);
|
||||
std::string rnd_str =
|
||||
@@ -342,21 +351,22 @@ TEST_F(DBIOFailureTest, CompactSstRangeSyncError) {
|
||||
ASSERT_OK(Put(1, "foo1_1", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo1_2", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo1_3", rnd_str));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo3_1", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo3_2", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo3_3", rnd_str));
|
||||
ASSERT_OK(Put(1, "foo4", "bar"));
|
||||
Flush(1);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable(handles_[1]));
|
||||
|
||||
const char* io_error_msg = "range sync dummy error";
|
||||
std::atomic<int> range_sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::RangeSync", [&](void* arg) {
|
||||
if (range_sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("range sync dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
@@ -365,7 +375,9 @@ TEST_F(DBIOFailureTest, CompactSstRangeSyncError) {
|
||||
{
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
Status s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -389,13 +401,14 @@ TEST_F(DBIOFailureTest, FlushSstCloseError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
const char* io_error_msg = "close dummy error";
|
||||
std::atomic<int> close_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Close", [&](void* arg) {
|
||||
if (close_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("close dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -404,7 +417,9 @@ TEST_F(DBIOFailureTest, FlushSstCloseError) {
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
Status s = dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -429,25 +444,25 @@ TEST_F(DBIOFailureTest, CompactionSstCloseError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar3"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
const char* io_error_msg = "close dummy error";
|
||||
std::atomic<int> close_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Close", [&](void* arg) {
|
||||
if (close_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("close dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -456,7 +471,9 @@ TEST_F(DBIOFailureTest, CompactionSstCloseError) {
|
||||
{
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
Status s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as compaction failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -480,13 +497,14 @@ TEST_F(DBIOFailureTest, FlushSstSyncError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
const char* io_error_msg = "sync dummy error";
|
||||
std::atomic<int> sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Sync", [&](void* arg) {
|
||||
if (sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("sync dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -495,7 +513,9 @@ TEST_F(DBIOFailureTest, FlushSstSyncError) {
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo1", "bar1"));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
Status s = dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as flush failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
@@ -521,25 +541,25 @@ TEST_F(DBIOFailureTest, CompactionSstSyncError) {
|
||||
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
Status s;
|
||||
|
||||
ASSERT_OK(Put(1, "foo", "bar"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar2"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(Put(1, "foo", "bar3"));
|
||||
ASSERT_OK(Put(1, "foo2", "bar"));
|
||||
Flush(1);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_OK(Flush(1));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
|
||||
const char* io_error_msg = "sync dummy error";
|
||||
std::atomic<int> sync_called(0);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"SpecialEnv::SStableFile::Sync", [&](void* arg) {
|
||||
if (sync_called.fetch_add(1) == 0) {
|
||||
Status* st = static_cast<Status*>(arg);
|
||||
*st = Status::IOError("close dummy error");
|
||||
*st = Status::IOError(io_error_msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -548,7 +568,9 @@ TEST_F(DBIOFailureTest, CompactionSstSyncError) {
|
||||
{
|
||||
{"disable_auto_compactions", "false"},
|
||||
}));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
Status s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_TRUE(s.IsIOError());
|
||||
ASSERT_STREQ(s.getState(), io_error_msg);
|
||||
|
||||
// Following writes should fail as compaction failed.
|
||||
ASSERT_NOK(Put(1, "foo2", "bar3"));
|
||||
|
||||
@@ -190,10 +190,11 @@ TEST_F(DBOptionsTest, SetWalBytesPerSync) {
|
||||
options.env = env_;
|
||||
Reopen(options);
|
||||
ASSERT_EQ(512, dbfull()->GetDBOptions().wal_bytes_per_sync);
|
||||
int counter = 0;
|
||||
std::atomic_int counter{0};
|
||||
int low_bytes_per_sync = 0;
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WritableFileWriter::RangeSync:0", [&](void* /*arg*/) { counter++; });
|
||||
"WritableFileWriter::RangeSync:0",
|
||||
[&](void* /*arg*/) { counter.fetch_add(1); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
const std::string kValue(kValueSize, 'v');
|
||||
int i = 0;
|
||||
|
||||
+42
-20
@@ -98,7 +98,7 @@ TEST_F(DBSSTTest, SSTsWithLdbSuffixHandling) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
GenerateNewFile(&rnd, &key_id, false);
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
Close();
|
||||
int const num_files = GetSstFileCount(dbname_);
|
||||
ASSERT_GT(num_files, 0);
|
||||
@@ -374,6 +374,14 @@ TEST_F(DBSSTTest, RateLimitedDelete) {
|
||||
*abs_time_us = Env::Default()->NowMicros();
|
||||
});
|
||||
|
||||
// Disable PeriodicWorkScheduler as it also has TimedWait, which could update
|
||||
// the simulated sleep time
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::StartPeriodicWorkScheduler:DisableScheduler", [&](void* arg) {
|
||||
bool* disable_scheduler = static_cast<bool*>(arg);
|
||||
*disable_scheduler = true;
|
||||
});
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
Options options = CurrentOptions();
|
||||
@@ -393,7 +401,7 @@ TEST_F(DBSSTTest, RateLimitedDelete) {
|
||||
|
||||
WriteOptions wo;
|
||||
wo.disableWAL = true;
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
// Create 4 files in L0
|
||||
for (char v = 'a'; v <= 'd'; v++) {
|
||||
ASSERT_OK(Put("Key2", DummyString(1024, v), wo));
|
||||
@@ -540,7 +548,7 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
auto sfm = static_cast<SstFileManagerImpl*>(options.sst_file_manager.get());
|
||||
sfm->delete_scheduler()->SetMaxTrashDBRatio(3.1);
|
||||
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
|
||||
// Create 4 files in L0
|
||||
for (char v = 'a'; v <= 'd'; v++) {
|
||||
@@ -567,11 +575,11 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
if (!wal_dir_same_as_dbname_) {
|
||||
// Forcibly create some trash log files
|
||||
std::unique_ptr<WritableFile> result;
|
||||
env->NewWritableFile(options.wal_dir + "/1000.log.trash", &result,
|
||||
EnvOptions());
|
||||
ASSERT_OK(env->NewWritableFile(options.wal_dir + "/1000.log.trash", &result,
|
||||
EnvOptions()));
|
||||
result.reset();
|
||||
}
|
||||
env->GetChildren(options.wal_dir, &filenames);
|
||||
ASSERT_OK(env->GetChildren(options.wal_dir, &filenames));
|
||||
for (const std::string& fname : filenames) {
|
||||
if (fname.find(".log.trash") != std::string::npos) {
|
||||
trash_log_count++;
|
||||
@@ -580,11 +588,11 @@ TEST_P(DBWALTestWithParam, WALTrashCleanupOnOpen) {
|
||||
ASSERT_GE(trash_log_count, 1);
|
||||
|
||||
env->set_fake_log_delete(false);
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
|
||||
filenames.clear();
|
||||
trash_log_count = 0;
|
||||
env->GetChildren(options.wal_dir, &filenames);
|
||||
ASSERT_OK(env->GetChildren(options.wal_dir, &filenames));
|
||||
for (const std::string& fname : filenames) {
|
||||
if (fname.find(".log.trash") != std::string::npos) {
|
||||
trash_log_count++;
|
||||
@@ -614,7 +622,7 @@ TEST_F(DBSSTTest, OpenDBWithExistingTrash) {
|
||||
ASSERT_OK(WriteStringToFile(env_, "abc", dbname_ + "/" + "003.sst.trash"));
|
||||
|
||||
// Reopen the DB and verify that it deletes existing trash files
|
||||
ASSERT_OK(TryReopen(options));
|
||||
Reopen(options);
|
||||
sfm->WaitForEmptyTrash();
|
||||
ASSERT_NOK(env_->FileExists(dbname_ + "/" + "001.sst.trash"));
|
||||
ASSERT_NOK(env_->FileExists(dbname_ + "/" + "002.sst.trash"));
|
||||
@@ -872,10 +880,12 @@ TEST_F(DBSSTTest, CancellingManualCompactionsWorks) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
// OK, now trigger a manual compaction
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_TRUE(dbfull()
|
||||
->CompactRange(CompactRangeOptions(), nullptr, nullptr)
|
||||
.IsCompactionTooLarge());
|
||||
|
||||
// Wait for manual compaction to get scheduled and finish
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_EQ(sfm->GetCompactionsReservedSize(), 0);
|
||||
// Make sure the stat is bumped
|
||||
@@ -885,10 +895,13 @@ TEST_F(DBSSTTest, CancellingManualCompactionsWorks) {
|
||||
|
||||
// Now make sure CompactFiles also gets cancelled
|
||||
auto l0_files = collector->GetFlushedFiles();
|
||||
dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files, 0);
|
||||
ASSERT_TRUE(
|
||||
dbfull()
|
||||
->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files, 0)
|
||||
.IsCompactionTooLarge());
|
||||
|
||||
// Wait for manual compaction to get scheduled and finish
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_EQ(dbfull()->immutable_db_options().statistics.get()->getTickerCount(
|
||||
COMPACTION_CANCELLED),
|
||||
@@ -903,8 +916,9 @@ TEST_F(DBSSTTest, CancellingManualCompactionsWorks) {
|
||||
"CompactFilesImpl:End", [&](void* /*arg*/) { completed_compactions++; });
|
||||
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(), l0_files, 0);
|
||||
dbfull()->TEST_WaitForCompact(true);
|
||||
ASSERT_OK(dbfull()->CompactFiles(ROCKSDB_NAMESPACE::CompactionOptions(),
|
||||
l0_files, 0));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact(true));
|
||||
|
||||
ASSERT_EQ(sfm->GetCompactionsReservedSize(), 0);
|
||||
ASSERT_GT(completed_compactions, 0);
|
||||
@@ -1008,7 +1022,7 @@ TEST_F(DBSSTTest, OpenDBWithInfiniteMaxOpenFiles) {
|
||||
CompactRangeOptions compact_options;
|
||||
compact_options.change_level = true;
|
||||
compact_options.target_level = 2;
|
||||
db_->CompactRange(compact_options, nullptr, nullptr);
|
||||
ASSERT_OK(db_->CompactRange(compact_options, nullptr, nullptr));
|
||||
|
||||
// Create 12 Files in L0
|
||||
for (int i = 0; i < 12; i++) {
|
||||
@@ -1060,7 +1074,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
std::string val = "val_file_" + ToString(i);
|
||||
ASSERT_OK(Put(Key(j), val));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ("5", FilesPerLevel(0));
|
||||
|
||||
@@ -1084,6 +1098,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter1->status());
|
||||
|
||||
// Compact 5 files into 1 file in L0
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
@@ -1107,12 +1122,13 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter2(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter2->status());
|
||||
|
||||
// Delete all keys and compact, this will delete all live files
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ("", FilesPerLevel(0));
|
||||
|
||||
@@ -1126,6 +1142,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
// Total SST files = 6 (5 original files + compacted file)
|
||||
ASSERT_EQ(total_sst_files_size, 6 * single_file_size);
|
||||
|
||||
ASSERT_OK(iter1->status());
|
||||
iter1.reset();
|
||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
|
||||
&total_sst_files_size));
|
||||
@@ -1133,6 +1150,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSize) {
|
||||
// Total SST files = 1 (compacted file)
|
||||
ASSERT_EQ(total_sst_files_size, 1 * single_file_size);
|
||||
|
||||
ASSERT_OK(iter2->status());
|
||||
iter2.reset();
|
||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
|
||||
&total_sst_files_size));
|
||||
@@ -1151,7 +1169,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
// Generate 5 files in L0
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ASSERT_OK(Put(Key(i), "val"));
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
}
|
||||
ASSERT_EQ("5", FilesPerLevel(0));
|
||||
|
||||
@@ -1176,6 +1194,7 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter1->status());
|
||||
|
||||
// Compaction will do trivial move from L0 to L1
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
@@ -1199,12 +1218,13 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
|
||||
// hold current version
|
||||
std::unique_ptr<Iterator> iter2(dbfull()->NewIterator(ReadOptions()));
|
||||
ASSERT_OK(iter2->status());
|
||||
|
||||
// Delete all keys and compact, this will delete all live files
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
}
|
||||
Flush();
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ("", FilesPerLevel(0));
|
||||
|
||||
@@ -1218,7 +1238,9 @@ TEST_F(DBSSTTest, GetTotalSstFilesSizeVersionsFilesShared) {
|
||||
// Total SST files = 5 (used in 2 version)
|
||||
ASSERT_EQ(total_sst_files_size, 5 * single_file_size);
|
||||
|
||||
ASSERT_OK(iter1->status());
|
||||
iter1.reset();
|
||||
ASSERT_OK(iter2->status());
|
||||
iter2.reset();
|
||||
|
||||
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.total-sst-files-size",
|
||||
|
||||
@@ -31,6 +31,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorSingle) {
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
iter->SeekToFirst();
|
||||
ASSERT_TRUE(!iter->Valid());
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
// add a record and check that iter can see it
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "mirko", "fodor"));
|
||||
@@ -48,6 +49,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorKeepAdding) {
|
||||
read_options.tailing = true;
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
std::string value(1024, 'a');
|
||||
|
||||
const int num_records = 10000;
|
||||
@@ -70,7 +72,9 @@ TEST_F(DBTestTailingIterator, TailingIteratorSeekToNext) {
|
||||
read_options.tailing = true;
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
std::unique_ptr<Iterator> itern(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(itern->status());
|
||||
std::string value(1024, 'a');
|
||||
|
||||
const int num_records = 1000;
|
||||
@@ -138,8 +142,11 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
Slice keyu(bufe, 20);
|
||||
read_options.iterate_upper_bound = &keyu;
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
std::unique_ptr<Iterator> itern(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(itern->status());
|
||||
std::unique_ptr<Iterator> iterh(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iterh->status());
|
||||
std::string value(1024, 'a');
|
||||
bool file_iters_deleted = false;
|
||||
bool file_iters_renewed_null = false;
|
||||
@@ -225,6 +232,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
read_options.read_tier = kBlockCacheTier;
|
||||
std::unique_ptr<Iterator> iteri(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iteri->status());
|
||||
char buf5[32];
|
||||
snprintf(buf5, sizeof(buf5), "00a0%016d", (num_records / 2) * 5 - 2);
|
||||
Slice target1(buf5, 20);
|
||||
@@ -236,6 +244,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
options.table_factory.reset(NewBlockBasedTableFactory());
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
iter.reset(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
for (int i = 2 * num_records; i > 0; --i) {
|
||||
char buf1[32];
|
||||
char buf2[32];
|
||||
@@ -262,6 +271,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorDeletes) {
|
||||
read_options.tailing = true;
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
// write a single record, read it using the iterator, then delete it
|
||||
ASSERT_OK(Put(1, "0test", "test"));
|
||||
@@ -309,6 +319,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorPrefixSeek) {
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_OK(Put(1, "0101", "test"));
|
||||
|
||||
ASSERT_OK(Flush(1));
|
||||
@@ -339,6 +350,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorIncomplete) {
|
||||
ASSERT_OK(db_->Put(WriteOptions(), key, value));
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
iter->SeekToFirst();
|
||||
// we either see the entry or it's not in cache
|
||||
ASSERT_TRUE(iter->Valid() || iter->status().IsIncomplete());
|
||||
@@ -369,6 +381,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorSeekToSame) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
// Seek to 00001. We expect to find 00002.
|
||||
std::string start_key = "00001";
|
||||
iter->Seek(start_key);
|
||||
@@ -404,6 +417,7 @@ TEST_F(DBTestTailingIterator, TailingIteratorUpperBound) {
|
||||
ASSERT_OK(Put(1, "21", "21"));
|
||||
|
||||
std::unique_ptr<Iterator> it(db_->NewIterator(read_options, handles_[1]));
|
||||
ASSERT_OK(it->status());
|
||||
it->Seek("12");
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("12", it->key().ToString());
|
||||
@@ -479,6 +493,8 @@ TEST_F(DBTestTailingIterator, TailingIteratorGap) {
|
||||
it->Next();
|
||||
ASSERT_TRUE(it->Valid());
|
||||
ASSERT_EQ("40", it->key().ToString());
|
||||
|
||||
ASSERT_OK(it->status());
|
||||
}
|
||||
|
||||
TEST_F(DBTestTailingIterator, SeekWithUpperBoundBug) {
|
||||
@@ -497,6 +513,7 @@ TEST_F(DBTestTailingIterator, SeekWithUpperBoundBug) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
iter->Seek("aa");
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
@@ -519,6 +536,7 @@ TEST_F(DBTestTailingIterator, SeekToFirstWithUpperBoundBug) {
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
ASSERT_OK(iter->status());
|
||||
|
||||
iter->SeekToFirst();
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
|
||||
+75
-42
@@ -1337,17 +1337,19 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
SizeApproximationOptions size_approx_options;
|
||||
size_approx_options.include_memtabtles = true;
|
||||
size_approx_options.include_files = true;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_GT(size, 6000);
|
||||
ASSERT_LT(size, 204800);
|
||||
// Zero if not including mem table
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(500);
|
||||
end = Key(600);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
@@ -1357,13 +1359,15 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
start = Key(500);
|
||||
end = Key(600);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(100);
|
||||
end = Key(1020);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_GT(size, 6000);
|
||||
|
||||
options.max_write_buffer_number = 8;
|
||||
@@ -1389,29 +1393,32 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
start = Key(100);
|
||||
end = Key(300);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(1050);
|
||||
end = Key(1080);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_GT(size, 6000);
|
||||
|
||||
start = Key(2100);
|
||||
end = Key(2300);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(1050);
|
||||
end = Key(1080);
|
||||
r = Range(start, end);
|
||||
uint64_t size_with_mt, size_without_mt;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt));
|
||||
ASSERT_GT(size_with_mt, 6000);
|
||||
db_->GetApproximateSizes(&r, 1, &size_without_mt);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size_without_mt));
|
||||
ASSERT_EQ(size_without_mt, 0);
|
||||
|
||||
Flush();
|
||||
@@ -1423,15 +1430,16 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
start = Key(1050);
|
||||
end = Key(1080);
|
||||
r = Range(start, end);
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt);
|
||||
db_->GetApproximateSizes(&r, 1, &size_without_mt);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size_with_mt));
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size_without_mt));
|
||||
ASSERT_GT(size_with_mt, size_without_mt);
|
||||
ASSERT_GT(size_without_mt, 6000);
|
||||
|
||||
// Check that include_memtabtles flag works as expected
|
||||
size_approx_options.include_memtabtles = false;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
ASSERT_EQ(size, size_without_mt);
|
||||
|
||||
// Check that files_size_error_margin works as expected, when the heuristic
|
||||
@@ -1440,10 +1448,12 @@ TEST_F(DBTest, ApproximateSizesMemTable) {
|
||||
end = Key(1000 + N - 2);
|
||||
r = Range(start, end);
|
||||
size_approx_options.files_size_error_margin = -1.0; // disabled
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size));
|
||||
uint64_t size2;
|
||||
size_approx_options.files_size_error_margin = 0.5; // enabled, but not used
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size2);
|
||||
ASSERT_OK(
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size2));
|
||||
ASSERT_EQ(size, size2);
|
||||
}
|
||||
|
||||
@@ -1494,14 +1504,16 @@ TEST_F(DBTest, ApproximateSizesFilesWithErrorMargin) {
|
||||
|
||||
// Get the precise size without any approximation heuristic
|
||||
uint64_t size;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size));
|
||||
ASSERT_NE(size, 0);
|
||||
|
||||
// Get the size with an approximation heuristic
|
||||
uint64_t size2;
|
||||
const double error_margin = 0.2;
|
||||
size_approx_options.files_size_error_margin = error_margin;
|
||||
db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1, &size2);
|
||||
ASSERT_OK(db_->GetApproximateSizes(size_approx_options, default_cf, &r, 1,
|
||||
&size2));
|
||||
ASSERT_LT(size2, size * (1 + error_margin));
|
||||
ASSERT_GT(size2, size * (1 - error_margin));
|
||||
}
|
||||
@@ -1517,7 +1529,7 @@ TEST_F(DBTest, ApproximateSizesFilesWithErrorMargin) {
|
||||
const std::string end = Key(i + 11); // overlap by 1 key
|
||||
const Range r(start, end);
|
||||
uint64_t size;
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size));
|
||||
ASSERT_LE(size, 11 * 100);
|
||||
}
|
||||
}
|
||||
@@ -1585,9 +1597,12 @@ TEST_F(DBTest, ApproximateSizes) {
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
ASSERT_TRUE(Between(Size("", "xyz", 1), 0, 0));
|
||||
uint64_t size;
|
||||
ASSERT_OK(Size("", "xyz", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
ASSERT_TRUE(Between(Size("", "xyz", 1), 0, 0));
|
||||
ASSERT_OK(Size("", "xyz", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
|
||||
// Write 8MB (80 values, each 100K)
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
@@ -1600,7 +1615,8 @@ TEST_F(DBTest, ApproximateSizes) {
|
||||
}
|
||||
|
||||
// 0 because GetApproximateSizes() does not account for memtable space
|
||||
ASSERT_TRUE(Between(Size("", Key(50), 1), 0, 0));
|
||||
ASSERT_OK(Size("", Key(50), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
|
||||
// Check sizes across recovery by reopening a few times
|
||||
for (int run = 0; run < 3; run++) {
|
||||
@@ -1608,14 +1624,17 @@ TEST_F(DBTest, ApproximateSizes) {
|
||||
|
||||
for (int compact_start = 0; compact_start < N; compact_start += 10) {
|
||||
for (int i = 0; i < N; i += 10) {
|
||||
ASSERT_TRUE(Between(Size("", Key(i), 1), S1 * i, S2 * i));
|
||||
ASSERT_TRUE(Between(Size("", Key(i) + ".suffix", 1), S1 * (i + 1),
|
||||
S2 * (i + 1)));
|
||||
ASSERT_TRUE(Between(Size(Key(i), Key(i + 10), 1), S1 * 10, S2 * 10));
|
||||
ASSERT_OK(Size("", Key(i), 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * i, S2 * i));
|
||||
ASSERT_OK(Size("", Key(i) + ".suffix", 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * (i + 1), S2 * (i + 1)));
|
||||
ASSERT_OK(Size(Key(i), Key(i + 10), 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * 10, S2 * 10));
|
||||
}
|
||||
ASSERT_TRUE(Between(Size("", Key(50), 1), S1 * 50, S2 * 50));
|
||||
ASSERT_TRUE(
|
||||
Between(Size("", Key(50) + ".suffix", 1), S1 * 50, S2 * 50));
|
||||
ASSERT_OK(Size("", Key(50), 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * 50, S2 * 50));
|
||||
ASSERT_OK(Size("", Key(50) + ".suffix", 1, &size));
|
||||
ASSERT_TRUE(Between(size, S1 * 50, S2 * 50));
|
||||
|
||||
std::string cstart_str = Key(compact_start);
|
||||
std::string cend_str = Key(compact_start + 9);
|
||||
@@ -1650,21 +1669,32 @@ TEST_F(DBTest, ApproximateSizes_MixOfSmallAndLarge) {
|
||||
ASSERT_OK(Put(1, Key(7), rnd.RandomString(10000)));
|
||||
|
||||
// Check sizes across recovery by reopening a few times
|
||||
uint64_t size;
|
||||
for (int run = 0; run < 3; run++) {
|
||||
ReopenWithColumnFamilies({"default", "pikachu"}, options);
|
||||
|
||||
ASSERT_TRUE(Between(Size("", Key(0), 1), 0, 0));
|
||||
ASSERT_TRUE(Between(Size("", Key(1), 1), 10000, 11000));
|
||||
ASSERT_TRUE(Between(Size("", Key(2), 1), 20000, 21000));
|
||||
ASSERT_TRUE(Between(Size("", Key(3), 1), 120000, 121000));
|
||||
ASSERT_TRUE(Between(Size("", Key(4), 1), 130000, 131000));
|
||||
ASSERT_TRUE(Between(Size("", Key(5), 1), 230000, 232000));
|
||||
ASSERT_TRUE(Between(Size("", Key(6), 1), 240000, 242000));
|
||||
ASSERT_OK(Size("", Key(0), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 0));
|
||||
ASSERT_OK(Size("", Key(1), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 10000, 11000));
|
||||
ASSERT_OK(Size("", Key(2), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 20000, 21000));
|
||||
ASSERT_OK(Size("", Key(3), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 120000, 121000));
|
||||
ASSERT_OK(Size("", Key(4), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 130000, 131000));
|
||||
ASSERT_OK(Size("", Key(5), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 230000, 232000));
|
||||
ASSERT_OK(Size("", Key(6), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 240000, 242000));
|
||||
// Ensure some overhead is accounted for, even without including all
|
||||
ASSERT_TRUE(Between(Size("", Key(7), 1), 540500, 545000));
|
||||
ASSERT_TRUE(Between(Size("", Key(8), 1), 550500, 555000));
|
||||
ASSERT_OK(Size("", Key(7), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 540500, 545000));
|
||||
ASSERT_OK(Size("", Key(8), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 550500, 555000));
|
||||
|
||||
ASSERT_TRUE(Between(Size(Key(3), Key(5), 1), 110100, 111000));
|
||||
ASSERT_OK(Size(Key(3), Key(5), 1, &size));
|
||||
ASSERT_TRUE(Between(size, 110100, 111000));
|
||||
|
||||
dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
|
||||
}
|
||||
@@ -1748,6 +1778,7 @@ TEST_F(DBTest, Snapshot) {
|
||||
TEST_F(DBTest, HiddenValuesAreRemoved) {
|
||||
anon::OptionsOverride options_override;
|
||||
options_override.skip_policy = kSkipNoSnapshot;
|
||||
uint64_t size;
|
||||
do {
|
||||
Options options = CurrentOptions(options_override);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
@@ -1765,7 +1796,8 @@ TEST_F(DBTest, HiddenValuesAreRemoved) {
|
||||
ASSERT_GT(NumTableFilesAtLevel(0, 1), 0);
|
||||
|
||||
ASSERT_EQ(big, Get(1, "foo", snapshot));
|
||||
ASSERT_TRUE(Between(Size("", "pastfoo", 1), 50000, 60000));
|
||||
ASSERT_OK(Size("", "pastfoo", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 50000, 60000));
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
ASSERT_EQ(AllEntriesFor("foo", 1), "[ tiny, " + big + " ]");
|
||||
Slice x("x");
|
||||
@@ -1776,7 +1808,8 @@ TEST_F(DBTest, HiddenValuesAreRemoved) {
|
||||
dbfull()->TEST_CompactRange(1, nullptr, &x, handles_[1]);
|
||||
ASSERT_EQ(AllEntriesFor("foo", 1), "[ tiny ]");
|
||||
|
||||
ASSERT_TRUE(Between(Size("", "pastfoo", 1), 0, 1000));
|
||||
ASSERT_OK(Size("", "pastfoo", 1, &size));
|
||||
ASSERT_TRUE(Between(size, 0, 1000));
|
||||
// ApproximateOffsetOf() is not yet implemented in plain table format,
|
||||
// which is used by Size().
|
||||
} while (ChangeOptions(kSkipUniversalCompaction | kSkipFIFOCompaction |
|
||||
|
||||
+31
-18
@@ -41,9 +41,7 @@ TEST_F(DBTest2, OpenForReadOnly) {
|
||||
std::vector<std::string> files;
|
||||
ASSERT_OK(env_->GetChildren(dbname, &files));
|
||||
for (auto& f : files) {
|
||||
if (f != "." && f != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
// <dbname> should be empty now and we should be able to delete it
|
||||
ASSERT_OK(env_->DeleteDir(dbname));
|
||||
@@ -75,9 +73,7 @@ TEST_F(DBTest2, OpenForReadOnlyWithColumnFamilies) {
|
||||
std::vector<std::string> files;
|
||||
ASSERT_OK(env_->GetChildren(dbname, &files));
|
||||
for (auto& f : files) {
|
||||
if (f != "." && f != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(dbname + "/" + f));
|
||||
}
|
||||
// <dbname> should be empty now and we should be able to delete it
|
||||
ASSERT_OK(env_->DeleteDir(dbname));
|
||||
@@ -3685,20 +3681,26 @@ TEST_F(DBTest2, LiveFilesOmitObsoleteFiles) {
|
||||
|
||||
TEST_F(DBTest2, TestNumPread) {
|
||||
Options options = CurrentOptions();
|
||||
bool prefetch_supported =
|
||||
test::IsPrefetchSupported(env_->GetFileSystem(), dbname_);
|
||||
// disable block cache
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.no_block_cache = true;
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
Reopen(options);
|
||||
env_->count_random_reads_ = true;
|
||||
|
||||
env_->random_file_open_counter_.store(0);
|
||||
ASSERT_OK(Put("bar", "foo"));
|
||||
ASSERT_OK(Put("foo", "bar"));
|
||||
ASSERT_OK(Flush());
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
if (prefetch_supported) {
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
} else {
|
||||
// With prefetch not supported, we will do a single read into a buffer
|
||||
ASSERT_EQ(1, env_->random_read_counter_.Read());
|
||||
}
|
||||
ASSERT_EQ(1, env_->random_file_open_counter_.load());
|
||||
|
||||
// One pread per a normal data block read
|
||||
@@ -3714,19 +3716,30 @@ TEST_F(DBTest2, TestNumPread) {
|
||||
ASSERT_OK(Put("bar2", "foo2"));
|
||||
ASSERT_OK(Put("foo2", "bar2"));
|
||||
ASSERT_OK(Flush());
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
if (prefetch_supported) {
|
||||
// After flush, we'll open the file and read footer, meta block,
|
||||
// property block and index block.
|
||||
ASSERT_EQ(4, env_->random_read_counter_.Read());
|
||||
} else {
|
||||
// With prefetch not supported, we will do a single read into a buffer
|
||||
ASSERT_EQ(1, env_->random_read_counter_.Read());
|
||||
}
|
||||
ASSERT_EQ(1, env_->random_file_open_counter_.load());
|
||||
|
||||
// Compaction needs two input blocks, which requires 2 preads, and
|
||||
// generate a new SST file which needs 4 preads (footer, meta block,
|
||||
// property block and index block). In total 6.
|
||||
env_->random_file_open_counter_.store(0);
|
||||
env_->random_read_counter_.Reset();
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(6, env_->random_read_counter_.Read());
|
||||
// All compactin input files should have already been opened.
|
||||
if (prefetch_supported) {
|
||||
// Compaction needs two input blocks, which requires 2 preads, and
|
||||
// generate a new SST file which needs 4 preads (footer, meta block,
|
||||
// property block and index block). In total 6.
|
||||
ASSERT_EQ(6, env_->random_read_counter_.Read());
|
||||
} else {
|
||||
// With prefetch off, compaction needs two input blocks,
|
||||
// followed by a single buffered read. In total 3.
|
||||
ASSERT_EQ(3, env_->random_read_counter_.Read());
|
||||
}
|
||||
// All compaction input files should have already been opened.
|
||||
ASSERT_EQ(1, env_->random_file_open_counter_.load());
|
||||
|
||||
// One pread per a normal data block read
|
||||
|
||||
+33
-12
@@ -1128,27 +1128,48 @@ std::string DBTestBase::FilesPerLevel(int cf) {
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
size_t DBTestBase::CountFiles() {
|
||||
size_t count = 0;
|
||||
std::vector<std::string> files;
|
||||
EXPECT_OK(env_->GetChildren(dbname_, &files));
|
||||
|
||||
std::vector<std::string> logfiles;
|
||||
if (dbname_ != last_options_.wal_dir) {
|
||||
Status s = env_->GetChildren(last_options_.wal_dir, &logfiles);
|
||||
EXPECT_TRUE(s.ok() || s.IsNotFound());
|
||||
if (env_->GetChildren(dbname_, &files).ok()) {
|
||||
count += files.size();
|
||||
}
|
||||
|
||||
return files.size() + logfiles.size();
|
||||
if (dbname_ != last_options_.wal_dir) {
|
||||
if (env_->GetChildren(last_options_.wal_dir, &files).ok()) {
|
||||
count += files.size();
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
Status DBTestBase::CountFiles(size_t* count) {
|
||||
std::vector<std::string> files;
|
||||
Status s = env_->GetChildren(dbname_, &files);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
size_t files_count = files.size();
|
||||
|
||||
if (dbname_ != last_options_.wal_dir) {
|
||||
s = env_->GetChildren(last_options_.wal_dir, &files);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
*count = files_count + files.size();
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
uint64_t DBTestBase::Size(const Slice& start, const Slice& limit, int cf) {
|
||||
Status DBTestBase::Size(const Slice& start, const Slice& limit, int cf,
|
||||
uint64_t* size) {
|
||||
Range r(start, limit);
|
||||
uint64_t size;
|
||||
if (cf == 0) {
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
return db_->GetApproximateSizes(&r, 1, size);
|
||||
} else {
|
||||
db_->GetApproximateSizes(handles_[1], &r, 1, &size);
|
||||
return db_->GetApproximateSizes(handles_[1], &r, 1, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void DBTestBase::Compact(int cf, const Slice& start, const Slice& limit,
|
||||
|
||||
+7
-1
@@ -1070,7 +1070,13 @@ class DBTestBase : public testing::Test {
|
||||
|
||||
size_t CountFiles();
|
||||
|
||||
uint64_t Size(const Slice& start, const Slice& limit, int cf = 0);
|
||||
Status CountFiles(size_t* count);
|
||||
|
||||
Status Size(const Slice& start, const Slice& limit, uint64_t* size) {
|
||||
return Size(start, limit, 0, size);
|
||||
}
|
||||
|
||||
Status Size(const Slice& start, const Slice& limit, int cf, uint64_t* size);
|
||||
|
||||
void Compact(int cf, const Slice& start, const Slice& limit,
|
||||
uint32_t target_path_id);
|
||||
|
||||
+7
-17
@@ -506,9 +506,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> old_files;
|
||||
ASSERT_OK(env_->GetChildren(backup_logs, &old_files));
|
||||
for (auto& file : old_files) {
|
||||
if (file != "." && file != "..") {
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + file));
|
||||
}
|
||||
Options options = CurrentOptions();
|
||||
options.create_if_missing = true;
|
||||
@@ -528,9 +526,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
std::vector<std::string> logs;
|
||||
ASSERT_OK(env_->GetChildren(options.wal_dir, &logs));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(options.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
CopyFile(options.wal_dir + "/" + log, backup_logs + "/" + log);
|
||||
}
|
||||
|
||||
// recover the DB
|
||||
@@ -541,9 +537,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
|
||||
// copy the logs from backup back to wal dir
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
// this should ignore the log files, recovery should not happen again
|
||||
// if the recovery happens, the same merge operator would be called twice,
|
||||
@@ -559,9 +553,7 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
// copy the logs from backup back to wal dir
|
||||
ASSERT_OK(env_->CreateDirIfMissing(options.wal_dir));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
}
|
||||
// assert that we successfully recovered only from logs, even though we
|
||||
// destroyed the DB
|
||||
@@ -574,11 +566,9 @@ TEST_F(DBWALTest, IgnoreRecoveredLog) {
|
||||
// copy the logs from backup back to wal dir
|
||||
ASSERT_OK(env_->CreateDirIfMissing(options.wal_dir));
|
||||
for (auto& log : logs) {
|
||||
if (log != ".." && log != ".") {
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
// we won't be needing this file no more
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + log));
|
||||
}
|
||||
CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log);
|
||||
// we won't be needing this file no more
|
||||
ASSERT_OK(env_->DeleteFile(backup_logs + "/" + log));
|
||||
}
|
||||
Status s = TryReopen(options);
|
||||
ASSERT_NOK(s);
|
||||
|
||||
@@ -270,7 +270,7 @@ TEST_F(DBBasicTestWithTimestamp, GetApproximateSizes) {
|
||||
ASSERT_EQ(range_sizes[1], size);
|
||||
|
||||
// Zero if not including mem table
|
||||
db_->GetApproximateSizes(&r, 1, &size);
|
||||
ASSERT_OK(db_->GetApproximateSizes(&r, 1, &size));
|
||||
ASSERT_EQ(size, 0);
|
||||
|
||||
start = Key(500);
|
||||
|
||||
+27
-19
@@ -350,12 +350,17 @@ const Status& ErrorHandler::SetBGError(const Status& bg_err,
|
||||
|
||||
// This is the main function for looking at IO related error during the
|
||||
// background operations. The main logic is:
|
||||
// 1) File scope IO error is treated as retryable IO error in the write
|
||||
// path. In RocksDB, If a file has write IO error and it is at file scope,
|
||||
// RocksDB never write to the same file again. RocksDB will create a new
|
||||
// file and rewrite the whole content. Thus, it is retryable.
|
||||
// 1) if the error is caused by data loss, the error is mapped to
|
||||
// unrecoverable error. Application/user must take action to handle
|
||||
// this situation.
|
||||
// 2) if the error is a Retryable IO error, auto resume will be called and the
|
||||
// auto resume can be controlled by resume count and resume interval
|
||||
// options. There are three sub-cases:
|
||||
// this situation (File scope case is excluded).
|
||||
// 2) if the error is a Retryable IO error (i.e., it is a file scope IO error,
|
||||
// or its retryable flag is set and not a data loss error), auto resume
|
||||
// will be called and the auto resume can be controlled by resume count
|
||||
// and resume interval options. There are three sub-cases:
|
||||
// a) if the error happens during compaction, it is mapped to a soft error.
|
||||
// the compaction thread will reschedule a new compaction.
|
||||
// b) if the error happens during flush and also WAL is empty, it is mapped
|
||||
@@ -384,9 +389,10 @@ const Status& ErrorHandler::SetBGError(const IOStatus& bg_io_err,
|
||||
|
||||
Status new_bg_io_err = bg_io_err;
|
||||
DBRecoverContext context;
|
||||
if (bg_io_err.GetDataLoss()) {
|
||||
// First, data loss is treated as unrecoverable error. So it can directly
|
||||
// overwrite any existing bg_error_.
|
||||
if (bg_io_err.GetScope() != IOStatus::IOErrorScope::kIOErrorScopeFile &&
|
||||
bg_io_err.GetDataLoss()) {
|
||||
// First, data loss (non file scope) is treated as unrecoverable error. So
|
||||
// it can directly overwrite any existing bg_error_.
|
||||
bool auto_recovery = false;
|
||||
Status bg_err(new_bg_io_err, Status::Severity::kUnrecoverableError);
|
||||
bg_error_ = bg_err;
|
||||
@@ -397,23 +403,25 @@ const Status& ErrorHandler::SetBGError(const IOStatus& bg_io_err,
|
||||
&bg_err, db_mutex_, &auto_recovery);
|
||||
recover_context_ = context;
|
||||
return bg_error_;
|
||||
} else if (bg_io_err.GetRetryable()) {
|
||||
// Second, check if the error is a retryable IO error or not. if it is
|
||||
// retryable error and its severity is higher than bg_error_, overwrite
|
||||
// the bg_error_ with new error.
|
||||
// In current stage, for retryable IO error of compaction, treat it as
|
||||
// soft error. In other cases, treat the retryable IO error as hard
|
||||
// error.
|
||||
} else if (bg_io_err.GetScope() ==
|
||||
IOStatus::IOErrorScope::kIOErrorScopeFile ||
|
||||
bg_io_err.GetRetryable()) {
|
||||
// Second, check if the error is a retryable IO error (file scope IO error
|
||||
// is also treated as retryable IO error in RocksDB write path). if it is
|
||||
// retryable error and its severity is higher than bg_error_, overwrite the
|
||||
// bg_error_ with new error. In current stage, for retryable IO error of
|
||||
// compaction, treat it as soft error. In other cases, treat the retryable
|
||||
// IO error as hard error.
|
||||
bool auto_recovery = false;
|
||||
EventHelpers::NotifyOnBackgroundError(db_options_.listeners, reason,
|
||||
&new_bg_io_err, db_mutex_,
|
||||
&auto_recovery);
|
||||
if (BackgroundErrorReason::kCompaction == reason) {
|
||||
Status bg_err(new_bg_io_err, Status::Severity::kSoftError);
|
||||
if (bg_err.severity() > bg_error_.severity()) {
|
||||
bg_error_ = bg_err;
|
||||
}
|
||||
recover_context_ = context;
|
||||
// We map the retryable IO error during compaction to soft error. Since
|
||||
// compaction can reschedule by itself. We will not set the BG error in
|
||||
// this case
|
||||
// TODO: a better way to set or clean the retryable IO error which
|
||||
// happens during compaction SST file write.
|
||||
return bg_error_;
|
||||
} else if (BackgroundErrorReason::kFlushNoWAL == reason ||
|
||||
BackgroundErrorReason::kManifestWriteNoWAL == reason) {
|
||||
|
||||
+186
-4
@@ -241,6 +241,90 @@ TEST_F(DBErrorHandlingFSTest, FLushWritRetryableError) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, FLushWritFileScopeError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_env_.get();
|
||||
options.create_if_missing = true;
|
||||
options.listeners.emplace_back(listener);
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
|
||||
listener->EnableAutoRecovery(false);
|
||||
DestroyAndReopen(options);
|
||||
|
||||
IOStatus error_msg = IOStatus::IOError("File Scope Data Loss Error");
|
||||
error_msg.SetDataLoss(true);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFile);
|
||||
error_msg.SetRetryable(false);
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val1"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeFinishBuildTable",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val1", Get(Key(1)));
|
||||
|
||||
ASSERT_OK(Put(Key(2), "val2"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeSyncTable",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val2", Get(Key(2)));
|
||||
|
||||
ASSERT_OK(Put(Key(3), "val3"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeCloseTableFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val3", Get(Key(3)));
|
||||
|
||||
// not file scope, but retyrable set
|
||||
error_msg.SetDataLoss(false);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFileSystem);
|
||||
error_msg.SetRetryable(true);
|
||||
|
||||
ASSERT_OK(Put(Key(3), "val3"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"BuildTable:BeforeCloseTableFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val3", Get(Key(3)));
|
||||
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, FLushWritNoWALRetryableError1) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
@@ -453,6 +537,52 @@ TEST_F(DBErrorHandlingFSTest, ManifestWriteRetryableError) {
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, ManifestWriteFileScopeError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_env_.get();
|
||||
options.create_if_missing = true;
|
||||
options.listeners.emplace_back(listener);
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
std::string old_manifest;
|
||||
std::string new_manifest;
|
||||
|
||||
listener->EnableAutoRecovery(false);
|
||||
DestroyAndReopen(options);
|
||||
old_manifest = GetManifestNameFromLiveFiles();
|
||||
|
||||
IOStatus error_msg = IOStatus::IOError("File Scope Data Loss Error");
|
||||
error_msg.SetDataLoss(true);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFile);
|
||||
error_msg.SetRetryable(false);
|
||||
|
||||
ASSERT_OK(Put(Key(0), "val"));
|
||||
ASSERT_OK(Flush());
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionSet::LogAndApply:WriteManifest",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
s = Flush();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kHardError);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
|
||||
new_manifest = GetManifestNameFromLiveFiles();
|
||||
ASSERT_NE(new_manifest, old_manifest);
|
||||
|
||||
Reopen(options);
|
||||
ASSERT_EQ("val", Get(Key(0)));
|
||||
ASSERT_EQ("val", Get(Key(1)));
|
||||
Close();
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, ManifestWriteNoWALRetryableError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
@@ -762,14 +892,67 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableError) {
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"CompactionJob::OpenCompactionOutputFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:Finish",
|
||||
[&](void*) { CancelAllBackgroundWork(dbfull()); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kSoftError);
|
||||
s = dbfull()->TEST_GetBGError();
|
||||
ASSERT_OK(s);
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
s = dbfull()->Resume();
|
||||
ASSERT_OK(s);
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
TEST_F(DBErrorHandlingFSTest, CompactionWriteFileScopeError) {
|
||||
std::shared_ptr<ErrorHandlerFSListener> listener(
|
||||
new ErrorHandlerFSListener());
|
||||
Options options = GetDefaultOptions();
|
||||
options.env = fault_env_.get();
|
||||
options.create_if_missing = true;
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.listeners.emplace_back(listener);
|
||||
options.max_bgerror_resume_count = 0;
|
||||
Status s;
|
||||
DestroyAndReopen(options);
|
||||
|
||||
IOStatus error_msg = IOStatus::IOError("File Scope Data Loss Error");
|
||||
error_msg.SetDataLoss(true);
|
||||
error_msg.SetScope(
|
||||
ROCKSDB_NAMESPACE::IOStatus::IOErrorScope::kIOErrorScopeFile);
|
||||
error_msg.SetRetryable(false);
|
||||
|
||||
ASSERT_OK(Put(Key(0), "va;"));
|
||||
ASSERT_OK(Put(Key(2), "va;"));
|
||||
s = Flush();
|
||||
ASSERT_OK(s);
|
||||
|
||||
listener->OverrideBGError(Status(error_msg, Status::Severity::kHardError));
|
||||
listener->EnableAutoRecovery(false);
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"DBImpl::FlushMemTable:FlushMemTableFinished",
|
||||
"BackgroundCallCompaction:0"}});
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"CompactionJob::OpenCompactionOutputFile",
|
||||
[&](void*) { fault_fs_->SetFilesystemActive(false, error_msg); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::BackgroundCompaction:Finish",
|
||||
[&](void*) { CancelAllBackgroundWork(dbfull()); });
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_OK(Put(Key(1), "val"));
|
||||
s = Flush();
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_GetBGError();
|
||||
ASSERT_OK(s);
|
||||
|
||||
fault_fs_->SetFilesystemActive(true);
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
@@ -2012,8 +2195,7 @@ TEST_F(DBErrorHandlingFSTest, CompactionWriteRetryableErrorAutoRecover) {
|
||||
ASSERT_OK(s);
|
||||
|
||||
s = dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(s.severity(), ROCKSDB_NAMESPACE::Status::Severity::kSoftError);
|
||||
|
||||
ASSERT_OK(s);
|
||||
TEST_SYNC_POINT("CompactionWriteRetryableErrorAutoRecover0");
|
||||
SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
|
||||
+8
-9
@@ -213,17 +213,16 @@ void EventHelpers::NotifyOnErrorRecoveryCompleted(
|
||||
const std::vector<std::shared_ptr<EventListener>>& listeners,
|
||||
Status old_bg_error, InstrumentedMutex* db_mutex) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (listeners.size() == 0U) {
|
||||
return;
|
||||
}
|
||||
db_mutex->AssertHeld();
|
||||
// release lock while notifying events
|
||||
db_mutex->Unlock();
|
||||
for (auto& listener : listeners) {
|
||||
listener->OnErrorRecoveryCompleted(old_bg_error);
|
||||
if (listeners.size() > 0) {
|
||||
db_mutex->AssertHeld();
|
||||
// release lock while notifying events
|
||||
db_mutex->Unlock();
|
||||
for (auto& listener : listeners) {
|
||||
listener->OnErrorRecoveryCompleted(old_bg_error);
|
||||
}
|
||||
db_mutex->Lock();
|
||||
}
|
||||
old_bg_error.PermitUncheckedError();
|
||||
db_mutex->Lock();
|
||||
#else
|
||||
(void)listeners;
|
||||
(void)old_bg_error;
|
||||
|
||||
@@ -32,7 +32,7 @@ class FlushJobTestBase : public testing::Test {
|
||||
protected:
|
||||
FlushJobTestBase(std::string dbname, const Comparator* ucmp)
|
||||
: env_(Env::Default()),
|
||||
fs_(std::make_shared<LegacyFileSystemWrapper>(env_)),
|
||||
fs_(env_->GetFileSystem()),
|
||||
dbname_(std::move(dbname)),
|
||||
ucmp_(ucmp),
|
||||
options_(),
|
||||
|
||||
+61
-88
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "db/log_reader.h"
|
||||
#include "db/log_writer.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/sequence_file_reader.h"
|
||||
#include "file/writable_file_writer.h"
|
||||
#include "rocksdb/env.h"
|
||||
@@ -50,7 +49,7 @@ static std::string RandomSkewedString(int i, Random* rnd) {
|
||||
// get<1>(tuple): true if allow retry after read EOF, false otherwise
|
||||
class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
private:
|
||||
class StringSource : public SequentialFile {
|
||||
class StringSource : public FSSequentialFile {
|
||||
public:
|
||||
Slice& contents_;
|
||||
bool force_error_;
|
||||
@@ -68,7 +67,8 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
returned_partial_(false),
|
||||
fail_after_read_partial_(fail_after_read_partial) {}
|
||||
|
||||
Status Read(size_t n, Slice* result, char* scratch) override {
|
||||
IOStatus Read(size_t n, const IOOptions& /*opts*/, Slice* result,
|
||||
char* scratch, IODebugContext* /*dbg*/) override {
|
||||
if (fail_after_read_partial_) {
|
||||
EXPECT_TRUE(!returned_partial_) << "must not Read() after eof/error";
|
||||
}
|
||||
@@ -81,7 +81,7 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
contents_.remove_prefix(force_error_position_);
|
||||
force_error_ = false;
|
||||
returned_partial_ = true;
|
||||
return Status::Corruption("read error");
|
||||
return IOStatus::Corruption("read error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,28 +106,21 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
*result = Slice(scratch, n);
|
||||
|
||||
contents_.remove_prefix(n);
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
|
||||
Status Skip(uint64_t n) override {
|
||||
IOStatus Skip(uint64_t n) override {
|
||||
if (n > contents_.size()) {
|
||||
contents_.clear();
|
||||
return Status::NotFound("in-memory file skipepd past end");
|
||||
return IOStatus::NotFound("in-memory file skipepd past end");
|
||||
}
|
||||
|
||||
contents_.remove_prefix(n);
|
||||
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
};
|
||||
|
||||
inline StringSource* GetStringSourceFromLegacyReader(
|
||||
SequentialFileReader* reader) {
|
||||
LegacySequentialFileWrapper* file =
|
||||
static_cast<LegacySequentialFileWrapper*>(reader->file());
|
||||
return static_cast<StringSource*>(file->target());
|
||||
}
|
||||
|
||||
class ReportCollector : public Reader::Reporter {
|
||||
public:
|
||||
size_t dropped_bytes_;
|
||||
@@ -140,29 +133,17 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
}
|
||||
};
|
||||
|
||||
std::string& dest_contents() {
|
||||
auto dest = test::GetStringSinkFromLegacyWriter(writer_.file());
|
||||
assert(dest);
|
||||
return dest->contents_;
|
||||
}
|
||||
std::string& dest_contents() { return sink_->contents_; }
|
||||
|
||||
const std::string& dest_contents() const {
|
||||
auto dest = test::GetStringSinkFromLegacyWriter(writer_.file());
|
||||
assert(dest);
|
||||
return dest->contents_;
|
||||
}
|
||||
const std::string& dest_contents() const { return sink_->contents_; }
|
||||
|
||||
void reset_source_contents() {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
assert(src);
|
||||
src->contents_ = dest_contents();
|
||||
}
|
||||
void reset_source_contents() { source_->contents_ = dest_contents(); }
|
||||
|
||||
Slice reader_contents_;
|
||||
std::unique_ptr<WritableFileWriter> dest_holder_;
|
||||
std::unique_ptr<SequentialFileReader> source_holder_;
|
||||
test::StringSink* sink_;
|
||||
StringSource* source_;
|
||||
ReportCollector report_;
|
||||
Writer writer_;
|
||||
std::unique_ptr<Writer> writer_;
|
||||
std::unique_ptr<Reader> reader_;
|
||||
|
||||
protected:
|
||||
@@ -171,19 +152,23 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
public:
|
||||
LogTest()
|
||||
: reader_contents_(),
|
||||
dest_holder_(test::GetWritableFileWriter(
|
||||
new test::StringSink(&reader_contents_), "" /* don't care */)),
|
||||
source_holder_(test::GetSequentialFileReader(
|
||||
new StringSource(reader_contents_, !std::get<1>(GetParam())),
|
||||
"" /* file name */)),
|
||||
writer_(std::move(dest_holder_), 123, std::get<0>(GetParam())),
|
||||
sink_(new test::StringSink(&reader_contents_)),
|
||||
source_(new StringSource(reader_contents_, !std::get<1>(GetParam()))),
|
||||
allow_retry_read_(std::get<1>(GetParam())) {
|
||||
std::unique_ptr<FSWritableFile> sink_holder(sink_);
|
||||
std::unique_ptr<WritableFileWriter> file_writer(new WritableFileWriter(
|
||||
std::move(sink_holder), "" /* don't care */, FileOptions()));
|
||||
writer_.reset(
|
||||
new Writer(std::move(file_writer), 123, std::get<0>(GetParam())));
|
||||
std::unique_ptr<FSSequentialFile> source_holder(source_);
|
||||
std::unique_ptr<SequentialFileReader> file_reader(
|
||||
new SequentialFileReader(std::move(source_holder), "" /* file name */));
|
||||
if (allow_retry_read_) {
|
||||
reader_.reset(new FragmentBufferedReader(
|
||||
nullptr, std::move(source_holder_), &report_, true /* checksum */,
|
||||
123 /* log_number */));
|
||||
reader_.reset(new FragmentBufferedReader(nullptr, std::move(file_reader),
|
||||
&report_, true /* checksum */,
|
||||
123 /* log_number */));
|
||||
} else {
|
||||
reader_.reset(new Reader(nullptr, std::move(source_holder_), &report_,
|
||||
reader_.reset(new Reader(nullptr, std::move(file_reader), &report_,
|
||||
true /* checksum */, 123 /* log_number */));
|
||||
}
|
||||
}
|
||||
@@ -191,7 +176,7 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
Slice* get_reader_contents() { return &reader_contents_; }
|
||||
|
||||
void Write(const std::string& msg) {
|
||||
ASSERT_OK(writer_.AddRecord(Slice(msg)));
|
||||
ASSERT_OK(writer_->AddRecord(Slice(msg)));
|
||||
}
|
||||
|
||||
size_t WrittenBytes() const {
|
||||
@@ -219,11 +204,7 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
dest_contents()[offset] = new_byte;
|
||||
}
|
||||
|
||||
void ShrinkSize(int bytes) {
|
||||
auto dest = test::GetStringSinkFromLegacyWriter(writer_.file());
|
||||
assert(dest);
|
||||
dest->Drop(bytes);
|
||||
}
|
||||
void ShrinkSize(int bytes) { sink_->Drop(bytes); }
|
||||
|
||||
void FixChecksum(int header_offset, int len, bool recyclable) {
|
||||
// Compute crc of type/len/data
|
||||
@@ -235,9 +216,8 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
}
|
||||
|
||||
void ForceError(size_t position = 0) {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
src->force_error_ = true;
|
||||
src->force_error_position_ = position;
|
||||
source_->force_error_ = true;
|
||||
source_->force_error_position_ = position;
|
||||
}
|
||||
|
||||
size_t DroppedBytes() const {
|
||||
@@ -249,14 +229,12 @@ class LogTest : public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
}
|
||||
|
||||
void ForceEOF(size_t position = 0) {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
src->force_eof_ = true;
|
||||
src->force_eof_position_ = position;
|
||||
source_->force_eof_ = true;
|
||||
source_->force_eof_position_ = position;
|
||||
}
|
||||
|
||||
void UnmarkEOF() {
|
||||
auto src = GetStringSourceFromLegacyReader(reader_->file());
|
||||
src->returned_partial_ = false;
|
||||
source_->returned_partial_ = false;
|
||||
reader_->UnmarkEOF();
|
||||
}
|
||||
|
||||
@@ -685,9 +663,10 @@ TEST_P(LogTest, Recycle) {
|
||||
while (get_reader_contents()->size() < log::kBlockSize * 2) {
|
||||
Write("xxxxxxxxxxxxxxxx");
|
||||
}
|
||||
std::unique_ptr<WritableFileWriter> dest_holder(test::GetWritableFileWriter(
|
||||
new test::OverwritingStringSink(get_reader_contents()),
|
||||
"" /* don't care */));
|
||||
std::unique_ptr<FSWritableFile> sink(
|
||||
new test::OverwritingStringSink(get_reader_contents()));
|
||||
std::unique_ptr<WritableFileWriter> dest_holder(new WritableFileWriter(
|
||||
std::move(sink), "" /* don't care */, FileOptions()));
|
||||
Writer recycle_writer(std::move(dest_holder), 123, true);
|
||||
ASSERT_OK(recycle_writer.AddRecord(Slice("foooo")));
|
||||
ASSERT_OK(recycle_writer.AddRecord(Slice("bar")));
|
||||
@@ -718,10 +697,9 @@ class RetriableLogTest : public ::testing::TestWithParam<int> {
|
||||
};
|
||||
|
||||
Slice contents_;
|
||||
std::unique_ptr<WritableFileWriter> dest_holder_;
|
||||
test::StringSink* sink_;
|
||||
std::unique_ptr<Writer> log_writer_;
|
||||
Env* env_;
|
||||
EnvOptions env_options_;
|
||||
const std::string test_dir_;
|
||||
const std::string log_file_;
|
||||
std::unique_ptr<WritableFileWriter> writer_;
|
||||
@@ -732,55 +710,50 @@ class RetriableLogTest : public ::testing::TestWithParam<int> {
|
||||
public:
|
||||
RetriableLogTest()
|
||||
: contents_(),
|
||||
dest_holder_(nullptr),
|
||||
sink_(new test::StringSink(&contents_)),
|
||||
log_writer_(nullptr),
|
||||
env_(Env::Default()),
|
||||
test_dir_(test::PerThreadDBPath("retriable_log_test")),
|
||||
log_file_(test_dir_ + "/log"),
|
||||
writer_(nullptr),
|
||||
reader_(nullptr),
|
||||
log_reader_(nullptr) {}
|
||||
log_reader_(nullptr) {
|
||||
std::unique_ptr<FSWritableFile> sink_holder(sink_);
|
||||
std::unique_ptr<WritableFileWriter> wfw(new WritableFileWriter(
|
||||
std::move(sink_holder), "" /* file name */, FileOptions()));
|
||||
log_writer_.reset(new Writer(std::move(wfw), 123, GetParam()));
|
||||
}
|
||||
|
||||
Status SetupTestEnv() {
|
||||
dest_holder_.reset(test::GetWritableFileWriter(
|
||||
new test::StringSink(&contents_), "" /* file name */));
|
||||
assert(dest_holder_ != nullptr);
|
||||
log_writer_.reset(new Writer(std::move(dest_holder_), 123, GetParam()));
|
||||
assert(log_writer_ != nullptr);
|
||||
|
||||
Status s;
|
||||
s = env_->CreateDirIfMissing(test_dir_);
|
||||
std::unique_ptr<WritableFile> writable_file;
|
||||
FileOptions fopts;
|
||||
auto fs = env_->GetFileSystem();
|
||||
s = fs->CreateDirIfMissing(test_dir_, IOOptions(), nullptr);
|
||||
std::unique_ptr<FSWritableFile> writable_file;
|
||||
if (s.ok()) {
|
||||
s = env_->NewWritableFile(log_file_, &writable_file, env_options_);
|
||||
s = fs->NewWritableFile(log_file_, fopts, &writable_file, nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
writer_.reset(new WritableFileWriter(
|
||||
NewLegacyWritableFileWrapper(std::move(writable_file)), log_file_,
|
||||
env_options_));
|
||||
assert(writer_ != nullptr);
|
||||
writer_.reset(
|
||||
new WritableFileWriter(std::move(writable_file), log_file_, fopts));
|
||||
EXPECT_NE(writer_, nullptr);
|
||||
}
|
||||
std::unique_ptr<SequentialFile> seq_file;
|
||||
std::unique_ptr<FSSequentialFile> seq_file;
|
||||
if (s.ok()) {
|
||||
s = env_->NewSequentialFile(log_file_, &seq_file, env_options_);
|
||||
s = fs->NewSequentialFile(log_file_, fopts, &seq_file, nullptr);
|
||||
}
|
||||
if (s.ok()) {
|
||||
reader_.reset(new SequentialFileReader(
|
||||
NewLegacySequentialFileWrapper(seq_file), log_file_));
|
||||
assert(reader_ != nullptr);
|
||||
reader_.reset(new SequentialFileReader(std::move(seq_file), log_file_));
|
||||
EXPECT_NE(reader_, nullptr);
|
||||
log_reader_.reset(new FragmentBufferedReader(
|
||||
nullptr, std::move(reader_), &report_, true /* checksum */,
|
||||
123 /* log_number */));
|
||||
assert(log_reader_ != nullptr);
|
||||
EXPECT_NE(log_reader_, nullptr);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string contents() {
|
||||
auto file = test::GetStringSinkFromLegacyWriter(log_writer_->file());
|
||||
assert(file != nullptr);
|
||||
return file->contents_;
|
||||
}
|
||||
std::string contents() { return sink_->contents_; }
|
||||
|
||||
void Encode(const std::string& msg) {
|
||||
ASSERT_OK(log_writer_->AddRecord(Slice(msg)));
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
PeriodicWorkScheduler::PeriodicWorkScheduler(Env* env) {
|
||||
PeriodicWorkScheduler::PeriodicWorkScheduler(Env* env) : timer_mu_(env) {
|
||||
timer = std::unique_ptr<Timer>(new Timer(env));
|
||||
}
|
||||
|
||||
void PeriodicWorkScheduler::Register(DBImpl* dbi,
|
||||
unsigned int stats_dump_period_sec,
|
||||
unsigned int stats_persist_period_sec) {
|
||||
MutexLock l(&timer_mu_);
|
||||
static std::atomic<uint64_t> initial_delay(0);
|
||||
timer->Start();
|
||||
if (stats_dump_period_sec > 0) {
|
||||
@@ -41,6 +42,7 @@ void PeriodicWorkScheduler::Register(DBImpl* dbi,
|
||||
}
|
||||
|
||||
void PeriodicWorkScheduler::Unregister(DBImpl* dbi) {
|
||||
MutexLock l(&timer_mu_);
|
||||
timer->Cancel(GetTaskName(dbi, "dump_st"));
|
||||
timer->Cancel(GetTaskName(dbi, "pst_st"));
|
||||
timer->Cancel(GetTaskName(dbi, "flush_info_log"));
|
||||
@@ -78,7 +80,10 @@ PeriodicWorkTestScheduler* PeriodicWorkTestScheduler::Default(Env* env) {
|
||||
MutexLock l(&mutex);
|
||||
if (scheduler.timer.get() != nullptr &&
|
||||
scheduler.timer->TEST_GetPendingTaskNum() == 0) {
|
||||
scheduler.timer->Shutdown();
|
||||
{
|
||||
MutexLock timer_mu_guard(&scheduler.timer_mu_);
|
||||
scheduler.timer->Shutdown();
|
||||
}
|
||||
scheduler.timer.reset(new Timer(env));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,12 @@ class PeriodicWorkScheduler {
|
||||
|
||||
protected:
|
||||
std::unique_ptr<Timer> timer;
|
||||
// `timer_mu_` serves two purposes currently:
|
||||
// (1) to ensure calls to `Start()` and `Shutdown()` are serialized, as
|
||||
// they are currently not implemented in a thread-safe way; and
|
||||
// (2) to ensure the `Timer::Add()`s and `Timer::Start()` run atomically, and
|
||||
// the `Timer::Cancel()`s and `Timer::Shutdown()` run atomically.
|
||||
port::Mutex timer_mu_;
|
||||
|
||||
explicit PeriodicWorkScheduler(Env* env);
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ TEST_F(PlainTableKeyDecoderTest, ReadNonMmap) {
|
||||
Slice contents(tmp);
|
||||
test::StringSource* string_source =
|
||||
new test::StringSource(contents, 0, false);
|
||||
|
||||
std::unique_ptr<FSRandomAccessFile> holder(string_source);
|
||||
std::unique_ptr<RandomAccessFileReader> file_reader(
|
||||
test::GetRandomAccessFileReader(string_source));
|
||||
new RandomAccessFileReader(std::move(holder), "test"));
|
||||
std::unique_ptr<PlainTableReaderFileInfo> file_info(
|
||||
new PlainTableReaderFileInfo(std::move(file_reader), EnvOptions(),
|
||||
kLength));
|
||||
|
||||
@@ -439,7 +439,6 @@ class Repairer {
|
||||
range_del_iters.emplace_back(range_del_iter);
|
||||
}
|
||||
|
||||
LegacyFileSystemWrapper fs(env_);
|
||||
IOStatus io_s;
|
||||
status = BuildTable(
|
||||
dbname_, /* versions */ nullptr, immutable_db_options_,
|
||||
|
||||
+4
-4
@@ -80,8 +80,8 @@ TEST_F(RepairTest, CorruptManifest) {
|
||||
Close();
|
||||
ASSERT_OK(env_->FileExists(manifest_path));
|
||||
|
||||
LegacyFileSystemWrapper fs(env_);
|
||||
ASSERT_OK(CreateFile(&fs, manifest_path, "blah", false /* use_fsync */));
|
||||
ASSERT_OK(CreateFile(env_->GetFileSystem(), manifest_path, "blah",
|
||||
false /* use_fsync */));
|
||||
ASSERT_OK(RepairDB(dbname_, CurrentOptions()));
|
||||
Reopen(CurrentOptions());
|
||||
|
||||
@@ -163,8 +163,8 @@ TEST_F(RepairTest, CorruptSst) {
|
||||
ASSERT_OK(GetFirstSstPath(&sst_path));
|
||||
ASSERT_FALSE(sst_path.empty());
|
||||
|
||||
LegacyFileSystemWrapper fs(env_);
|
||||
ASSERT_OK(CreateFile(&fs, sst_path, "blah", false /* use_fsync */));
|
||||
ASSERT_OK(CreateFile(env_->GetFileSystem(), sst_path, "blah",
|
||||
false /* use_fsync */));
|
||||
|
||||
Close();
|
||||
ASSERT_OK(RepairDB(dbname_, CurrentOptions()));
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include "db/db_impl/db_impl.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/sequence_file_reader.h"
|
||||
#include "file/writable_file_writer.h"
|
||||
#include "options/cf_options.h"
|
||||
@@ -49,10 +48,9 @@ void MakeBuilder(const Options& options, const ImmutableCFOptions& ioptions,
|
||||
int_tbl_prop_collector_factories,
|
||||
std::unique_ptr<WritableFileWriter>* writable,
|
||||
std::unique_ptr<TableBuilder>* builder) {
|
||||
std::unique_ptr<WritableFile> wf(new test::StringSink);
|
||||
std::unique_ptr<FSWritableFile> wf(new test::StringSink);
|
||||
writable->reset(
|
||||
new WritableFileWriter(NewLegacyWritableFileWrapper(std::move(wf)),
|
||||
"" /* don't care */, EnvOptions()));
|
||||
new WritableFileWriter(std::move(wf), "" /* don't care */, EnvOptions()));
|
||||
int unknown_level = -1;
|
||||
builder->reset(NewTableBuilder(
|
||||
ioptions, moptions, internal_comparator, int_tbl_prop_collector_factories,
|
||||
@@ -286,12 +284,13 @@ void TestCustomizedTablePropertiesCollector(
|
||||
writer->Flush();
|
||||
|
||||
// -- Step 2: Read properties
|
||||
LegacyWritableFileWrapper* file =
|
||||
static_cast<LegacyWritableFileWrapper*>(writer->writable_file());
|
||||
test::StringSink* fwf = static_cast<test::StringSink*>(file->target());
|
||||
test::StringSink* fwf =
|
||||
static_cast<test::StringSink*>(writer->writable_file());
|
||||
std::unique_ptr<FSRandomAccessFile> source(
|
||||
new test::StringSource(fwf->contents()));
|
||||
std::unique_ptr<RandomAccessFileReader> fake_file_reader(
|
||||
test::GetRandomAccessFileReader(
|
||||
new test::StringSource(fwf->contents())));
|
||||
new RandomAccessFileReader(std::move(source), "test"));
|
||||
|
||||
TableProperties* props;
|
||||
Status s = ReadTableProperties(fake_file_reader.get(), fwf->contents().size(),
|
||||
magic_number, ioptions, &props,
|
||||
@@ -427,12 +426,13 @@ void TestInternalKeyPropertiesCollector(
|
||||
ASSERT_OK(builder->Finish());
|
||||
writable->Flush();
|
||||
|
||||
LegacyWritableFileWrapper* file =
|
||||
static_cast<LegacyWritableFileWrapper*>(writable->writable_file());
|
||||
test::StringSink* fwf = static_cast<test::StringSink*>(file->target());
|
||||
test::StringSink* fwf =
|
||||
static_cast<test::StringSink*>(writable->writable_file());
|
||||
std::unique_ptr<FSRandomAccessFile> source(
|
||||
new test::StringSource(fwf->contents()));
|
||||
std::unique_ptr<RandomAccessFileReader> reader(
|
||||
test::GetRandomAccessFileReader(
|
||||
new test::StringSource(fwf->contents())));
|
||||
new RandomAccessFileReader(std::move(source), "test"));
|
||||
|
||||
TableProperties* props;
|
||||
Status s =
|
||||
ReadTableProperties(reader.get(), fwf->contents().size(), magic_number,
|
||||
|
||||
+56
-6
@@ -226,13 +226,17 @@ bool VersionEdit::EncodeTo(std::string* dst) const {
|
||||
}
|
||||
|
||||
for (const auto& wal_addition : wal_additions_) {
|
||||
PutVarint32(dst, kWalAddition);
|
||||
wal_addition.EncodeTo(dst);
|
||||
PutVarint32(dst, kWalAddition2);
|
||||
std::string encoded;
|
||||
wal_addition.EncodeTo(&encoded);
|
||||
PutLengthPrefixedSlice(dst, encoded);
|
||||
}
|
||||
|
||||
if (!wal_deletion_.IsEmpty()) {
|
||||
PutVarint32(dst, kWalDeletion);
|
||||
wal_deletion_.EncodeTo(dst);
|
||||
PutVarint32(dst, kWalDeletion2);
|
||||
std::string encoded;
|
||||
wal_deletion_.EncodeTo(&encoded);
|
||||
PutLengthPrefixedSlice(dst, encoded);
|
||||
}
|
||||
|
||||
// 0 is default and does not need to be explicitly written
|
||||
@@ -375,6 +379,11 @@ const char* VersionEdit::DecodeNewFile4From(Slice* input) {
|
||||
|
||||
Status VersionEdit::DecodeFrom(const Slice& src) {
|
||||
Clear();
|
||||
#ifndef NDEBUG
|
||||
bool ignore_ignorable_tags = false;
|
||||
TEST_SYNC_POINT_CALLBACK("VersionEdit::EncodeTo:IgnoreIgnorableTags",
|
||||
&ignore_ignorable_tags);
|
||||
#endif
|
||||
Slice input = src;
|
||||
const char* msg = nullptr;
|
||||
uint32_t tag = 0;
|
||||
@@ -385,6 +394,11 @@ Status VersionEdit::DecodeFrom(const Slice& src) {
|
||||
Slice str;
|
||||
InternalKey key;
|
||||
while (msg == nullptr && GetVarint32(&input, &tag)) {
|
||||
#ifndef NDEBUG
|
||||
if (ignore_ignorable_tags && tag > kTagSafeIgnoreMask) {
|
||||
tag = kTagSafeIgnoreMask;
|
||||
}
|
||||
#endif
|
||||
switch (tag) {
|
||||
case kDbId:
|
||||
if (GetLengthPrefixedSlice(&input, &str)) {
|
||||
@@ -542,7 +556,8 @@ Status VersionEdit::DecodeFrom(const Slice& src) {
|
||||
break;
|
||||
}
|
||||
|
||||
case kBlobFileAddition: {
|
||||
case kBlobFileAddition:
|
||||
case kBlobFileAddition_DEPRECATED: {
|
||||
BlobFileAddition blob_file_addition;
|
||||
const Status s = blob_file_addition.DecodeFrom(&input);
|
||||
if (!s.ok()) {
|
||||
@@ -553,7 +568,8 @@ Status VersionEdit::DecodeFrom(const Slice& src) {
|
||||
break;
|
||||
}
|
||||
|
||||
case kBlobFileGarbage: {
|
||||
case kBlobFileGarbage:
|
||||
case kBlobFileGarbage_DEPRECATED: {
|
||||
BlobFileGarbage blob_file_garbage;
|
||||
const Status s = blob_file_garbage.DecodeFrom(&input);
|
||||
if (!s.ok()) {
|
||||
@@ -575,6 +591,23 @@ Status VersionEdit::DecodeFrom(const Slice& src) {
|
||||
break;
|
||||
}
|
||||
|
||||
case kWalAddition2: {
|
||||
Slice encoded;
|
||||
if (!GetLengthPrefixedSlice(&input, &encoded)) {
|
||||
msg = "WalAddition not prefixed by length";
|
||||
break;
|
||||
}
|
||||
|
||||
WalAddition wal_addition;
|
||||
const Status s = wal_addition.DecodeFrom(&encoded);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
wal_additions_.emplace_back(std::move(wal_addition));
|
||||
break;
|
||||
}
|
||||
|
||||
case kWalDeletion: {
|
||||
WalDeletion wal_deletion;
|
||||
const Status s = wal_deletion.DecodeFrom(&input);
|
||||
@@ -586,6 +619,23 @@ Status VersionEdit::DecodeFrom(const Slice& src) {
|
||||
break;
|
||||
}
|
||||
|
||||
case kWalDeletion2: {
|
||||
Slice encoded;
|
||||
if (!GetLengthPrefixedSlice(&input, &encoded)) {
|
||||
msg = "WalDeletion not prefixed by length";
|
||||
break;
|
||||
}
|
||||
|
||||
WalDeletion wal_deletion;
|
||||
const Status s = wal_deletion.DecodeFrom(&encoded);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
wal_deletion_ = std::move(wal_deletion);
|
||||
break;
|
||||
}
|
||||
|
||||
case kColumnFamily:
|
||||
if (!GetVarint32(&input, &column_family_)) {
|
||||
if (!msg) {
|
||||
|
||||
+7
-2
@@ -52,16 +52,21 @@ enum Tag : uint32_t {
|
||||
|
||||
kInAtomicGroup = 300,
|
||||
|
||||
kBlobFileAddition = 400,
|
||||
kBlobFileGarbage,
|
||||
|
||||
// Mask for an unidentified tag from the future which can be safely ignored.
|
||||
kTagSafeIgnoreMask = 1 << 13,
|
||||
|
||||
// Forward compatible (aka ignorable) records
|
||||
kDbId,
|
||||
kBlobFileAddition,
|
||||
kBlobFileGarbage,
|
||||
kBlobFileAddition_DEPRECATED,
|
||||
kBlobFileGarbage_DEPRECATED,
|
||||
kWalAddition,
|
||||
kWalDeletion,
|
||||
kFullHistoryTsLow,
|
||||
kWalAddition2,
|
||||
kWalDeletion2,
|
||||
};
|
||||
|
||||
enum NewFileCustomTag : uint32_t {
|
||||
|
||||
@@ -98,12 +98,18 @@ Status ListColumnFamiliesHandler::ApplyVersionEdit(
|
||||
Status FileChecksumRetriever::ApplyVersionEdit(VersionEdit& edit,
|
||||
ColumnFamilyData** /*unused*/) {
|
||||
for (const auto& deleted_file : edit.GetDeletedFiles()) {
|
||||
file_checksum_list_.RemoveOneFileChecksum(deleted_file.second);
|
||||
Status s = file_checksum_list_.RemoveOneFileChecksum(deleted_file.second);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
for (const auto& new_file : edit.GetNewFiles()) {
|
||||
file_checksum_list_.InsertOneFileChecksum(
|
||||
Status s = file_checksum_list_.InsertOneFileChecksum(
|
||||
new_file.second.fd.GetNumber(), new_file.second.file_checksum,
|
||||
new_file.second.file_checksum_func_name);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
+88
-14
@@ -324,14 +324,22 @@ TEST_F(VersionEditTest, AddWalEncodeDecode) {
|
||||
TestEncodeDecode(edit);
|
||||
}
|
||||
|
||||
static std::string PrefixEncodedWalAdditionWithLength(
|
||||
const std::string& encoded) {
|
||||
std::string ret;
|
||||
PutVarint32(&ret, Tag::kWalAddition2);
|
||||
PutLengthPrefixedSlice(&ret, encoded);
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST_F(VersionEditTest, AddWalDecodeBadLogNumber) {
|
||||
std::string encoded;
|
||||
PutVarint32(&encoded, Tag::kWalAddition);
|
||||
|
||||
{
|
||||
// No log number.
|
||||
std::string encoded_edit = PrefixEncodedWalAdditionWithLength(encoded);
|
||||
VersionEdit edit;
|
||||
Status s = edit.DecodeFrom(encoded);
|
||||
Status s = edit.DecodeFrom(encoded_edit);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(s.ToString().find("Error decoding WAL log number") !=
|
||||
std::string::npos)
|
||||
@@ -345,8 +353,10 @@ TEST_F(VersionEditTest, AddWalDecodeBadLogNumber) {
|
||||
unsigned char* ptr = reinterpret_cast<unsigned char*>(&c);
|
||||
*ptr = 128;
|
||||
encoded.append(1, c);
|
||||
|
||||
std::string encoded_edit = PrefixEncodedWalAdditionWithLength(encoded);
|
||||
VersionEdit edit;
|
||||
Status s = edit.DecodeFrom(encoded);
|
||||
Status s = edit.DecodeFrom(encoded_edit);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(s.ToString().find("Error decoding WAL log number") !=
|
||||
std::string::npos)
|
||||
@@ -358,14 +368,14 @@ TEST_F(VersionEditTest, AddWalDecodeBadTag) {
|
||||
constexpr WalNumber kLogNumber = 100;
|
||||
constexpr uint64_t kSizeInBytes = 100;
|
||||
|
||||
std::string encoded_without_tag;
|
||||
PutVarint32(&encoded_without_tag, Tag::kWalAddition);
|
||||
PutVarint64(&encoded_without_tag, kLogNumber);
|
||||
std::string encoded;
|
||||
PutVarint64(&encoded, kLogNumber);
|
||||
|
||||
{
|
||||
// No tag.
|
||||
std::string encoded_edit = PrefixEncodedWalAdditionWithLength(encoded);
|
||||
VersionEdit edit;
|
||||
Status s = edit.DecodeFrom(encoded_without_tag);
|
||||
Status s = edit.DecodeFrom(encoded_edit);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(s.ToString().find("Error decoding tag") != std::string::npos)
|
||||
<< s.ToString();
|
||||
@@ -373,12 +383,15 @@ TEST_F(VersionEditTest, AddWalDecodeBadTag) {
|
||||
|
||||
{
|
||||
// Only has size tag, no terminate tag.
|
||||
std::string encoded_with_size = encoded_without_tag;
|
||||
std::string encoded_with_size = encoded;
|
||||
PutVarint32(&encoded_with_size,
|
||||
static_cast<uint32_t>(WalAdditionTag::kSyncedSize));
|
||||
PutVarint64(&encoded_with_size, kSizeInBytes);
|
||||
|
||||
std::string encoded_edit =
|
||||
PrefixEncodedWalAdditionWithLength(encoded_with_size);
|
||||
VersionEdit edit;
|
||||
Status s = edit.DecodeFrom(encoded_with_size);
|
||||
Status s = edit.DecodeFrom(encoded_edit);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(s.ToString().find("Error decoding tag") != std::string::npos)
|
||||
<< s.ToString();
|
||||
@@ -386,11 +399,14 @@ TEST_F(VersionEditTest, AddWalDecodeBadTag) {
|
||||
|
||||
{
|
||||
// Only has terminate tag.
|
||||
std::string encoded_with_terminate = encoded_without_tag;
|
||||
std::string encoded_with_terminate = encoded;
|
||||
PutVarint32(&encoded_with_terminate,
|
||||
static_cast<uint32_t>(WalAdditionTag::kTerminate));
|
||||
|
||||
std::string encoded_edit =
|
||||
PrefixEncodedWalAdditionWithLength(encoded_with_terminate);
|
||||
VersionEdit edit;
|
||||
ASSERT_OK(edit.DecodeFrom(encoded_with_terminate));
|
||||
ASSERT_OK(edit.DecodeFrom(encoded_edit));
|
||||
auto& wal_addition = edit.GetWalAdditions()[0];
|
||||
ASSERT_EQ(wal_addition.GetLogNumber(), kLogNumber);
|
||||
ASSERT_FALSE(wal_addition.GetMetadata().HasSyncedSize());
|
||||
@@ -401,15 +417,15 @@ TEST_F(VersionEditTest, AddWalDecodeNoSize) {
|
||||
constexpr WalNumber kLogNumber = 100;
|
||||
|
||||
std::string encoded;
|
||||
PutVarint32(&encoded, Tag::kWalAddition);
|
||||
PutVarint64(&encoded, kLogNumber);
|
||||
PutVarint32(&encoded, static_cast<uint32_t>(WalAdditionTag::kSyncedSize));
|
||||
// No real size after the size tag.
|
||||
|
||||
{
|
||||
// Without terminate tag.
|
||||
std::string encoded_edit = PrefixEncodedWalAdditionWithLength(encoded);
|
||||
VersionEdit edit;
|
||||
Status s = edit.DecodeFrom(encoded);
|
||||
Status s = edit.DecodeFrom(encoded_edit);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
ASSERT_TRUE(s.ToString().find("Error decoding WAL file size") !=
|
||||
std::string::npos)
|
||||
@@ -419,8 +435,10 @@ TEST_F(VersionEditTest, AddWalDecodeNoSize) {
|
||||
{
|
||||
// With terminate tag.
|
||||
PutVarint32(&encoded, static_cast<uint32_t>(WalAdditionTag::kTerminate));
|
||||
|
||||
std::string encoded_edit = PrefixEncodedWalAdditionWithLength(encoded);
|
||||
VersionEdit edit;
|
||||
Status s = edit.DecodeFrom(encoded);
|
||||
Status s = edit.DecodeFrom(encoded_edit);
|
||||
ASSERT_TRUE(s.IsCorruption());
|
||||
// The terminate tag is misunderstood as the size.
|
||||
ASSERT_TRUE(s.ToString().find("Error decoding tag") != std::string::npos)
|
||||
@@ -515,6 +533,62 @@ TEST_F(VersionEditTest, FullHistoryTsLow) {
|
||||
TestEncodeDecode(edit);
|
||||
}
|
||||
|
||||
// Tests that if RocksDB is downgraded, the new types of VersionEdits
|
||||
// that have a tag larger than kTagSafeIgnoreMask can be safely ignored.
|
||||
TEST_F(VersionEditTest, IgnorableTags) {
|
||||
SyncPoint::GetInstance()->SetCallBack(
|
||||
"VersionEdit::EncodeTo:IgnoreIgnorableTags", [&](void* arg) {
|
||||
bool* ignore = static_cast<bool*>(arg);
|
||||
*ignore = true;
|
||||
});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
constexpr uint64_t kPrevLogNumber = 100;
|
||||
constexpr uint64_t kLogNumber = 200;
|
||||
constexpr uint64_t kNextFileNumber = 300;
|
||||
constexpr uint64_t kColumnFamilyId = 400;
|
||||
|
||||
VersionEdit edit;
|
||||
// Add some ignorable entries.
|
||||
for (int i = 0; i < 2; i++) {
|
||||
edit.AddWal(i + 1, WalMetadata(i + 2));
|
||||
}
|
||||
edit.SetDBId("db_id");
|
||||
// Add unignorable entries.
|
||||
edit.SetPrevLogNumber(kPrevLogNumber);
|
||||
edit.SetLogNumber(kLogNumber);
|
||||
// Add more ignorable entries.
|
||||
edit.DeleteWalsBefore(100);
|
||||
// Add unignorable entry.
|
||||
edit.SetNextFile(kNextFileNumber);
|
||||
// Add more ignorable entries.
|
||||
edit.SetFullHistoryTsLow("ts");
|
||||
// Add unignorable entry.
|
||||
edit.SetColumnFamily(kColumnFamilyId);
|
||||
|
||||
std::string encoded;
|
||||
ASSERT_TRUE(edit.EncodeTo(&encoded));
|
||||
|
||||
VersionEdit decoded;
|
||||
ASSERT_OK(decoded.DecodeFrom(encoded));
|
||||
|
||||
// Check that all ignorable entries are ignored.
|
||||
ASSERT_FALSE(decoded.HasDbId());
|
||||
ASSERT_FALSE(decoded.HasFullHistoryTsLow());
|
||||
ASSERT_FALSE(decoded.IsWalAddition());
|
||||
ASSERT_FALSE(decoded.IsWalDeletion());
|
||||
ASSERT_TRUE(decoded.GetWalAdditions().empty());
|
||||
ASSERT_TRUE(decoded.GetWalDeletion().IsEmpty());
|
||||
|
||||
// Check that unignorable entries are still present.
|
||||
ASSERT_EQ(edit.GetPrevLogNumber(), kPrevLogNumber);
|
||||
ASSERT_EQ(edit.GetLogNumber(), kLogNumber);
|
||||
ASSERT_EQ(edit.GetNextFile(), kNextFileNumber);
|
||||
ASSERT_EQ(edit.GetColumnFamily(), kColumnFamilyId);
|
||||
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -47,8 +47,7 @@ class WalManagerTest : public testing::Test {
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
db_options_.wal_dir = dbname_;
|
||||
db_options_.env = env_.get();
|
||||
fs_.reset(new LegacyFileSystemWrapper(env_.get()));
|
||||
db_options_.fs = fs_;
|
||||
db_options_.fs = env_->GetFileSystem();
|
||||
|
||||
versions_.reset(
|
||||
new VersionSet(dbname_, &db_options_, env_options_, table_cache_.get(),
|
||||
@@ -116,7 +115,6 @@ class WalManagerTest : public testing::Test {
|
||||
WriteBufferManager write_buffer_manager_;
|
||||
std::unique_ptr<VersionSet> versions_;
|
||||
std::unique_ptr<WalManager> wal_manager_;
|
||||
std::shared_ptr<LegacyFileSystemWrapper> fs_;
|
||||
|
||||
std::unique_ptr<log::Writer> current_log_writer_;
|
||||
uint64_t current_log_number_;
|
||||
|
||||
@@ -472,7 +472,7 @@ Status StressTest::NewTxn(WriteOptions& write_opts, Transaction** txn) {
|
||||
}
|
||||
static std::atomic<uint64_t> txn_id = {0};
|
||||
TransactionOptions txn_options;
|
||||
txn_options.lock_timeout = 60000; // 1min
|
||||
txn_options.lock_timeout = 600000; // 10 min
|
||||
txn_options.deadlock_detect = true;
|
||||
*txn = txn_db_->BeginTransaction(write_opts, txn_options);
|
||||
auto istr = std::to_string(txn_id.fetch_add(1));
|
||||
|
||||
+3
-1
@@ -1,2 +1,4 @@
|
||||
source 'https://rubygems.org'
|
||||
gem 'github-pages', '~> 207'
|
||||
gem 'github-pages', '~> 209'
|
||||
|
||||
gem "webrick", "~> 1.7"
|
||||
+42
-33
@@ -1,7 +1,7 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (6.0.3.2)
|
||||
activesupport (6.0.3.4)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
@@ -17,37 +17,40 @@ GEM
|
||||
commonmarker (0.17.13)
|
||||
ruby-enum (~> 0.5)
|
||||
concurrent-ruby (1.1.7)
|
||||
dnsruby (1.61.4)
|
||||
dnsruby (1.61.5)
|
||||
simpleidn (~> 0.1)
|
||||
em-websocket (0.5.1)
|
||||
em-websocket (0.5.2)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
ethon (0.12.0)
|
||||
ffi (>= 1.3.0)
|
||||
eventmachine (1.2.7)
|
||||
execjs (2.7.0)
|
||||
faraday (1.0.1)
|
||||
faraday (1.3.0)
|
||||
faraday-net_http (~> 1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.13.1)
|
||||
ruby2_keywords
|
||||
faraday-net_http (1.0.0)
|
||||
ffi (1.14.2)
|
||||
forwardable-extended (2.6.0)
|
||||
gemoji (3.0.1)
|
||||
github-pages (207)
|
||||
github-pages (209)
|
||||
github-pages-health-check (= 1.16.1)
|
||||
jekyll (= 3.9.0)
|
||||
jekyll-avatar (= 0.7.0)
|
||||
jekyll-coffeescript (= 1.1.1)
|
||||
jekyll-commonmark-ghpages (= 0.1.6)
|
||||
jekyll-default-layout (= 0.1.4)
|
||||
jekyll-feed (= 0.13.0)
|
||||
jekyll-feed (= 0.15.1)
|
||||
jekyll-gist (= 1.5.0)
|
||||
jekyll-github-metadata (= 2.13.0)
|
||||
jekyll-mentions (= 1.5.1)
|
||||
jekyll-mentions (= 1.6.0)
|
||||
jekyll-optional-front-matter (= 0.3.2)
|
||||
jekyll-paginate (= 1.1.0)
|
||||
jekyll-readme-index (= 0.3.0)
|
||||
jekyll-redirect-from (= 0.15.0)
|
||||
jekyll-redirect-from (= 0.16.0)
|
||||
jekyll-relative-links (= 0.6.1)
|
||||
jekyll-remote-theme (= 0.4.1)
|
||||
jekyll-remote-theme (= 0.4.2)
|
||||
jekyll-sass-converter (= 1.5.2)
|
||||
jekyll-seo-tag (= 2.6.1)
|
||||
jekyll-sitemap (= 1.4.0)
|
||||
@@ -55,7 +58,7 @@ GEM
|
||||
jekyll-theme-architect (= 0.1.1)
|
||||
jekyll-theme-cayman (= 0.1.1)
|
||||
jekyll-theme-dinky (= 0.1.1)
|
||||
jekyll-theme-hacker (= 0.1.1)
|
||||
jekyll-theme-hacker (= 0.1.2)
|
||||
jekyll-theme-leap-day (= 0.1.1)
|
||||
jekyll-theme-merlot (= 0.1.1)
|
||||
jekyll-theme-midnight (= 0.1.1)
|
||||
@@ -66,14 +69,14 @@ GEM
|
||||
jekyll-theme-tactile (= 0.1.1)
|
||||
jekyll-theme-time-machine (= 0.1.1)
|
||||
jekyll-titles-from-headings (= 0.5.3)
|
||||
jemoji (= 0.11.1)
|
||||
jemoji (= 0.12.0)
|
||||
kramdown (= 2.3.0)
|
||||
kramdown-parser-gfm (= 1.1.0)
|
||||
liquid (= 4.0.3)
|
||||
mercenary (~> 0.3)
|
||||
minima (= 2.5.1)
|
||||
nokogiri (>= 1.10.4, < 2.0)
|
||||
rouge (= 3.19.0)
|
||||
rouge (= 3.23.0)
|
||||
terminal-table (~> 1.4)
|
||||
github-pages-health-check (1.16.1)
|
||||
addressable (~> 2.3)
|
||||
@@ -81,7 +84,7 @@ GEM
|
||||
octokit (~> 4.0)
|
||||
public_suffix (~> 3.0)
|
||||
typhoeus (~> 1.3)
|
||||
html-pipeline (2.13.0)
|
||||
html-pipeline (2.14.0)
|
||||
activesupport (>= 2)
|
||||
nokogiri (>= 1.4)
|
||||
http_parser.rb (0.6.0)
|
||||
@@ -114,14 +117,14 @@ GEM
|
||||
rouge (>= 2.0, < 4.0)
|
||||
jekyll-default-layout (0.1.4)
|
||||
jekyll (~> 3.0)
|
||||
jekyll-feed (0.13.0)
|
||||
jekyll-feed (0.15.1)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-gist (1.5.0)
|
||||
octokit (~> 4.2)
|
||||
jekyll-github-metadata (2.13.0)
|
||||
jekyll (>= 3.4, < 5.0)
|
||||
octokit (~> 4.0, != 4.4.0)
|
||||
jekyll-mentions (1.5.1)
|
||||
jekyll-mentions (1.6.0)
|
||||
html-pipeline (~> 2.3)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-optional-front-matter (0.3.2)
|
||||
@@ -129,14 +132,15 @@ GEM
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-readme-index (0.3.0)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
jekyll-redirect-from (0.15.0)
|
||||
jekyll-redirect-from (0.16.0)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-relative-links (0.6.1)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-remote-theme (0.4.1)
|
||||
jekyll-remote-theme (0.4.2)
|
||||
addressable (~> 2.0)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
rubyzip (>= 1.3.0)
|
||||
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
|
||||
rubyzip (>= 1.3.0, < 3.0)
|
||||
jekyll-sass-converter (1.5.2)
|
||||
sass (~> 3.4)
|
||||
jekyll-seo-tag (2.6.1)
|
||||
@@ -153,8 +157,8 @@ GEM
|
||||
jekyll-theme-dinky (0.1.1)
|
||||
jekyll (~> 3.5)
|
||||
jekyll-seo-tag (~> 2.0)
|
||||
jekyll-theme-hacker (0.1.1)
|
||||
jekyll (~> 3.5)
|
||||
jekyll-theme-hacker (0.1.2)
|
||||
jekyll (> 3.5, < 5.0)
|
||||
jekyll-seo-tag (~> 2.0)
|
||||
jekyll-theme-leap-day (0.1.1)
|
||||
jekyll (~> 3.5)
|
||||
@@ -188,7 +192,7 @@ GEM
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
jemoji (0.11.1)
|
||||
jemoji (0.12.0)
|
||||
gemoji (~> 3.0)
|
||||
html-pipeline (~> 2.2)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
@@ -197,32 +201,35 @@ GEM
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
liquid (4.0.3)
|
||||
listen (3.2.1)
|
||||
listen (3.4.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.4.0)
|
||||
mini_portile2 (2.5.0)
|
||||
minima (2.5.1)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-feed (~> 0.9)
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.14.1)
|
||||
minitest (5.14.3)
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
octokit (4.18.0)
|
||||
nokogiri (1.11.1)
|
||||
mini_portile2 (~> 2.5.0)
|
||||
racc (~> 1.4)
|
||||
octokit (4.20.0)
|
||||
faraday (>= 0.9)
|
||||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (3.1.1)
|
||||
racc (1.5.2)
|
||||
rb-fsevent (0.10.4)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.2.4)
|
||||
rouge (3.19.0)
|
||||
rouge (3.23.0)
|
||||
ruby-enum (0.8.0)
|
||||
i18n
|
||||
ruby2_keywords (0.0.2)
|
||||
rubyzip (2.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sass (3.7.4)
|
||||
@@ -240,19 +247,21 @@ GEM
|
||||
thread_safe (0.3.6)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.7)
|
||||
tzinfo (1.2.9)
|
||||
thread_safe (~> 0.1)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
zeitwerk (2.4.0)
|
||||
webrick (1.7.0)
|
||||
zeitwerk (2.4.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
github-pages (~> 207)
|
||||
github-pages (~> 209)
|
||||
webrick (~> 1.7)
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
2.2.3
|
||||
Vendored
+70
-294
@@ -8,6 +8,13 @@
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/file_system.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows API macro interference
|
||||
#undef DeleteFile
|
||||
#undef GetCurrentTime
|
||||
#undef LoadLibrary
|
||||
#endif
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// The CompositeEnvWrapper class provides an interface that is compatible
|
||||
@@ -271,16 +278,11 @@ class CompositeDirectoryWrapper : public Directory {
|
||||
std::unique_ptr<FSDirectory> target_;
|
||||
};
|
||||
|
||||
class CompositeEnvWrapper : public Env {
|
||||
class CompositeEnv : public Env {
|
||||
public:
|
||||
// Initialize a CompositeEnvWrapper that delegates all thread/time related
|
||||
// calls to env, and all file operations to fs
|
||||
explicit CompositeEnvWrapper(Env* env, std::shared_ptr<FileSystem> fs)
|
||||
: Env(fs), env_target_(env) {}
|
||||
~CompositeEnvWrapper() {}
|
||||
|
||||
// Return the target to which this Env forwards all calls
|
||||
Env* env_target() const { return env_target_; }
|
||||
explicit CompositeEnv(const std::shared_ptr<FileSystem>& fs) : Env(fs) {}
|
||||
|
||||
Status RegisterDbPaths(const std::vector<std::string>& paths) override {
|
||||
return file_system_->RegisterDbPaths(paths);
|
||||
@@ -498,6 +500,66 @@ class CompositeEnvWrapper : public Env {
|
||||
return file_system_->IsDirectory(path, io_opts, is_dir, &dbg);
|
||||
}
|
||||
|
||||
Status GetTestDirectory(std::string* path) override {
|
||||
IOOptions io_opts;
|
||||
IODebugContext dbg;
|
||||
return file_system_->GetTestDirectory(io_opts, path, &dbg);
|
||||
}
|
||||
|
||||
EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const override {
|
||||
return file_system_->OptimizeForLogRead(FileOptions(env_options));
|
||||
}
|
||||
|
||||
EnvOptions OptimizeForManifestRead(
|
||||
const EnvOptions& env_options) const override {
|
||||
return file_system_->OptimizeForManifestRead(FileOptions(env_options));
|
||||
}
|
||||
|
||||
EnvOptions OptimizeForLogWrite(const EnvOptions& env_options,
|
||||
const DBOptions& db_options) const override {
|
||||
return file_system_->OptimizeForLogWrite(FileOptions(env_options),
|
||||
db_options);
|
||||
}
|
||||
|
||||
EnvOptions OptimizeForManifestWrite(
|
||||
const EnvOptions& env_options) const override {
|
||||
return file_system_->OptimizeForManifestWrite(FileOptions(env_options));
|
||||
}
|
||||
|
||||
EnvOptions OptimizeForCompactionTableWrite(
|
||||
const EnvOptions& env_options,
|
||||
const ImmutableDBOptions& immutable_ops) const override {
|
||||
return file_system_->OptimizeForCompactionTableWrite(
|
||||
FileOptions(env_options), immutable_ops);
|
||||
}
|
||||
EnvOptions OptimizeForCompactionTableRead(
|
||||
const EnvOptions& env_options,
|
||||
const ImmutableDBOptions& db_options) const override {
|
||||
return file_system_->OptimizeForCompactionTableRead(
|
||||
FileOptions(env_options), db_options);
|
||||
}
|
||||
|
||||
// This seems to clash with a macro on Windows, so #undef it here
|
||||
#ifdef GetFreeSpace
|
||||
#undef GetFreeSpace
|
||||
#endif
|
||||
Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override {
|
||||
IOOptions io_opts;
|
||||
IODebugContext dbg;
|
||||
return file_system_->GetFreeSpace(path, io_opts, diskfree, &dbg);
|
||||
}
|
||||
};
|
||||
|
||||
class CompositeEnvWrapper : public CompositeEnv {
|
||||
public:
|
||||
// Initialize a CompositeEnvWrapper that delegates all thread/time related
|
||||
// calls to env, and all file operations to fs
|
||||
explicit CompositeEnvWrapper(Env* env, const std::shared_ptr<FileSystem>& fs)
|
||||
: CompositeEnv(fs), env_target_(env) {}
|
||||
|
||||
// Return the target to which this Env forwards all calls
|
||||
Env* env_target() const { return env_target_; }
|
||||
|
||||
#if !defined(OS_WIN) && !defined(ROCKSDB_NO_DYNAMIC_EXTENSION)
|
||||
Status LoadLibrary(const std::string& lib_name,
|
||||
const std::string& search_path,
|
||||
@@ -522,11 +584,7 @@ class CompositeEnvWrapper : public Env {
|
||||
unsigned int GetThreadPoolQueueLen(Priority pri = LOW) const override {
|
||||
return env_target_->GetThreadPoolQueueLen(pri);
|
||||
}
|
||||
Status GetTestDirectory(std::string* path) override {
|
||||
IOOptions io_opts;
|
||||
IODebugContext dbg;
|
||||
return file_system_->GetTestDirectory(io_opts, path, &dbg);
|
||||
}
|
||||
|
||||
uint64_t NowMicros() override { return env_target_->NowMicros(); }
|
||||
uint64_t NowNanos() override { return env_target_->NowNanos(); }
|
||||
uint64_t NowCPUNanos() override { return env_target_->NowCPUNanos(); }
|
||||
@@ -585,45 +643,6 @@ class CompositeEnvWrapper : public Env {
|
||||
return env_target_->GenerateUniqueId();
|
||||
}
|
||||
|
||||
EnvOptions OptimizeForLogRead(const EnvOptions& env_options) const override {
|
||||
return file_system_->OptimizeForLogRead(FileOptions(env_options));
|
||||
}
|
||||
EnvOptions OptimizeForManifestRead(
|
||||
const EnvOptions& env_options) const override {
|
||||
return file_system_->OptimizeForManifestRead(FileOptions(env_options));
|
||||
}
|
||||
EnvOptions OptimizeForLogWrite(const EnvOptions& env_options,
|
||||
const DBOptions& db_options) const override {
|
||||
return file_system_->OptimizeForLogWrite(FileOptions(env_options),
|
||||
db_options);
|
||||
}
|
||||
EnvOptions OptimizeForManifestWrite(
|
||||
const EnvOptions& env_options) const override {
|
||||
return file_system_->OptimizeForManifestWrite(FileOptions(env_options));
|
||||
}
|
||||
EnvOptions OptimizeForCompactionTableWrite(
|
||||
const EnvOptions& env_options,
|
||||
const ImmutableDBOptions& immutable_ops) const override {
|
||||
return file_system_->OptimizeForCompactionTableWrite(
|
||||
FileOptions(env_options), immutable_ops);
|
||||
}
|
||||
EnvOptions OptimizeForCompactionTableRead(
|
||||
const EnvOptions& env_options,
|
||||
const ImmutableDBOptions& db_options) const override {
|
||||
return file_system_->OptimizeForCompactionTableRead(
|
||||
FileOptions(env_options), db_options);
|
||||
}
|
||||
|
||||
// This seems to clash with a macro on Windows, so #undef it here
|
||||
#ifdef GetFreeSpace
|
||||
#undef GetFreeSpace
|
||||
#endif
|
||||
Status GetFreeSpace(const std::string& path, uint64_t* diskfree) override {
|
||||
IOOptions io_opts;
|
||||
IODebugContext dbg;
|
||||
return file_system_->GetFreeSpace(path, io_opts, diskfree, &dbg);
|
||||
}
|
||||
|
||||
private:
|
||||
Env* env_target_;
|
||||
};
|
||||
@@ -880,249 +899,6 @@ class LegacyDirectoryWrapper : public FSDirectory {
|
||||
std::unique_ptr<Directory> target_;
|
||||
};
|
||||
|
||||
class LegacyFileSystemWrapper : public FileSystem {
|
||||
public:
|
||||
// Initialize an EnvWrapper that delegates all calls to *t
|
||||
explicit LegacyFileSystemWrapper(Env* t) : target_(t) {}
|
||||
~LegacyFileSystemWrapper() override {}
|
||||
|
||||
const char* Name() const override { return "Legacy File System"; }
|
||||
|
||||
// Return the target to which this Env forwards all calls
|
||||
Env* target() const { return target_; }
|
||||
|
||||
// The following text is boilerplate that forwards all methods to target()
|
||||
IOStatus NewSequentialFile(const std::string& f,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSSequentialFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<SequentialFile> file;
|
||||
Status s = target_->NewSequentialFile(f, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacySequentialFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewRandomAccessFile(const std::string& f,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<RandomAccessFile> file;
|
||||
Status s = target_->NewRandomAccessFile(f, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacyRandomAccessFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<WritableFile> file;
|
||||
Status s = target_->NewWritableFile(f, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacyWritableFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus ReopenWritableFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<WritableFile> file;
|
||||
Status s = target_->ReopenWritableFile(fname, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
result->reset(new LegacyWritableFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus ReuseWritableFile(const std::string& fname,
|
||||
const std::string& old_fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<WritableFile> file;
|
||||
Status s = target_->ReuseWritableFile(fname, old_fname, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacyWritableFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewRandomRWFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomRWFile>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<RandomRWFile> file;
|
||||
Status s = target_->NewRandomRWFile(fname, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
result->reset(new LegacyRandomRWFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewMemoryMappedFileBuffer(
|
||||
const std::string& fname,
|
||||
std::unique_ptr<MemoryMappedFileBuffer>* result) override {
|
||||
return status_to_io_status(
|
||||
target_->NewMemoryMappedFileBuffer(fname, result));
|
||||
}
|
||||
IOStatus NewDirectory(const std::string& name, const IOOptions& /*io_opts*/,
|
||||
std::unique_ptr<FSDirectory>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<Directory> dir;
|
||||
Status s = target_->NewDirectory(name, &dir);
|
||||
if (s.ok()) {
|
||||
result->reset(new LegacyDirectoryWrapper(std::move(dir)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus FileExists(const std::string& f, const IOOptions& /*io_opts*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->FileExists(f));
|
||||
}
|
||||
IOStatus GetChildren(const std::string& dir, const IOOptions& /*io_opts*/,
|
||||
std::vector<std::string>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetChildren(dir, r));
|
||||
}
|
||||
IOStatus GetChildrenFileAttributes(const std::string& dir,
|
||||
const IOOptions& /*options*/,
|
||||
std::vector<FileAttributes>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetChildrenFileAttributes(dir, result));
|
||||
}
|
||||
IOStatus DeleteFile(const std::string& f, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->DeleteFile(f));
|
||||
}
|
||||
IOStatus Truncate(const std::string& fname, size_t size,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->Truncate(fname, size));
|
||||
}
|
||||
IOStatus CreateDir(const std::string& d, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->CreateDir(d));
|
||||
}
|
||||
IOStatus CreateDirIfMissing(const std::string& d,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->CreateDirIfMissing(d));
|
||||
}
|
||||
IOStatus DeleteDir(const std::string& d, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->DeleteDir(d));
|
||||
}
|
||||
IOStatus GetFileSize(const std::string& f, const IOOptions& /*options*/,
|
||||
uint64_t* s, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetFileSize(f, s));
|
||||
}
|
||||
|
||||
IOStatus GetFileModificationTime(const std::string& fname,
|
||||
const IOOptions& /*options*/,
|
||||
uint64_t* file_mtime,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(
|
||||
target_->GetFileModificationTime(fname, file_mtime));
|
||||
}
|
||||
|
||||
IOStatus GetAbsolutePath(const std::string& db_path,
|
||||
const IOOptions& /*options*/,
|
||||
std::string* output_path,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetAbsolutePath(db_path, output_path));
|
||||
}
|
||||
|
||||
IOStatus RenameFile(const std::string& s, const std::string& t,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->RenameFile(s, t));
|
||||
}
|
||||
|
||||
IOStatus LinkFile(const std::string& s, const std::string& t,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->LinkFile(s, t));
|
||||
}
|
||||
|
||||
IOStatus NumFileLinks(const std::string& fname, const IOOptions& /*options*/,
|
||||
uint64_t* count, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->NumFileLinks(fname, count));
|
||||
}
|
||||
|
||||
IOStatus AreFilesSame(const std::string& first, const std::string& second,
|
||||
const IOOptions& /*options*/, bool* res,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->AreFilesSame(first, second, res));
|
||||
}
|
||||
|
||||
IOStatus LockFile(const std::string& f, const IOOptions& /*options*/,
|
||||
FileLock** l, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->LockFile(f, l));
|
||||
}
|
||||
|
||||
IOStatus UnlockFile(FileLock* l, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->UnlockFile(l));
|
||||
}
|
||||
|
||||
IOStatus GetTestDirectory(const IOOptions& /*options*/, std::string* path,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetTestDirectory(path));
|
||||
}
|
||||
IOStatus NewLogger(const std::string& fname, const IOOptions& /*options*/,
|
||||
std::shared_ptr<Logger>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->NewLogger(fname, result));
|
||||
}
|
||||
|
||||
void SanitizeFileOptions(FileOptions* opts) const override {
|
||||
target_->SanitizeEnvOptions(opts);
|
||||
}
|
||||
|
||||
FileOptions OptimizeForLogRead(
|
||||
const FileOptions& file_options) const override {
|
||||
return target_->OptimizeForLogRead(file_options);
|
||||
}
|
||||
FileOptions OptimizeForManifestRead(
|
||||
const FileOptions& file_options) const override {
|
||||
return target_->OptimizeForManifestRead(file_options);
|
||||
}
|
||||
FileOptions OptimizeForLogWrite(const FileOptions& file_options,
|
||||
const DBOptions& db_options) const override {
|
||||
return target_->OptimizeForLogWrite(file_options, db_options);
|
||||
}
|
||||
FileOptions OptimizeForManifestWrite(
|
||||
const FileOptions& file_options) const override {
|
||||
return target_->OptimizeForManifestWrite(file_options);
|
||||
}
|
||||
FileOptions OptimizeForCompactionTableWrite(
|
||||
const FileOptions& file_options,
|
||||
const ImmutableDBOptions& immutable_ops) const override {
|
||||
return target_->OptimizeForCompactionTableWrite(file_options,
|
||||
immutable_ops);
|
||||
}
|
||||
FileOptions OptimizeForCompactionTableRead(
|
||||
const FileOptions& file_options,
|
||||
const ImmutableDBOptions& db_options) const override {
|
||||
return target_->OptimizeForCompactionTableRead(file_options, db_options);
|
||||
}
|
||||
|
||||
// This seems to clash with a macro on Windows, so #undef it here
|
||||
#ifdef GetFreeSpace
|
||||
#undef GetFreeSpace
|
||||
#endif
|
||||
IOStatus GetFreeSpace(const std::string& path, const IOOptions& /*options*/,
|
||||
uint64_t* diskfree, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetFreeSpace(path, diskfree));
|
||||
}
|
||||
IOStatus IsDirectory(const std::string& path, const IOOptions& /*options*/,
|
||||
bool* is_dir, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->IsDirectory(path, is_dir));
|
||||
}
|
||||
|
||||
private:
|
||||
Env* target_;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<FSSequentialFile> NewLegacySequentialFileWrapper(
|
||||
std::unique_ptr<SequentialFile>& file) {
|
||||
return std::unique_ptr<FSSequentialFile>(
|
||||
|
||||
Vendored
+246
-11
@@ -20,6 +20,248 @@
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
class LegacyFileSystemWrapper : public FileSystem {
|
||||
public:
|
||||
// Initialize an EnvWrapper that delegates all calls to *t
|
||||
explicit LegacyFileSystemWrapper(Env* t) : target_(t) {}
|
||||
~LegacyFileSystemWrapper() override {}
|
||||
|
||||
const char* Name() const override { return "Legacy File System"; }
|
||||
|
||||
// Return the target to which this Env forwards all calls
|
||||
Env* target() const { return target_; }
|
||||
|
||||
// The following text is boilerplate that forwards all methods to target()
|
||||
IOStatus NewSequentialFile(const std::string& f, const FileOptions& file_opts,
|
||||
std::unique_ptr<FSSequentialFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<SequentialFile> file;
|
||||
Status s = target_->NewSequentialFile(f, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacySequentialFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewRandomAccessFile(const std::string& f,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomAccessFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<RandomAccessFile> file;
|
||||
Status s = target_->NewRandomAccessFile(f, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacyRandomAccessFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewWritableFile(const std::string& f, const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<WritableFile> file;
|
||||
Status s = target_->NewWritableFile(f, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacyWritableFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus ReopenWritableFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<WritableFile> file;
|
||||
Status s = target_->ReopenWritableFile(fname, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
result->reset(new LegacyWritableFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus ReuseWritableFile(const std::string& fname,
|
||||
const std::string& old_fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSWritableFile>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<WritableFile> file;
|
||||
Status s = target_->ReuseWritableFile(fname, old_fname, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
r->reset(new LegacyWritableFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewRandomRWFile(const std::string& fname,
|
||||
const FileOptions& file_opts,
|
||||
std::unique_ptr<FSRandomRWFile>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<RandomRWFile> file;
|
||||
Status s = target_->NewRandomRWFile(fname, &file, file_opts);
|
||||
if (s.ok()) {
|
||||
result->reset(new LegacyRandomRWFileWrapper(std::move(file)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus NewMemoryMappedFileBuffer(
|
||||
const std::string& fname,
|
||||
std::unique_ptr<MemoryMappedFileBuffer>* result) override {
|
||||
return status_to_io_status(
|
||||
target_->NewMemoryMappedFileBuffer(fname, result));
|
||||
}
|
||||
IOStatus NewDirectory(const std::string& name, const IOOptions& /*io_opts*/,
|
||||
std::unique_ptr<FSDirectory>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
std::unique_ptr<Directory> dir;
|
||||
Status s = target_->NewDirectory(name, &dir);
|
||||
if (s.ok()) {
|
||||
result->reset(new LegacyDirectoryWrapper(std::move(dir)));
|
||||
}
|
||||
return status_to_io_status(std::move(s));
|
||||
}
|
||||
IOStatus FileExists(const std::string& f, const IOOptions& /*io_opts*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->FileExists(f));
|
||||
}
|
||||
IOStatus GetChildren(const std::string& dir, const IOOptions& /*io_opts*/,
|
||||
std::vector<std::string>* r,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetChildren(dir, r));
|
||||
}
|
||||
IOStatus GetChildrenFileAttributes(const std::string& dir,
|
||||
const IOOptions& /*options*/,
|
||||
std::vector<FileAttributes>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetChildrenFileAttributes(dir, result));
|
||||
}
|
||||
IOStatus DeleteFile(const std::string& f, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->DeleteFile(f));
|
||||
}
|
||||
IOStatus Truncate(const std::string& fname, size_t size,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->Truncate(fname, size));
|
||||
}
|
||||
IOStatus CreateDir(const std::string& d, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->CreateDir(d));
|
||||
}
|
||||
IOStatus CreateDirIfMissing(const std::string& d,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->CreateDirIfMissing(d));
|
||||
}
|
||||
IOStatus DeleteDir(const std::string& d, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->DeleteDir(d));
|
||||
}
|
||||
IOStatus GetFileSize(const std::string& f, const IOOptions& /*options*/,
|
||||
uint64_t* s, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetFileSize(f, s));
|
||||
}
|
||||
|
||||
IOStatus GetFileModificationTime(const std::string& fname,
|
||||
const IOOptions& /*options*/,
|
||||
uint64_t* file_mtime,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(
|
||||
target_->GetFileModificationTime(fname, file_mtime));
|
||||
}
|
||||
|
||||
IOStatus GetAbsolutePath(const std::string& db_path,
|
||||
const IOOptions& /*options*/,
|
||||
std::string* output_path,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetAbsolutePath(db_path, output_path));
|
||||
}
|
||||
|
||||
IOStatus RenameFile(const std::string& s, const std::string& t,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->RenameFile(s, t));
|
||||
}
|
||||
|
||||
IOStatus LinkFile(const std::string& s, const std::string& t,
|
||||
const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->LinkFile(s, t));
|
||||
}
|
||||
|
||||
IOStatus NumFileLinks(const std::string& fname, const IOOptions& /*options*/,
|
||||
uint64_t* count, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->NumFileLinks(fname, count));
|
||||
}
|
||||
|
||||
IOStatus AreFilesSame(const std::string& first, const std::string& second,
|
||||
const IOOptions& /*options*/, bool* res,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->AreFilesSame(first, second, res));
|
||||
}
|
||||
|
||||
IOStatus LockFile(const std::string& f, const IOOptions& /*options*/,
|
||||
FileLock** l, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->LockFile(f, l));
|
||||
}
|
||||
|
||||
IOStatus UnlockFile(FileLock* l, const IOOptions& /*options*/,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->UnlockFile(l));
|
||||
}
|
||||
|
||||
IOStatus GetTestDirectory(const IOOptions& /*options*/, std::string* path,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetTestDirectory(path));
|
||||
}
|
||||
IOStatus NewLogger(const std::string& fname, const IOOptions& /*options*/,
|
||||
std::shared_ptr<Logger>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->NewLogger(fname, result));
|
||||
}
|
||||
|
||||
void SanitizeFileOptions(FileOptions* opts) const override {
|
||||
target_->SanitizeEnvOptions(opts);
|
||||
}
|
||||
|
||||
FileOptions OptimizeForLogRead(
|
||||
const FileOptions& file_options) const override {
|
||||
return target_->OptimizeForLogRead(file_options);
|
||||
}
|
||||
FileOptions OptimizeForManifestRead(
|
||||
const FileOptions& file_options) const override {
|
||||
return target_->OptimizeForManifestRead(file_options);
|
||||
}
|
||||
FileOptions OptimizeForLogWrite(const FileOptions& file_options,
|
||||
const DBOptions& db_options) const override {
|
||||
return target_->OptimizeForLogWrite(file_options, db_options);
|
||||
}
|
||||
FileOptions OptimizeForManifestWrite(
|
||||
const FileOptions& file_options) const override {
|
||||
return target_->OptimizeForManifestWrite(file_options);
|
||||
}
|
||||
FileOptions OptimizeForCompactionTableWrite(
|
||||
const FileOptions& file_options,
|
||||
const ImmutableDBOptions& immutable_ops) const override {
|
||||
return target_->OptimizeForCompactionTableWrite(file_options,
|
||||
immutable_ops);
|
||||
}
|
||||
FileOptions OptimizeForCompactionTableRead(
|
||||
const FileOptions& file_options,
|
||||
const ImmutableDBOptions& db_options) const override {
|
||||
return target_->OptimizeForCompactionTableRead(file_options, db_options);
|
||||
}
|
||||
|
||||
#ifdef GetFreeSpace
|
||||
#undef GetFreeSpace
|
||||
#endif
|
||||
IOStatus GetFreeSpace(const std::string& path, const IOOptions& /*options*/,
|
||||
uint64_t* diskfree, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->GetFreeSpace(path, diskfree));
|
||||
}
|
||||
IOStatus IsDirectory(const std::string& path, const IOOptions& /*options*/,
|
||||
bool* is_dir, IODebugContext* /*dbg*/) override {
|
||||
return status_to_io_status(target_->IsDirectory(path, is_dir));
|
||||
}
|
||||
|
||||
private:
|
||||
Env* target_;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
Env::Env() : thread_status_updater_(nullptr) {
|
||||
file_system_ = std::make_shared<LegacyFileSystemWrapper>(this);
|
||||
@@ -386,13 +628,13 @@ void Log(const std::shared_ptr<Logger>& info_log, const char* format, ...) {
|
||||
|
||||
Status WriteStringToFile(Env* env, const Slice& data, const std::string& fname,
|
||||
bool should_sync) {
|
||||
LegacyFileSystemWrapper lfsw(env);
|
||||
return WriteStringToFile(&lfsw, data, fname, should_sync);
|
||||
const auto& fs = env->GetFileSystem();
|
||||
return WriteStringToFile(fs.get(), data, fname, should_sync);
|
||||
}
|
||||
|
||||
Status ReadFileToString(Env* env, const std::string& fname, std::string* data) {
|
||||
LegacyFileSystemWrapper lfsw(env);
|
||||
return ReadFileToString(&lfsw, fname, data);
|
||||
const auto& fs = env->GetFileSystem();
|
||||
return ReadFileToString(fs.get(), fname, data);
|
||||
}
|
||||
|
||||
EnvWrapper::~EnvWrapper() {
|
||||
@@ -488,11 +730,4 @@ Status NewEnvLogger(const std::string& fname, Env* env,
|
||||
const std::shared_ptr<FileSystem>& Env::GetFileSystem() const {
|
||||
return file_system_;
|
||||
}
|
||||
|
||||
#ifdef OS_WIN
|
||||
std::unique_ptr<Env> NewCompositeEnv(std::shared_ptr<FileSystem> fs) {
|
||||
return std::unique_ptr<Env>(new CompositeEnvWrapper(Env::Default(), fs));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
+32
-61
@@ -10,6 +10,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "env/mock_env.h"
|
||||
#include "file/file_util.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/env_encryption.h"
|
||||
@@ -17,46 +18,6 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
// Normalizes trivial differences across Envs such that these test cases can
|
||||
// run on all Envs.
|
||||
class NormalizingEnvWrapper : public EnvWrapper {
|
||||
private:
|
||||
std::unique_ptr<Env> base_;
|
||||
|
||||
public:
|
||||
explicit NormalizingEnvWrapper(std::unique_ptr<Env>&& base)
|
||||
: EnvWrapper(base.get()), base_(std::move(base)) {}
|
||||
explicit NormalizingEnvWrapper(Env* base) : EnvWrapper(base) {}
|
||||
|
||||
// Removes . and .. from directory listing
|
||||
Status GetChildren(const std::string& dir,
|
||||
std::vector<std::string>* result) override {
|
||||
Status status = EnvWrapper::GetChildren(dir, result);
|
||||
if (status.ok()) {
|
||||
result->erase(std::remove_if(result->begin(), result->end(),
|
||||
[](const std::string& s) {
|
||||
return s == "." || s == "..";
|
||||
}),
|
||||
result->end());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Removes . and .. from directory listing
|
||||
Status GetChildrenFileAttributes(
|
||||
const std::string& dir, std::vector<FileAttributes>* result) override {
|
||||
Status status = EnvWrapper::GetChildrenFileAttributes(dir, result);
|
||||
if (status.ok()) {
|
||||
result->erase(std::remove_if(result->begin(), result->end(),
|
||||
[](const FileAttributes& fa) {
|
||||
return fa.name == "." || fa.name == "..";
|
||||
}),
|
||||
result->end());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
class EnvBasicTestWithParam : public testing::Test,
|
||||
public ::testing::WithParamInterface<Env*> {
|
||||
public:
|
||||
@@ -68,32 +29,17 @@ class EnvBasicTestWithParam : public testing::Test,
|
||||
test_dir_ = test::PerThreadDBPath(env_, "env_basic_test");
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
env_->CreateDirIfMissing(test_dir_).PermitUncheckedError();
|
||||
}
|
||||
void SetUp() override { ASSERT_OK(env_->CreateDirIfMissing(test_dir_)); }
|
||||
|
||||
void TearDown() override {
|
||||
std::vector<std::string> files;
|
||||
env_->GetChildren(test_dir_, &files).PermitUncheckedError();
|
||||
for (const auto& file : files) {
|
||||
// don't know whether it's file or directory, try both. The tests must
|
||||
// only create files or empty directories, so one must succeed, else the
|
||||
// directory's corrupted.
|
||||
Status s = env_->DeleteFile(test_dir_ + "/" + file);
|
||||
if (!s.ok()) {
|
||||
ASSERT_OK(env_->DeleteDir(test_dir_ + "/" + file));
|
||||
}
|
||||
}
|
||||
}
|
||||
void TearDown() override { ASSERT_OK(DestroyDir(env_, test_dir_)); }
|
||||
};
|
||||
|
||||
class EnvMoreTestWithParam : public EnvBasicTestWithParam {};
|
||||
|
||||
static std::unique_ptr<Env> def_env(new NormalizingEnvWrapper(Env::Default()));
|
||||
INSTANTIATE_TEST_CASE_P(EnvDefault, EnvBasicTestWithParam,
|
||||
::testing::Values(def_env.get()));
|
||||
::testing::Values(Env::Default()));
|
||||
INSTANTIATE_TEST_CASE_P(EnvDefault, EnvMoreTestWithParam,
|
||||
::testing::Values(def_env.get()));
|
||||
::testing::Values(Env::Default()));
|
||||
|
||||
static std::unique_ptr<Env> mock_env(new MockEnv(Env::Default()));
|
||||
INSTANTIATE_TEST_CASE_P(MockEnv, EnvBasicTestWithParam,
|
||||
@@ -104,8 +50,7 @@ static Env* NewTestEncryptedEnv(Env* base, const std::string& provider_id) {
|
||||
std::shared_ptr<EncryptionProvider> provider;
|
||||
EXPECT_OK(EncryptionProvider::CreateFromString(ConfigOptions(), provider_id,
|
||||
&provider));
|
||||
std::unique_ptr<Env> encrypted(NewEncryptedEnv(base, provider));
|
||||
return new NormalizingEnvWrapper(std::move(encrypted));
|
||||
return NewEncryptedEnv(base, provider);
|
||||
}
|
||||
|
||||
// next statements run env test against default encryption code.
|
||||
@@ -374,6 +319,32 @@ TEST_P(EnvMoreTestWithParam, GetChildren) {
|
||||
ASSERT_EQ(0U, children.size());
|
||||
}
|
||||
|
||||
TEST_P(EnvMoreTestWithParam, GetChildrenIgnoresDotAndDotDot) {
|
||||
auto* env = Env::Default();
|
||||
ASSERT_OK(env->CreateDirIfMissing(test_dir_));
|
||||
|
||||
// Create a single file
|
||||
std::string path = test_dir_;
|
||||
const EnvOptions soptions;
|
||||
#ifdef OS_WIN
|
||||
path.append("\\test_file");
|
||||
#else
|
||||
path.append("/test_file");
|
||||
#endif
|
||||
std::string data("test data");
|
||||
std::unique_ptr<WritableFile> file;
|
||||
ASSERT_OK(env->NewWritableFile(path, &file, soptions));
|
||||
ASSERT_OK(file->Append("test data"));
|
||||
|
||||
// get the children
|
||||
std::vector<std::string> result;
|
||||
ASSERT_OK(env->GetChildren(test_dir_, &result));
|
||||
|
||||
// expect only one file named `test_data`, i.e. no `.` or `..` names
|
||||
ASSERT_EQ(result.size(), 1);
|
||||
ASSERT_EQ(result.at(0), "test_file");
|
||||
}
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
Vendored
+11
-15
@@ -122,14 +122,9 @@ class PosixDynamicLibrary : public DynamicLibrary {
|
||||
};
|
||||
#endif // !ROCKSDB_NO_DYNAMIC_EXTENSION
|
||||
|
||||
class PosixEnv : public CompositeEnvWrapper {
|
||||
class PosixEnv : public CompositeEnv {
|
||||
public:
|
||||
// This constructor is for constructing non-default Envs, mainly by
|
||||
// NewCompositeEnv(). It allows new instances to share the same
|
||||
// threadpool and other resources as the default Env, while allowing
|
||||
// a non-default FileSystem implementation
|
||||
PosixEnv(const PosixEnv* default_env, std::shared_ptr<FileSystem> fs);
|
||||
|
||||
PosixEnv(const PosixEnv* default_env, const std::shared_ptr<FileSystem>& fs);
|
||||
~PosixEnv() override {
|
||||
if (this == Env::Default()) {
|
||||
for (const auto tid : threads_to_join_) {
|
||||
@@ -387,7 +382,7 @@ class PosixEnv : public CompositeEnvWrapper {
|
||||
};
|
||||
|
||||
PosixEnv::PosixEnv()
|
||||
: CompositeEnvWrapper(this, FileSystem::Default()),
|
||||
: CompositeEnv(FileSystem::Default()),
|
||||
thread_pools_storage_(Priority::TOTAL),
|
||||
allow_non_owner_access_storage_(true),
|
||||
thread_pools_(thread_pools_storage_),
|
||||
@@ -404,12 +399,13 @@ PosixEnv::PosixEnv()
|
||||
thread_status_updater_ = CreateThreadStatusUpdater();
|
||||
}
|
||||
|
||||
PosixEnv::PosixEnv(const PosixEnv* default_env, std::shared_ptr<FileSystem> fs)
|
||||
: CompositeEnvWrapper(this, fs),
|
||||
thread_pools_(default_env->thread_pools_),
|
||||
mu_(default_env->mu_),
|
||||
threads_to_join_(default_env->threads_to_join_),
|
||||
allow_non_owner_access_(default_env->allow_non_owner_access_) {
|
||||
PosixEnv::PosixEnv(const PosixEnv* default_env,
|
||||
const std::shared_ptr<FileSystem>& fs)
|
||||
: CompositeEnv(fs),
|
||||
thread_pools_(default_env->thread_pools_),
|
||||
mu_(default_env->mu_),
|
||||
threads_to_join_(default_env->threads_to_join_),
|
||||
allow_non_owner_access_(default_env->allow_non_owner_access_) {
|
||||
thread_status_updater_ = default_env->thread_status_updater_;
|
||||
}
|
||||
|
||||
@@ -508,7 +504,7 @@ Env* Env::Default() {
|
||||
return &default_env;
|
||||
}
|
||||
|
||||
std::unique_ptr<Env> NewCompositeEnv(std::shared_ptr<FileSystem> fs) {
|
||||
std::unique_ptr<Env> NewCompositeEnv(const std::shared_ptr<FileSystem>& fs) {
|
||||
PosixEnv* default_env = static_cast<PosixEnv*>(Env::Default());
|
||||
return std::unique_ptr<Env>(new PosixEnv(default_env, fs));
|
||||
}
|
||||
|
||||
Vendored
-9
@@ -129,13 +129,4 @@ IOStatus ReadFileToString(FileSystem* fs, const std::string& fname,
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef OS_WIN
|
||||
std::shared_ptr<FileSystem> FileSystem::Default() {
|
||||
static LegacyFileSystemWrapper default_fs(Env::Default());
|
||||
static std::shared_ptr<LegacyFileSystemWrapper> default_fs_ptr(
|
||||
&default_fs, [](LegacyFileSystemWrapper*) {});
|
||||
return default_fs_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
Vendored
+27
-3
@@ -607,6 +607,7 @@ class PosixFileSystem : public FileSystem {
|
||||
std::vector<std::string>* result,
|
||||
IODebugContext* /*dbg*/) override {
|
||||
result->clear();
|
||||
|
||||
DIR* d = opendir(dir.c_str());
|
||||
if (d == nullptr) {
|
||||
switch (errno) {
|
||||
@@ -618,11 +619,34 @@ class PosixFileSystem : public FileSystem {
|
||||
return IOError("While opendir", dir, errno);
|
||||
}
|
||||
}
|
||||
|
||||
const auto pre_read_errno = errno; // errno may be modified by readdir
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(d)) != nullptr) {
|
||||
result->push_back(entry->d_name);
|
||||
while ((entry = readdir(d)) != nullptr && errno == pre_read_errno) {
|
||||
// filter out '.' and '..' directory entries
|
||||
// which appear only on some platforms
|
||||
const bool ignore =
|
||||
entry->d_type == DT_DIR &&
|
||||
(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0);
|
||||
if (!ignore) {
|
||||
result->push_back(entry->d_name);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
|
||||
// always attempt to close the dir
|
||||
const auto pre_close_errno = errno; // errno may be modified by closedir
|
||||
const int close_result = closedir(d);
|
||||
|
||||
if (pre_close_errno != pre_read_errno) {
|
||||
// error occured during readdir
|
||||
return IOError("While readdir", dir, pre_close_errno);
|
||||
}
|
||||
|
||||
if (close_result != 0) {
|
||||
// error occured during closedir
|
||||
return IOError("While closedir", dir, errno);
|
||||
}
|
||||
|
||||
return IOStatus::OK();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ DeleteScheduler::~DeleteScheduler() {
|
||||
if (bg_thread_) {
|
||||
bg_thread_->join();
|
||||
}
|
||||
for (const auto& it : bg_errors_) {
|
||||
it.second.PermitUncheckedError();
|
||||
}
|
||||
}
|
||||
|
||||
Status DeleteScheduler::DeleteFile(const std::string& file_path,
|
||||
@@ -98,11 +101,13 @@ Status DeleteScheduler::DeleteFile(const std::string& file_path,
|
||||
|
||||
// Update the total trash size
|
||||
uint64_t trash_file_size = 0;
|
||||
Status ignored =
|
||||
IOStatus io_s =
|
||||
fs_->GetFileSize(trash_file, IOOptions(), &trash_file_size, nullptr);
|
||||
ignored.PermitUncheckedError(); //**TODO: What should we do if we failed to
|
||||
// get the file size?
|
||||
total_trash_size_.fetch_add(trash_file_size);
|
||||
if (io_s.ok()) {
|
||||
total_trash_size_.fetch_add(trash_file_size);
|
||||
}
|
||||
//**TODO: What should we do if we failed to
|
||||
// get the file size?
|
||||
|
||||
// Add file to delete queue
|
||||
{
|
||||
@@ -199,9 +204,7 @@ Status DeleteScheduler::MarkAsTrash(const std::string& file_path,
|
||||
cnt++;
|
||||
}
|
||||
if (s.ok()) {
|
||||
//**TODO: What should we do if this returns an error?
|
||||
sst_file_manager_->OnMoveFile(file_path, *trash_file)
|
||||
.PermitUncheckedError();
|
||||
s = sst_file_manager_->OnMoveFile(file_path, *trash_file);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class SstFileManagerImpl;
|
||||
|
||||
// DeleteScheduler allows the DB to enforce a rate limit on file deletion,
|
||||
// Instead of deleteing files immediately, files are marked as trash
|
||||
// and deleted in a background thread that apply sleep penlty between deletes
|
||||
// and deleted in a background thread that apply sleep penalty between deletes
|
||||
// if they are happening in a rate faster than rate_bytes_per_sec,
|
||||
//
|
||||
// Rate limiting can be turned off by setting rate_bytes_per_sec = 0, In this
|
||||
@@ -48,7 +48,7 @@ class DeleteScheduler {
|
||||
MaybeCreateBackgroundThread();
|
||||
}
|
||||
|
||||
// Mark file as trash directory and schedule it's deletion. If force_bg is
|
||||
// Mark file as trash directory and schedule its deletion. If force_bg is
|
||||
// set, it forces the file to always be deleted in the background thread,
|
||||
// except when rate limiting is disabled
|
||||
Status DeleteFile(const std::string& fname, const std::string& dir_to_sync,
|
||||
@@ -78,7 +78,7 @@ class DeleteScheduler {
|
||||
static const std::string kTrashExtension;
|
||||
static bool IsTrashFile(const std::string& file_path);
|
||||
|
||||
// Check if there are any .trash filse in path, and schedule their deletion
|
||||
// Check if there are any .trash files in path, and schedule their deletion
|
||||
// Or delete immediately if sst_file_manager is nullptr
|
||||
static Status CleanupDirectory(Env* env, SstFileManagerImpl* sfm,
|
||||
const std::string& path);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "file/file_util.h"
|
||||
#include "file/sst_file_manager_impl.h"
|
||||
#include "rocksdb/env.h"
|
||||
@@ -58,7 +57,7 @@ class DeleteSchedulerTest : public testing::Test {
|
||||
|
||||
int normal_cnt = 0;
|
||||
for (auto& f : files_in_dir) {
|
||||
if (!DeleteScheduler::IsTrashFile(f) && f != "." && f != "..") {
|
||||
if (!DeleteScheduler::IsTrashFile(f)) {
|
||||
normal_cnt++;
|
||||
}
|
||||
}
|
||||
@@ -96,11 +95,9 @@ class DeleteSchedulerTest : public testing::Test {
|
||||
// Tests in this file are for DeleteScheduler component and don't create any
|
||||
// DBs, so we need to set max_trash_db_ratio to 100% (instead of default
|
||||
// 25%)
|
||||
std::shared_ptr<FileSystem>
|
||||
fs(std::make_shared<LegacyFileSystemWrapper>(env_));
|
||||
sst_file_mgr_.reset(
|
||||
new SstFileManagerImpl(env_, fs, nullptr, rate_bytes_per_sec_,
|
||||
/* max_trash_db_ratio= */ 1.1, 128 * 1024));
|
||||
sst_file_mgr_.reset(new SstFileManagerImpl(
|
||||
env_, env_->GetFileSystem(), nullptr, rate_bytes_per_sec_,
|
||||
/* max_trash_db_ratio= */ 1.1, 128 * 1024));
|
||||
delete_scheduler_ = sst_file_mgr_->delete_scheduler();
|
||||
sst_file_mgr_->SetStatisticsPtr(stats_);
|
||||
}
|
||||
@@ -426,7 +423,9 @@ TEST_F(DeleteSchedulerTest, BackgroundError) {
|
||||
delete_scheduler_->WaitForEmptyTrash();
|
||||
auto bg_errors = delete_scheduler_->GetBackgroundErrors();
|
||||
ASSERT_EQ(bg_errors.size(), 10);
|
||||
|
||||
for (const auto& it : bg_errors) {
|
||||
ASSERT_TRUE(it.second.IsPathNotFound());
|
||||
}
|
||||
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
@@ -670,7 +669,7 @@ TEST_F(DeleteSchedulerTest, ImmediateDeleteOn25PercDBSize) {
|
||||
}
|
||||
|
||||
for (std::string& file_name : generated_files) {
|
||||
delete_scheduler_->DeleteFile(file_name, "");
|
||||
ASSERT_OK(delete_scheduler_->DeleteFile(file_name, ""));
|
||||
}
|
||||
|
||||
// When we end up with 26 files in trash we will start
|
||||
|
||||
+18
-11
@@ -124,8 +124,10 @@ bool IsWalDirSameAsDBPath(const ImmutableDBOptions* db_options) {
|
||||
}
|
||||
|
||||
// requested_checksum_func_name brings the function name of the checksum
|
||||
// generator in checksum_factory. Checksum factories may use or ignore
|
||||
// requested_checksum_func_name.
|
||||
// generator in checksum_factory. Empty string is permitted, in which case the
|
||||
// name of the generator created by the factory is unchecked. When
|
||||
// `requested_checksum_func_name` is non-empty, however, the created generator's
|
||||
// name must match it, otherwise an `InvalidArgument` error is returned.
|
||||
IOStatus GenerateOneFileChecksum(
|
||||
FileSystem* fs, const std::string& file_path,
|
||||
FileChecksumGenFactory* checksum_factory,
|
||||
@@ -151,14 +153,22 @@ IOStatus GenerateOneFileChecksum(
|
||||
requested_checksum_func_name +
|
||||
" from checksum factory: " + checksum_factory->Name();
|
||||
return IOStatus::InvalidArgument(msg);
|
||||
} else {
|
||||
// For backward compatibility and use in file ingestion clients where there
|
||||
// is no stored checksum function name, `requested_checksum_func_name` can
|
||||
// be empty. If we give the requested checksum function name, we expect it
|
||||
// is the same name of the checksum generator.
|
||||
if (!requested_checksum_func_name.empty() &&
|
||||
checksum_generator->Name() != requested_checksum_func_name) {
|
||||
std::string msg = "Expected file checksum generator named '" +
|
||||
requested_checksum_func_name +
|
||||
"', while the factory created one "
|
||||
"named '" +
|
||||
checksum_generator->Name() + "'";
|
||||
return IOStatus::InvalidArgument(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// For backward compatable, requested_checksum_func_name can be empty.
|
||||
// If we give the requested checksum function name, we expect it is the
|
||||
// same name of the checksum generator.
|
||||
assert(!checksum_generator || requested_checksum_func_name.empty() ||
|
||||
requested_checksum_func_name == checksum_generator->Name());
|
||||
|
||||
uint64_t size;
|
||||
IOStatus io_s;
|
||||
std::unique_ptr<RandomAccessFileReader> reader;
|
||||
@@ -220,9 +230,6 @@ Status DestroyDir(Env* env, const std::string& dir) {
|
||||
s = env->GetChildren(dir, &files_in_dir);
|
||||
if (s.ok()) {
|
||||
for (auto& file_in_dir : files_in_dir) {
|
||||
if (file_in_dir == "." || file_in_dir == "..") {
|
||||
continue;
|
||||
}
|
||||
std::string path = dir + "/" + file_in_dir;
|
||||
bool is_dir = false;
|
||||
s = env->IsDirectory(path, &is_dir);
|
||||
|
||||
@@ -22,10 +22,23 @@ extern IOStatus CopyFile(FileSystem* fs, const std::string& source,
|
||||
const std::string& destination, uint64_t size,
|
||||
bool use_fsync,
|
||||
const std::shared_ptr<IOTracer>& io_tracer = nullptr);
|
||||
inline IOStatus CopyFile(const std::shared_ptr<FileSystem>& fs,
|
||||
const std::string& source,
|
||||
const std::string& destination, uint64_t size,
|
||||
bool use_fsync,
|
||||
const std::shared_ptr<IOTracer>& io_tracer = nullptr) {
|
||||
return CopyFile(fs.get(), source, destination, size, use_fsync, io_tracer);
|
||||
}
|
||||
|
||||
extern IOStatus CreateFile(FileSystem* fs, const std::string& destination,
|
||||
const std::string& contents, bool use_fsync);
|
||||
|
||||
inline IOStatus CreateFile(const std::shared_ptr<FileSystem>& fs,
|
||||
const std::string& destination,
|
||||
const std::string& contents, bool use_fsync) {
|
||||
return CreateFile(fs.get(), destination, contents, use_fsync);
|
||||
}
|
||||
|
||||
extern Status DeleteDBFile(const ImmutableDBOptions* db_options,
|
||||
const std::string& fname,
|
||||
const std::string& path_to_sync, const bool force_bg,
|
||||
@@ -41,6 +54,19 @@ extern IOStatus GenerateOneFileChecksum(
|
||||
size_t verify_checksums_readahead_size, bool allow_mmap_reads,
|
||||
std::shared_ptr<IOTracer>& io_tracer, RateLimiter* rate_limiter = nullptr);
|
||||
|
||||
inline IOStatus GenerateOneFileChecksum(
|
||||
const std::shared_ptr<FileSystem>& fs, const std::string& file_path,
|
||||
FileChecksumGenFactory* checksum_factory,
|
||||
const std::string& requested_checksum_func_name, std::string* file_checksum,
|
||||
std::string* file_checksum_func_name,
|
||||
size_t verify_checksums_readahead_size, bool allow_mmap_reads,
|
||||
std::shared_ptr<IOTracer>& io_tracer) {
|
||||
return GenerateOneFileChecksum(
|
||||
fs.get(), file_path, checksum_factory, requested_checksum_func_name,
|
||||
file_checksum, file_checksum_func_name, verify_checksums_readahead_size,
|
||||
allow_mmap_reads, io_tracer);
|
||||
}
|
||||
|
||||
inline IOStatus PrepareIOFromReadOptions(const ReadOptions& ro, Env* env,
|
||||
IOOptions& opts) {
|
||||
if (!env) {
|
||||
|
||||
@@ -75,7 +75,9 @@ std::string BuildKey(int num, std::string postfix = "") {
|
||||
|
||||
TEST_P(PrefetchTest, Basic) {
|
||||
// First param is if the mockFS support_prefetch or not
|
||||
bool support_prefetch = std::get<0>(GetParam());
|
||||
bool support_prefetch =
|
||||
std::get<0>(GetParam()) &&
|
||||
test::IsPrefetchSupported(env_->GetFileSystem(), dbname_);
|
||||
|
||||
// Second param is if directIO is enabled or not
|
||||
bool use_direct_io = std::get<1>(GetParam());
|
||||
|
||||
+25
-18
@@ -11,15 +11,17 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
#include "file/read_write_util.h"
|
||||
#include "rocksdb/file_system.h"
|
||||
#include "util/aligned_buffer.h"
|
||||
#include "util/rate_limiter.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
namespace {
|
||||
class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
class ReadaheadRandomAccessFile : public FSRandomAccessFile {
|
||||
public:
|
||||
ReadaheadRandomAccessFile(std::unique_ptr<RandomAccessFile>&& file,
|
||||
ReadaheadRandomAccessFile(std::unique_ptr<FSRandomAccessFile>&& file,
|
||||
size_t readahead_size)
|
||||
: file_(std::move(file)),
|
||||
alignment_(file_->GetRequiredBufferAlignment()),
|
||||
@@ -35,11 +37,12 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
ReadaheadRandomAccessFile& operator=(const ReadaheadRandomAccessFile&) =
|
||||
delete;
|
||||
|
||||
Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const override {
|
||||
IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
|
||||
Slice* result, char* scratch,
|
||||
IODebugContext* dbg) const override {
|
||||
// Read-ahead only make sense if we have some slack left after reading
|
||||
if (n + alignment_ >= readahead_size_) {
|
||||
return file_->Read(offset, n, result, scratch);
|
||||
return file_->Read(offset, n, options, result, scratch, dbg);
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lk(lock_);
|
||||
@@ -53,14 +56,14 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
(cached_len == n || buffer_.CurrentSize() < readahead_size_)) {
|
||||
// We read exactly what we needed, or we hit end of file - return.
|
||||
*result = Slice(scratch, cached_len);
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
size_t advanced_offset = static_cast<size_t>(offset + cached_len);
|
||||
// In the case of cache hit advanced_offset is already aligned, means that
|
||||
// chunk_offset equals to advanced_offset
|
||||
size_t chunk_offset = TruncateToPageBoundary(alignment_, advanced_offset);
|
||||
|
||||
Status s = ReadIntoBuffer(chunk_offset, readahead_size_);
|
||||
IOStatus s = ReadIntoBuffer(chunk_offset, readahead_size_, options, dbg);
|
||||
if (s.ok()) {
|
||||
// The data we need is now in cache, so we can safely read it
|
||||
size_t remaining_len;
|
||||
@@ -71,11 +74,12 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
return s;
|
||||
}
|
||||
|
||||
Status Prefetch(uint64_t offset, size_t n) override {
|
||||
IOStatus Prefetch(uint64_t offset, size_t n, const IOOptions& options,
|
||||
IODebugContext* dbg) override {
|
||||
if (n < readahead_size_) {
|
||||
// Don't allow smaller prefetches than the configured `readahead_size_`.
|
||||
// `Read()` assumes a smaller prefetch buffer indicates EOF was reached.
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lk(lock_);
|
||||
@@ -83,10 +87,11 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
size_t offset_ = static_cast<size_t>(offset);
|
||||
size_t prefetch_offset = TruncateToPageBoundary(alignment_, offset_);
|
||||
if (prefetch_offset == buffer_offset_) {
|
||||
return Status::OK();
|
||||
return IOStatus::OK();
|
||||
}
|
||||
return ReadIntoBuffer(prefetch_offset,
|
||||
Roundup(offset_ + n, alignment_) - prefetch_offset);
|
||||
Roundup(offset_ + n, alignment_) - prefetch_offset,
|
||||
options, dbg);
|
||||
}
|
||||
|
||||
size_t GetUniqueId(char* id, size_t max_size) const override {
|
||||
@@ -95,7 +100,7 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
|
||||
void Hint(AccessPattern pattern) override { file_->Hint(pattern); }
|
||||
|
||||
Status InvalidateCache(size_t offset, size_t length) override {
|
||||
IOStatus InvalidateCache(size_t offset, size_t length) override {
|
||||
std::unique_lock<std::mutex> lk(lock_);
|
||||
buffer_.Clear();
|
||||
return file_->InvalidateCache(offset, length);
|
||||
@@ -125,14 +130,16 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
// Reads into buffer_ the next n bytes from file_ starting at offset.
|
||||
// Can actually read less if EOF was reached.
|
||||
// Returns the status of the read operastion on the file.
|
||||
Status ReadIntoBuffer(uint64_t offset, size_t n) const {
|
||||
IOStatus ReadIntoBuffer(uint64_t offset, size_t n, const IOOptions& options,
|
||||
IODebugContext* dbg) const {
|
||||
if (n > buffer_.Capacity()) {
|
||||
n = buffer_.Capacity();
|
||||
}
|
||||
assert(IsFileSectorAligned(offset, alignment_));
|
||||
assert(IsFileSectorAligned(n, alignment_));
|
||||
Slice result;
|
||||
Status s = file_->Read(offset, n, &result, buffer_.BufferStart());
|
||||
IOStatus s =
|
||||
file_->Read(offset, n, options, &result, buffer_.BufferStart(), dbg);
|
||||
if (s.ok()) {
|
||||
buffer_offset_ = offset;
|
||||
buffer_.Size(result.size());
|
||||
@@ -141,7 +148,7 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
return s;
|
||||
}
|
||||
|
||||
const std::unique_ptr<RandomAccessFile> file_;
|
||||
const std::unique_ptr<FSRandomAccessFile> file_;
|
||||
const size_t alignment_;
|
||||
const size_t readahead_size_;
|
||||
|
||||
@@ -153,9 +160,9 @@ class ReadaheadRandomAccessFile : public RandomAccessFile {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<RandomAccessFile> NewReadaheadRandomAccessFile(
|
||||
std::unique_ptr<RandomAccessFile>&& file, size_t readahead_size) {
|
||||
std::unique_ptr<RandomAccessFile> result(
|
||||
std::unique_ptr<FSRandomAccessFile> NewReadaheadRandomAccessFile(
|
||||
std::unique_ptr<FSRandomAccessFile>&& file, size_t readahead_size) {
|
||||
std::unique_ptr<FSRandomAccessFile> result(
|
||||
new ReadaheadRandomAccessFile(std::move(file), readahead_size));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include "rocksdb/env.h"
|
||||
#include <memory>
|
||||
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class FSRandomAccessFile;
|
||||
// This file provides the following main abstractions:
|
||||
// SequentialFileReader : wrapper over Env::SequentialFile
|
||||
// RandomAccessFileReader : wrapper over Env::RandomAccessFile
|
||||
@@ -22,6 +24,6 @@ namespace ROCKSDB_NAMESPACE {
|
||||
// NewReadaheadRandomAccessFile provides a wrapper over RandomAccessFile to
|
||||
// always prefetch additional data with every read. This is mainly used in
|
||||
// Compaction Table Readers.
|
||||
std::unique_ptr<RandomAccessFile> NewReadaheadRandomAccessFile(
|
||||
std::unique_ptr<RandomAccessFile>&& file, size_t readahead_size);
|
||||
std::unique_ptr<FSRandomAccessFile> NewReadaheadRandomAccessFile(
|
||||
std::unique_ptr<FSRandomAccessFile>&& file, size_t readahead_size);
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "db/db_impl/db_impl.h"
|
||||
#include "env/composite_env_wrapper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/sst_file_manager.h"
|
||||
@@ -159,7 +158,7 @@ bool SstFileManagerImpl::IsMaxAllowedSpaceReachedIncludingCompactions() {
|
||||
|
||||
bool SstFileManagerImpl::EnoughRoomForCompaction(
|
||||
ColumnFamilyData* cfd, const std::vector<CompactionInputFiles>& inputs,
|
||||
Status bg_error) {
|
||||
const Status& bg_error) {
|
||||
MutexLock l(&mu_);
|
||||
uint64_t size_added_by_compaction = 0;
|
||||
// First check if we even have the space to do the compaction
|
||||
@@ -184,7 +183,7 @@ bool SstFileManagerImpl::EnoughRoomForCompaction(
|
||||
// seen a NoSpace() error. This is tin order to contain a single potentially
|
||||
// misbehaving DB instance and prevent it from slowing down compactions of
|
||||
// other DB instances
|
||||
if (bg_error == Status::NoSpace() && CheckFreeSpace()) {
|
||||
if (bg_error.IsNoSpace() && CheckFreeSpace()) {
|
||||
auto fn =
|
||||
TableFileName(cfd->ioptions()->cf_paths, inputs[0][0]->fd.GetNumber(),
|
||||
inputs[0][0]->fd.GetPathId());
|
||||
@@ -485,13 +484,7 @@ SstFileManager* NewSstFileManager(Env* env, std::shared_ptr<Logger> info_log,
|
||||
bool delete_existing_trash, Status* status,
|
||||
double max_trash_db_ratio,
|
||||
uint64_t bytes_max_delete_chunk) {
|
||||
std::shared_ptr<FileSystem> fs;
|
||||
|
||||
if (env == Env::Default()) {
|
||||
fs = FileSystem::Default();
|
||||
} else {
|
||||
fs.reset(new LegacyFileSystemWrapper(env));
|
||||
}
|
||||
const auto& fs = env->GetFileSystem();
|
||||
|
||||
return NewSstFileManager(env, fs, info_log, trash_dir, rate_bytes_per_sec,
|
||||
delete_existing_trash, status, max_trash_db_ratio,
|
||||
@@ -517,10 +510,6 @@ SstFileManager* NewSstFileManager(Env* env, std::shared_ptr<FileSystem> fs,
|
||||
s = fs->GetChildren(trash_dir, IOOptions(), &files_in_trash, nullptr);
|
||||
if (s.ok()) {
|
||||
for (const std::string& trash_file : files_in_trash) {
|
||||
if (trash_file == "." || trash_file == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string path_in_trash = trash_dir + "/" + trash_file;
|
||||
res->OnAddFile(path_in_trash);
|
||||
Status file_delete =
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace ROCKSDB_NAMESPACE {
|
||||
class Env;
|
||||
class Logger;
|
||||
|
||||
// SstFileManager is used to track SST files in the DB and control there
|
||||
// SstFileManager is used to track SST files in the DB and control their
|
||||
// deletion rate.
|
||||
// All SstFileManager public functions are thread-safe.
|
||||
class SstFileManagerImpl : public SstFileManager {
|
||||
@@ -77,7 +77,7 @@ class SstFileManagerImpl : public SstFileManager {
|
||||
// the full compaction size).
|
||||
bool EnoughRoomForCompaction(ColumnFamilyData* cfd,
|
||||
const std::vector<CompactionInputFiles>& inputs,
|
||||
Status bg_error);
|
||||
const Status& bg_error);
|
||||
|
||||
// Bookkeeping so total_file_sizes_ goes back to normal after compaction
|
||||
// finishes
|
||||
|
||||
+2
-2
@@ -496,13 +496,13 @@ extern ROCKSDB_LIBRARY_API char* rocksdb_property_value_cf(
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_approximate_sizes(
|
||||
rocksdb_t* db, int num_ranges, const char* const* range_start_key,
|
||||
const size_t* range_start_key_len, const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len, uint64_t* sizes);
|
||||
const size_t* range_limit_key_len, uint64_t* sizes, char** errptr);
|
||||
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_approximate_sizes_cf(
|
||||
rocksdb_t* db, rocksdb_column_family_handle_t* column_family,
|
||||
int num_ranges, const char* const* range_start_key,
|
||||
const size_t* range_start_key_len, const char* const* range_limit_key,
|
||||
const size_t* range_limit_key_len, uint64_t* sizes);
|
||||
const size_t* range_limit_key_len, uint64_t* sizes, char** errptr);
|
||||
|
||||
extern ROCKSDB_LIBRARY_API void rocksdb_compact_range(rocksdb_t* db,
|
||||
const char* start_key,
|
||||
|
||||
@@ -83,7 +83,7 @@ class CompactionFilter {
|
||||
//
|
||||
// Note that RocksDB snapshots (i.e. call GetSnapshot() API on a
|
||||
// DB* object) will not guarantee to preserve the state of the DB with
|
||||
// CompactionFilter. Data seen from a snapshot might disppear after a
|
||||
// CompactionFilter. Data seen from a snapshot might disappear after a
|
||||
// compaction finishes. If you use snapshots, think twice about whether you
|
||||
// want to use compaction filter and whether you are using it in a safe way.
|
||||
//
|
||||
@@ -188,7 +188,7 @@ class CompactionFilter {
|
||||
|
||||
// This function is deprecated. Snapshots will always be ignored for
|
||||
// compaction filters, because we realized that not ignoring snapshots doesn't
|
||||
// provide the gurantee we initially thought it would provide. Repeatable
|
||||
// provide the guarantee we initially thought it would provide. Repeatable
|
||||
// reads will not be guaranteed anyway. If you override the function and
|
||||
// returns false, we will fail the compaction.
|
||||
virtual bool IgnoreSnapshots() const { return true; }
|
||||
|
||||
@@ -240,7 +240,7 @@ class Configurable {
|
||||
// @param config_options Controls how the object is prepared. Also contains
|
||||
// a Logger and Env that can be used to initialize this object.
|
||||
// @return OK If the object was successfully initialized.
|
||||
// @return InvalidArgument If this object could not be successfull
|
||||
// @return InvalidArgument If this object could not be successfully
|
||||
// initialized.
|
||||
virtual Status PrepareOptions(const ConfigOptions& config_options);
|
||||
|
||||
|
||||
+10
-8
@@ -1027,20 +1027,22 @@ class DB {
|
||||
// Simpler versions of the GetApproximateSizes() method above.
|
||||
// The include_flags argumenbt must of type DB::SizeApproximationFlags
|
||||
// and can not be NONE.
|
||||
virtual void GetApproximateSizes(ColumnFamilyHandle* column_family,
|
||||
const Range* ranges, int n, uint64_t* sizes,
|
||||
uint8_t include_flags = INCLUDE_FILES) {
|
||||
virtual Status GetApproximateSizes(ColumnFamilyHandle* column_family,
|
||||
const Range* ranges, int n,
|
||||
uint64_t* sizes,
|
||||
uint8_t include_flags = INCLUDE_FILES) {
|
||||
SizeApproximationOptions options;
|
||||
options.include_memtabtles =
|
||||
(include_flags & SizeApproximationFlags::INCLUDE_MEMTABLES) != 0;
|
||||
options.include_files =
|
||||
(include_flags & SizeApproximationFlags::INCLUDE_FILES) != 0;
|
||||
Status s = GetApproximateSizes(options, column_family, ranges, n, sizes);
|
||||
s.PermitUncheckedError();
|
||||
return GetApproximateSizes(options, column_family, ranges, n, sizes);
|
||||
}
|
||||
virtual void GetApproximateSizes(const Range* ranges, int n, uint64_t* sizes,
|
||||
uint8_t include_flags = INCLUDE_FILES) {
|
||||
GetApproximateSizes(DefaultColumnFamily(), ranges, n, sizes, include_flags);
|
||||
virtual Status GetApproximateSizes(const Range* ranges, int n,
|
||||
uint64_t* sizes,
|
||||
uint8_t include_flags = INCLUDE_FILES) {
|
||||
return GetApproximateSizes(DefaultColumnFamily(), ranges, n, sizes,
|
||||
include_flags);
|
||||
}
|
||||
|
||||
// The method is similar to GetApproximateSizes, except it
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
// Windows API macro interference
|
||||
#undef DeleteFile
|
||||
#undef GetCurrentTime
|
||||
#undef LoadLibrary
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
@@ -282,7 +283,8 @@ class Env {
|
||||
virtual Status FileExists(const std::string& fname) = 0;
|
||||
|
||||
// Store in *result the names of the children of the specified directory.
|
||||
// The names are relative to "dir".
|
||||
// The names are relative to "dir", and shall never include the
|
||||
// names `.` or `..`.
|
||||
// Original contents of *results are dropped.
|
||||
// Returns OK if "dir" exists and "*result" contains its children.
|
||||
// NotFound if "dir" does not exist, the calling process does not have
|
||||
@@ -295,7 +297,8 @@ class Env {
|
||||
// In case the implementation lists the directory prior to iterating the files
|
||||
// and files are concurrently deleted, the deleted files will be omitted from
|
||||
// result.
|
||||
// The name attributes are relative to "dir".
|
||||
// The name attributes are relative to "dir", and shall never include the
|
||||
// names `.` or `..`.
|
||||
// Original contents of *results are dropped.
|
||||
// Returns OK if "dir" exists and "*result" contains its children.
|
||||
// NotFound if "dir" does not exist, the calling process does not have
|
||||
@@ -1663,6 +1666,6 @@ Env* NewTimedEnv(Env* base_env);
|
||||
Status NewEnvLogger(const std::string& fname, Env* env,
|
||||
std::shared_ptr<Logger>* result);
|
||||
|
||||
std::unique_ptr<Env> NewCompositeEnv(std::shared_ptr<FileSystem> fs);
|
||||
std::unique_ptr<Env> NewCompositeEnv(const std::shared_ptr<FileSystem>& fs);
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
@@ -76,7 +76,7 @@ class FileChecksumGenFactory {
|
||||
};
|
||||
|
||||
// FileChecksumList stores the checksum information of a list of files (e.g.,
|
||||
// SST files). The FileChecksumLIst can be used to store the checksum
|
||||
// SST files). The FileChecksumList can be used to store the checksum
|
||||
// information of all SST file getting from the MANIFEST, which are
|
||||
// the checksum information of all valid SST file of a DB instance. It can
|
||||
// also be used to store the checksum information of a list of SST files to
|
||||
|
||||
@@ -366,6 +366,10 @@ class FileSystem {
|
||||
return IOStatus::OK();
|
||||
}
|
||||
|
||||
// This seems to clash with a macro on Windows, so #undef it here
|
||||
#ifdef DeleteFile
|
||||
#undef DeleteFile
|
||||
#endif
|
||||
// Delete the named file.
|
||||
virtual IOStatus DeleteFile(const std::string& fname,
|
||||
const IOOptions& options,
|
||||
@@ -1048,7 +1052,8 @@ class FSDirectory {
|
||||
class FileSystemWrapper : public FileSystem {
|
||||
public:
|
||||
// Initialize an EnvWrapper that delegates all calls to *t
|
||||
explicit FileSystemWrapper(std::shared_ptr<FileSystem> t) : target_(t) {}
|
||||
explicit FileSystemWrapper(const std::shared_ptr<FileSystem>& t)
|
||||
: target_(t) {}
|
||||
~FileSystemWrapper() override {}
|
||||
|
||||
const char* Name() const override { return target_->Name(); }
|
||||
|
||||
@@ -88,6 +88,8 @@ class LDBCommand {
|
||||
|
||||
virtual void OverrideBaseOptions();
|
||||
|
||||
virtual void OverrideBaseCFOptions(ColumnFamilyOptions* cf_opts);
|
||||
|
||||
virtual void SetDBOptions(Options options) { options_ = options; }
|
||||
|
||||
virtual void SetColumnFamilies(
|
||||
|
||||
@@ -51,6 +51,8 @@ struct OptimisticTransactionDBOptions {
|
||||
uint32_t occ_lock_buckets = (1 << 20);
|
||||
};
|
||||
|
||||
// Range deletions (including those in `WriteBatch`es passed to `Write()`) are
|
||||
// incompatible with `OptimisticTransactionDB` and will return a non-OK `Status`
|
||||
class OptimisticTransactionDB : public StackableDB {
|
||||
public:
|
||||
// Open an OptimisticTransactionDB similar to DB::Open().
|
||||
|
||||
@@ -344,6 +344,17 @@ class TransactionDB : public StackableDB {
|
||||
// falls back to the un-optimized version of ::Write
|
||||
return Write(opts, updates);
|
||||
}
|
||||
// Transactional `DeleteRange()` is not yet supported.
|
||||
// However, users who know their deleted range does not conflict with
|
||||
// anything can still use it via the `Write()` API. In all cases, the
|
||||
// `Write()` overload specifying `TransactionDBWriteOptimizations` must be
|
||||
// used and `skip_concurrency_control` must be set. When using either
|
||||
// WRITE_PREPARED or WRITE_UNPREPARED , `skip_duplicate_key_check` must
|
||||
// additionally be set.
|
||||
virtual Status DeleteRange(const WriteOptions&, ColumnFamilyHandle*,
|
||||
const Slice&, const Slice&) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
// Open a TransactionDB similar to DB::Open().
|
||||
// Internally call PrepareWrap() and WrapDB()
|
||||
// If the return status is not ok, then dbptr is set to nullptr.
|
||||
|
||||
@@ -40,12 +40,13 @@ enum WriteType {
|
||||
kDeleteRangeRecord,
|
||||
kLogDataRecord,
|
||||
kXIDRecord,
|
||||
kUnknownRecord,
|
||||
};
|
||||
|
||||
// an entry for Put, Merge, Delete, or SingleDelete entry for write batches.
|
||||
// Used in WBWIIterator.
|
||||
struct WriteEntry {
|
||||
WriteType type;
|
||||
WriteType type = kUnknownRecord;
|
||||
Slice key;
|
||||
Slice value;
|
||||
};
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#pragma once
|
||||
|
||||
#define ROCKSDB_MAJOR 6
|
||||
#define ROCKSDB_MINOR 16
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_MINOR 17
|
||||
#define ROCKSDB_PATCH 3
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
@@ -43,6 +43,9 @@ class WriteBufferManager {
|
||||
size_t mutable_memtable_memory_usage() const {
|
||||
return memory_active_.load(std::memory_order_relaxed);
|
||||
}
|
||||
size_t dummy_entries_in_cache_usage() const {
|
||||
return dummy_size_.load(std::memory_order_relaxed);
|
||||
}
|
||||
size_t buffer_size() const { return buffer_size_; }
|
||||
|
||||
// Should only be called from write thread
|
||||
@@ -93,6 +96,7 @@ class WriteBufferManager {
|
||||
std::atomic<size_t> memory_used_;
|
||||
// Memory that hasn't been scheduled to free.
|
||||
std::atomic<size_t> memory_active_;
|
||||
std::atomic<size_t> dummy_size_;
|
||||
struct CacheRep;
|
||||
std::unique_ptr<CacheRep> cache_rep_;
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ set(JNI_NATIVE_SOURCES
|
||||
rocksjni/table.cc
|
||||
rocksjni/table_filter.cc
|
||||
rocksjni/table_filter_jnicallback.cc
|
||||
rocksjni/testable_event_listener.cc
|
||||
rocksjni/thread_status.cc
|
||||
rocksjni/trace_writer.cc
|
||||
rocksjni/trace_writer_jnicallback.cc
|
||||
@@ -283,6 +284,7 @@ set(JAVA_TEST_CLASSES
|
||||
src/test/java/org/rocksdb/WriteBatchTest.java
|
||||
src/test/java/org/rocksdb/util/CapturingWriteBatchHandler.java
|
||||
src/test/java/org/rocksdb/util/WriteBatchGetter.java
|
||||
src/test/java/org/rocksdb/test/TestableEventListener.java
|
||||
)
|
||||
|
||||
include(FindJava)
|
||||
@@ -434,6 +436,8 @@ if(${CMAKE_VERSION} VERSION_LESS "3.11.4" OR (${Java_VERSION_MINOR} STREQUAL "7"
|
||||
org.rocksdb.CompactRangeOptions
|
||||
org.rocksdb.ComparatorOptions
|
||||
org.rocksdb.CompressionOptions
|
||||
org.rocksdb.ConcurrentTaskLimiterImpl
|
||||
org.rocksdb.ConfigOptions
|
||||
org.rocksdb.DBOptions
|
||||
org.rocksdb.DirectSlice
|
||||
org.rocksdb.Env
|
||||
@@ -502,6 +506,7 @@ if(${CMAKE_VERSION} VERSION_LESS "3.11.4" OR (${Java_VERSION_MINOR} STREQUAL "7"
|
||||
org.rocksdb.WriteBatchTest
|
||||
org.rocksdb.WriteBatchTestInternalHelper
|
||||
org.rocksdb.WriteBufferManager
|
||||
org.rocksdb.test.TestableEventListener
|
||||
)
|
||||
|
||||
create_javah(
|
||||
|
||||
+38
-11
@@ -101,10 +101,7 @@ ROCKSDB_PATCH = $(shell egrep "ROCKSDB_PATCH.[0-9]" ../include/rocksdb/version.h
|
||||
|
||||
NATIVE_INCLUDE = ./include
|
||||
ARCH := $(shell getconf LONG_BIT)
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH).jar
|
||||
ifeq ($(PLATFORM), OS_MACOSX)
|
||||
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-osx.jar
|
||||
endif
|
||||
SHA256_CMD ?= sha256sum
|
||||
|
||||
JAVA_TESTS = \
|
||||
org.rocksdb.BackupableDBOptionsTest\
|
||||
@@ -209,19 +206,24 @@ SAMPLES_OUTPUT = samples/target
|
||||
SAMPLES_MAIN_CLASSES = $(SAMPLES_OUTPUT)/classes
|
||||
|
||||
JAVA_TEST_LIBDIR = test-libs
|
||||
JAVA_JUNIT_VER = 4.12
|
||||
JAVA_JUNIT_VER = 4.13.1
|
||||
JAVA_JUNIT_SHA256 = c30719db974d6452793fe191b3638a5777005485bae145924044530ffa5f6122
|
||||
JAVA_JUNIT_JAR = junit-$(JAVA_JUNIT_VER).jar
|
||||
JAVA_JUNIT_JAR_PATH = $(JAVA_TEST_LIBDIR)/$(JAVA_JUNIT_JAR)
|
||||
JAVA_HAMCREST_VER = 1.3
|
||||
JAVA_HAMCREST_JAR = hamcrest-core-$(JAVA_HAMCREST_VER).jar
|
||||
JAVA_HAMCREST_VER = 2.2
|
||||
JAVA_HAMCREST_SHA256 = 5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1
|
||||
JAVA_HAMCREST_JAR = hamcrest-$(JAVA_HAMCREST_VER).jar
|
||||
JAVA_HAMCREST_JAR_PATH = $(JAVA_TEST_LIBDIR)/$(JAVA_HAMCREST_JAR)
|
||||
JAVA_MOCKITO_VER = 1.10.19
|
||||
JAVA_MOCKITO_SHA256 = d1a7a7ef14b3db5c0fc3e0a63a81b374b510afe85add9f7984b97911f4c70605
|
||||
JAVA_MOCKITO_JAR = mockito-all-$(JAVA_MOCKITO_VER).jar
|
||||
JAVA_MOCKITO_JAR_PATH = $(JAVA_TEST_LIBDIR)/$(JAVA_MOCKITO_JAR)
|
||||
JAVA_CGLIB_VER = 2.2.2
|
||||
JAVA_CGLIB_VER = 3.3.0
|
||||
JAVA_CGLIB_SHA256 = 9fe0c26d7464140ccdfe019ac687be1fb906122b508ab54beb810db0f09a9212
|
||||
JAVA_CGLIB_JAR = cglib-$(JAVA_CGLIB_VER).jar
|
||||
JAVA_CGLIB_JAR_PATH = $(JAVA_TEST_LIBDIR)/$(JAVA_CGLIB_JAR)
|
||||
JAVA_ASSERTJ_VER = 1.7.1
|
||||
JAVA_ASSERTJ_VER = 2.9.0
|
||||
JAVA_ASSERTJ_SHA256 = 5e88ea3ecbe3c48aa1346fec76c84979fa9c8d22499f11479011691230e8babf
|
||||
JAVA_ASSERTJ_JAR = assertj-core-$(JAVA_ASSERTJ_VER).jar
|
||||
JAVA_ASSERTJ_JAR_PATH = $(JAVA_TEST_LIBDIR)/$(JAVA_ASSERTJ_JAR)
|
||||
JAVA_TESTCLASSPATH = $(JAVA_JUNIT_JAR_PATH):$(JAVA_HAMCREST_JAR_PATH):$(JAVA_MOCKITO_JAR_PATH):$(JAVA_CGLIB_JAR_PATH):$(JAVA_ASSERTJ_JAR_PATH)
|
||||
@@ -316,13 +318,23 @@ ifneq (,$(wildcard $(MVN_LOCAL)/junit/junit/$(JAVA_JUNIT_VER)/$(JAVA_JUNIT_JAR))
|
||||
cp -v $(MVN_LOCAL)/junit/junit/$(JAVA_JUNIT_VER)/$(JAVA_JUNIT_JAR) $(JAVA_TEST_LIBDIR)
|
||||
else
|
||||
curl --fail --insecure --output $(JAVA_JUNIT_JAR_PATH) --location $(DEPS_URL)/$(JAVA_JUNIT_JAR)
|
||||
JAVA_JUNIT_SHA256_ACTUAL=`$(SHA256_CMD) $(JAVA_JUNIT_JAR_PATH) | cut -d ' ' -f 1`; \
|
||||
if [ "$(JAVA_JUNIT_SHA256)" != "$$JAVA_JUNIT_SHA256_ACTUAL" ]; then \
|
||||
echo $(JAVA_JUNIT_JAR_PATH) checksum mismatch, expected=\"$(JAVA_JUNIT_SHA256)\" actual=\"$$JAVA_JUNIT_SHA256_ACTUAL\"; \
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
$(JAVA_HAMCREST_JAR_PATH): $(JAVA_TEST_LIBDIR)
|
||||
ifneq (,$(wildcard $(MVN_LOCAL)/org/hamcrest/hamcrest-core/$(JAVA_HAMCREST_VER)/$(JAVA_HAMCREST_JAR)))
|
||||
cp -v $(MVN_LOCAL)/org/hamcrest/hamcrest-core/$(JAVA_HAMCREST_VER)/$(JAVA_HAMCREST_JAR) $(JAVA_TEST_LIBDIR)
|
||||
ifneq (,$(wildcard $(MVN_LOCAL)/org/hamcrest/hamcrest/$(JAVA_HAMCREST_VER)/$(JAVA_HAMCREST_JAR)))
|
||||
cp -v $(MVN_LOCAL)/org/hamcrest/hamcrest/$(JAVA_HAMCREST_VER)/$(JAVA_HAMCREST_JAR) $(JAVA_TEST_LIBDIR)
|
||||
else
|
||||
curl --fail --insecure --output $(JAVA_HAMCREST_JAR_PATH) --location $(DEPS_URL)/$(JAVA_HAMCREST_JAR)
|
||||
JAVA_HAMCREST_SHA256_ACTUAL=`$(SHA256_CMD) $(JAVA_HAMCREST_JAR_PATH) | cut -d ' ' -f 1`; \
|
||||
if [ "$(JAVA_HAMCREST_SHA256)" != "$$JAVA_HAMCREST_SHA256_ACTUAL" ]; then \
|
||||
echo $(JAVA_HAMCREST_JAR_PATH) checksum mismatch, expected=\"$(JAVA_HAMCREST_SHA256)\" actual=\"$$JAVA_HAMCREST_SHA256_ACTUAL\"; \
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
$(JAVA_MOCKITO_JAR_PATH): $(JAVA_TEST_LIBDIR)
|
||||
@@ -330,6 +342,11 @@ ifneq (,$(wildcard $(MVN_LOCAL)/org/mockito/mockito-all/$(JAVA_MOCKITO_VER)/$(JA
|
||||
cp -v $(MVN_LOCAL)/org/mockito/mockito-all/$(JAVA_MOCKITO_VER)/$(JAVA_MOCKITO_JAR) $(JAVA_TEST_LIBDIR)
|
||||
else
|
||||
curl --fail --insecure --output "$(JAVA_MOCKITO_JAR_PATH)" --location $(DEPS_URL)/$(JAVA_MOCKITO_JAR)
|
||||
JAVA_MOCKITO_SHA256_ACTUAL=`$(SHA256_CMD) $(JAVA_MOCKITO_JAR_PATH) | cut -d ' ' -f 1`; \
|
||||
if [ "$(JAVA_MOCKITO_SHA256)" != "$$JAVA_MOCKITO_SHA256_ACTUAL" ]; then \
|
||||
echo $(JAVA_MOCKITO_JAR_PATH) checksum mismatch, expected=\"$(JAVA_MOCKITO_SHA256)\" actual=\"$$JAVA_MOCKITO_SHA256_ACTUAL\"; \
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
$(JAVA_CGLIB_JAR_PATH): $(JAVA_TEST_LIBDIR)
|
||||
@@ -337,6 +354,11 @@ ifneq (,$(wildcard $(MVN_LOCAL)/cglib/cglib/$(JAVA_CGLIB_VER)/$(JAVA_CGLIB_JAR))
|
||||
cp -v $(MVN_LOCAL)/cglib/cglib/$(JAVA_CGLIB_VER)/$(JAVA_CGLIB_JAR) $(JAVA_TEST_LIBDIR)
|
||||
else
|
||||
curl --fail --insecure --output "$(JAVA_CGLIB_JAR_PATH)" --location $(DEPS_URL)/$(JAVA_CGLIB_JAR)
|
||||
JAVA_CGLIB_SHA256_ACTUAL=`$(SHA256_CMD) $(JAVA_CGLIB_JAR_PATH) | cut -d ' ' -f 1`; \
|
||||
if [ "$(JAVA_CGLIB_SHA256)" != "$$JAVA_CGLIB_SHA256_ACTUAL" ]; then \
|
||||
echo $(JAVA_CGLIB_JAR_PATH) checksum mismatch, expected=\"$(JAVA_CGLIB_SHA256)\" actual=\"$$JAVA_CGLIB_SHA256_ACTUAL\"; \
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
$(JAVA_ASSERTJ_JAR_PATH): $(JAVA_TEST_LIBDIR)
|
||||
@@ -344,6 +366,11 @@ ifneq (,$(wildcard $(MVN_LOCAL)/org/assertj/assertj-core/$(JAVA_ASSERTJ_VER)/$(J
|
||||
cp -v $(MVN_LOCAL)/org/assertj/assertj-core/$(JAVA_ASSERTJ_VER)/$(JAVA_ASSERTJ_JAR) $(JAVA_TEST_LIBDIR)
|
||||
else
|
||||
curl --fail --insecure --output "$(JAVA_ASSERTJ_JAR_PATH)" --location $(DEPS_URL)/$(JAVA_ASSERTJ_JAR)
|
||||
JAVA_ASSERTJ_SHA256_ACTUAL=`$(SHA256_CMD) $(JAVA_ASSERTJ_JAR_PATH) | cut -d ' ' -f 1`; \
|
||||
if [ "$(JAVA_ASSERTJ_SHA256)" != "$$JAVA_ASSERTJ_SHA256_ACTUAL" ]; then \
|
||||
echo $(JAVA_ASSERTJ_JAR_PATH) checksum mismatch, expected=\"$(JAVA_ASSERTJ_SHA256)\" actual=\"$$JAVA_ASSERTJ_SHA256_ACTUAL\"; \
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
resolve_test_deps: $(JAVA_JUNIT_JAR_PATH) $(JAVA_HAMCREST_JAR_PATH) $(JAVA_MOCKITO_JAR_PATH) $(JAVA_CGLIB_JAR_PATH) $(JAVA_ASSERTJ_JAR_PATH)
|
||||
|
||||
+14
-2
@@ -147,13 +147,25 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<version>4.13.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<version>2.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>1.7.1</version>
|
||||
<version>2.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
jlong Java_org_rocksdb_ConcurrentTaskLimiterImpl_newConcurrentTaskLimiterImpl0(
|
||||
JNIEnv* env, jclass, jstring jname, jint limit) {
|
||||
jboolean has_exception;
|
||||
jboolean has_exception = JNI_FALSE;
|
||||
std::string name =
|
||||
ROCKSDB_NAMESPACE::JniUtil::copyStdString(env, jname, &has_exception);
|
||||
if (JNI_TRUE == has_exception) {
|
||||
|
||||
@@ -945,6 +945,7 @@ rocksdb_convert_cf_paths_from_java_helper(JNIEnv* env, jobjectArray path_array,
|
||||
jlong* size_array_ptr = env->GetLongArrayElements(size_array, nullptr);
|
||||
if (nullptr == size_array_ptr) {
|
||||
// exception thrown: OutOfMemoryError
|
||||
*has_exception = JNI_TRUE;
|
||||
return {};
|
||||
}
|
||||
std::vector<ROCKSDB_NAMESPACE::DbPath> cf_paths;
|
||||
@@ -977,7 +978,7 @@ void Java_org_rocksdb_Options_setCfPaths(JNIEnv* env, jclass, jlong jhandle,
|
||||
jobjectArray path_array,
|
||||
jlongArray size_array) {
|
||||
auto* options = reinterpret_cast<ROCKSDB_NAMESPACE::Options*>(jhandle);
|
||||
jboolean has_exception;
|
||||
jboolean has_exception = JNI_FALSE;
|
||||
std::vector<ROCKSDB_NAMESPACE::DbPath> cf_paths =
|
||||
rocksdb_convert_cf_paths_from_java_helper(env, path_array, size_array,
|
||||
&has_exception);
|
||||
@@ -4142,7 +4143,7 @@ void Java_org_rocksdb_ColumnFamilyOptions_setCfPaths(JNIEnv* env, jclass,
|
||||
jlongArray size_array) {
|
||||
auto* options =
|
||||
reinterpret_cast<ROCKSDB_NAMESPACE::ColumnFamilyOptions*>(jhandle);
|
||||
jboolean has_exception;
|
||||
jboolean has_exception = JNI_FALSE;
|
||||
std::vector<ROCKSDB_NAMESPACE::DbPath> cf_paths =
|
||||
rocksdb_convert_cf_paths_from_java_helper(env, path_array, size_array,
|
||||
&has_exception);
|
||||
|
||||
@@ -228,6 +228,17 @@ void Java_org_rocksdb_Slice_removePrefix0(JNIEnv* /*env*/, jobject /*jobj*/,
|
||||
slice->remove_prefix(length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_DirectSlice
|
||||
* Method: setLength0
|
||||
* Signature: (JI)V
|
||||
*/
|
||||
void Java_org_rocksdb_DirectSlice_setLength0(JNIEnv* /*env*/, jobject /*jobj*/,
|
||||
jlong handle, jint length) {
|
||||
auto* slice = reinterpret_cast<rocksdb::Slice*>(handle);
|
||||
slice->size_ = length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_rocksdb_Slice
|
||||
* Method: disposeInternalBuf
|
||||
|
||||
@@ -115,7 +115,9 @@ public class ColumnFamilyHandle extends RocksObject {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
try {
|
||||
return Objects.hash(getName(), getID(), rocksDB_.nativeHandle_);
|
||||
int result = Objects.hash(getID(), rocksDB_.nativeHandle_);
|
||||
result = 31 * result + Arrays.hashCode(getName());
|
||||
return result;
|
||||
} catch (RocksDBException e) {
|
||||
throw new RuntimeException("Cannot calculate hash code of column family handle", e);
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@ public class DirectSlice extends AbstractSlice<ByteBuffer> {
|
||||
this.internalBufferOffset += n;
|
||||
}
|
||||
|
||||
public void setLength(final int n) {
|
||||
setLength0(getNativeHandle(), n);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disposeInternal() {
|
||||
final long nativeHandle = getNativeHandle();
|
||||
@@ -127,6 +131,7 @@ public class DirectSlice extends AbstractSlice<ByteBuffer> {
|
||||
private native void clear0(long handle, boolean internalBuffer,
|
||||
long internalBufferOffset);
|
||||
private native void removePrefix0(long handle, int length);
|
||||
private native void setLength0(long handle, int length);
|
||||
private native void disposeInternalBuf(final long handle,
|
||||
long internalBufferOffset);
|
||||
}
|
||||
@@ -440,13 +440,12 @@ public class ReadOptions extends RocksObject {
|
||||
* @param iterateLowerBound Slice representing the upper bound
|
||||
* @return the reference to the current ReadOptions.
|
||||
*/
|
||||
public ReadOptions setIterateLowerBound(final Slice iterateLowerBound) {
|
||||
public ReadOptions setIterateLowerBound(final AbstractSlice<?> iterateLowerBound) {
|
||||
assert(isOwningHandle());
|
||||
if (iterateLowerBound != null) {
|
||||
// Hold onto a reference so it doesn't get garbage collected out from under us.
|
||||
iterateLowerBoundSlice_ = iterateLowerBound;
|
||||
setIterateLowerBound(nativeHandle_, iterateLowerBoundSlice_.getNativeHandle());
|
||||
}
|
||||
setIterateLowerBound(
|
||||
nativeHandle_, iterateLowerBound == null ? 0 : iterateLowerBound.getNativeHandle());
|
||||
// Hold onto a reference so it doesn't get garbage collected out from under us.
|
||||
iterateLowerBoundSlice_ = iterateLowerBound;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -485,13 +484,12 @@ public class ReadOptions extends RocksObject {
|
||||
* @param iterateUpperBound Slice representing the upper bound
|
||||
* @return the reference to the current ReadOptions.
|
||||
*/
|
||||
public ReadOptions setIterateUpperBound(final Slice iterateUpperBound) {
|
||||
public ReadOptions setIterateUpperBound(final AbstractSlice<?> iterateUpperBound) {
|
||||
assert(isOwningHandle());
|
||||
if (iterateUpperBound != null) {
|
||||
// Hold onto a reference so it doesn't get garbage collected out from under us.
|
||||
iterateUpperBoundSlice_ = iterateUpperBound;
|
||||
setIterateUpperBound(nativeHandle_, iterateUpperBoundSlice_.getNativeHandle());
|
||||
}
|
||||
setIterateUpperBound(
|
||||
nativeHandle_, iterateUpperBound == null ? 0 : iterateUpperBound.getNativeHandle());
|
||||
// Hold onto a reference so it doesn't get garbage collected out from under us.
|
||||
iterateUpperBoundSlice_ = iterateUpperBound;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -570,8 +568,8 @@ public class ReadOptions extends RocksObject {
|
||||
// freely leave scope without us losing the Java Slice object, which during
|
||||
// close() would also reap its associated rocksdb::Slice native object since
|
||||
// it's possibly (likely) to be an owning handle.
|
||||
private Slice iterateLowerBoundSlice_;
|
||||
private Slice iterateUpperBoundSlice_;
|
||||
private AbstractSlice<?> iterateLowerBoundSlice_;
|
||||
private AbstractSlice<?> iterateUpperBoundSlice_;
|
||||
|
||||
private native static long newReadOptions();
|
||||
private native static long newReadOptions(final boolean verifyChecksums,
|
||||
|
||||
@@ -15,6 +15,9 @@ import java.util.Comparator;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class NativeComparatorWrapperTest {
|
||||
static {
|
||||
RocksDB.loadLibrary();
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder dbFolder = new TemporaryFolder();
|
||||
|
||||
@@ -159,6 +159,8 @@ public class ReadOptionsTest {
|
||||
Slice upperBound = buildRandomSlice();
|
||||
opt.setIterateUpperBound(upperBound);
|
||||
assertThat(Arrays.equals(upperBound.data(), opt.iterateUpperBound().data())).isTrue();
|
||||
opt.setIterateUpperBound(null);
|
||||
assertThat(opt.iterateUpperBound()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +177,8 @@ public class ReadOptionsTest {
|
||||
Slice lowerBound = buildRandomSlice();
|
||||
opt.setIterateLowerBound(lowerBound);
|
||||
assertThat(Arrays.equals(lowerBound.data(), opt.iterateLowerBound().data())).isTrue();
|
||||
opt.setIterateLowerBound(null);
|
||||
assertThat(opt.iterateLowerBound()).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -156,8 +156,10 @@ public class CapturingWriteBatchHandler extends WriteBatch.Handler {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
return Objects.hash(action, columnFamilyId, key, value);
|
||||
int result = Objects.hash(action, columnFamilyId);
|
||||
result = 31 * result + Arrays.hashCode(key);
|
||||
result = 31 * result + Arrays.hashCode(value);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ WriteBufferManager::WriteBufferManager(size_t _buffer_size,
|
||||
mutable_limit_(buffer_size_ * 7 / 8),
|
||||
memory_used_(0),
|
||||
memory_active_(0),
|
||||
dummy_size_(0),
|
||||
cache_rep_(nullptr) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (cache) {
|
||||
@@ -104,6 +105,7 @@ void WriteBufferManager::ReserveMemWithCache(size_t mem) {
|
||||
// it in the future.
|
||||
cache_rep_->dummy_handles_.push_back(handle);
|
||||
cache_rep_->cache_allocated_size_ += kSizeDummyEntry;
|
||||
dummy_size_.fetch_add(kSizeDummyEntry, std::memory_order_relaxed);
|
||||
}
|
||||
#else
|
||||
(void)mem;
|
||||
@@ -137,6 +139,7 @@ void WriteBufferManager::FreeMemWithCache(size_t mem) {
|
||||
}
|
||||
cache_rep_->dummy_handles_.pop_back();
|
||||
cache_rep_->cache_allocated_size_ -= kSizeDummyEntry;
|
||||
dummy_size_.fetch_sub(kSizeDummyEntry, std::memory_order_relaxed);
|
||||
}
|
||||
#else
|
||||
(void)mem;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "test_util/testharness.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
const size_t kSizeDummyEntry = 256 * 1024;
|
||||
class WriteBufferManagerTest : public testing::Test {};
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
@@ -65,28 +65,35 @@ TEST_F(WriteBufferManagerTest, CacheCost) {
|
||||
wbf->ReserveMem(333 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 2 * 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 2 * 256 * 1024 + 10000);
|
||||
// 2 dummy entries are added for size 333 kb.
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 2 * kSizeDummyEntry);
|
||||
|
||||
// Allocate another 512KB
|
||||
wbf->ReserveMem(512 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 4 * 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 4 * 256 * 1024 + 10000);
|
||||
// 2 more dummy entries are added for size 512.
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 4 * kSizeDummyEntry);
|
||||
|
||||
// Allocate another 10MB
|
||||
wbf->ReserveMem(10 * 1024 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 11 * 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 11 * 1024 * 1024 + 10000);
|
||||
// 40 more entries are added for size 10 * 1024 * 1024.
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 44 * kSizeDummyEntry);
|
||||
|
||||
// Free 1MB will not cause any change in cache cost
|
||||
wbf->FreeMem(1024 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 11 * 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 11 * 1024 * 1024 + 10000);
|
||||
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 44 * kSizeDummyEntry);
|
||||
ASSERT_FALSE(wbf->ShouldFlush());
|
||||
|
||||
// Allocate another 41MB
|
||||
wbf->ReserveMem(41 * 1024 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 204 * kSizeDummyEntry);
|
||||
ASSERT_TRUE(wbf->ShouldFlush());
|
||||
|
||||
ASSERT_TRUE(wbf->ShouldFlush());
|
||||
@@ -94,7 +101,7 @@ TEST_F(WriteBufferManagerTest, CacheCost) {
|
||||
wbf->ScheduleFreeMem(20 * 1024 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 + 10000);
|
||||
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 204 * kSizeDummyEntry);
|
||||
// Still need flush as the hard limit hits
|
||||
ASSERT_TRUE(wbf->ShouldFlush());
|
||||
|
||||
@@ -102,6 +109,7 @@ TEST_F(WriteBufferManagerTest, CacheCost) {
|
||||
wbf->FreeMem(20 * 1024 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 256 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 203 * kSizeDummyEntry);
|
||||
|
||||
ASSERT_FALSE(wbf->ShouldFlush());
|
||||
|
||||
@@ -109,19 +117,23 @@ TEST_F(WriteBufferManagerTest, CacheCost) {
|
||||
wbf->FreeMem(16 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 2 * 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 2 * 256 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 202 * kSizeDummyEntry);
|
||||
|
||||
wbf->FreeMem(16 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 201 * kSizeDummyEntry);
|
||||
|
||||
// Reserve 512KB will not cause any change in cache cost
|
||||
wbf->ReserveMem(512 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 3 * 256 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 201 * kSizeDummyEntry);
|
||||
|
||||
wbf->FreeMem(16 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 4 * 256 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 51 * 1024 * 1024 - 4 * 256 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 200 * kSizeDummyEntry);
|
||||
|
||||
// Destory write buffer manger should free everything
|
||||
wbf.reset();
|
||||
@@ -137,6 +149,7 @@ TEST_F(WriteBufferManagerTest, NoCapCacheCost) {
|
||||
wbf->ReserveMem(10 * 1024 * 1024);
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 10 * 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 10 * 1024 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 40 * kSizeDummyEntry);
|
||||
ASSERT_FALSE(wbf->ShouldFlush());
|
||||
|
||||
wbf->FreeMem(9 * 1024 * 1024);
|
||||
@@ -145,6 +158,7 @@ TEST_F(WriteBufferManagerTest, NoCapCacheCost) {
|
||||
}
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 1024 * 1024 + 10000);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 4 * kSizeDummyEntry);
|
||||
}
|
||||
|
||||
TEST_F(WriteBufferManagerTest, CacheFull) {
|
||||
@@ -156,16 +170,20 @@ TEST_F(WriteBufferManagerTest, CacheFull) {
|
||||
std::shared_ptr<Cache> cache = NewLRUCache(lo);
|
||||
std::unique_ptr<WriteBufferManager> wbf(new WriteBufferManager(0, cache));
|
||||
wbf->ReserveMem(10 * 1024 * 1024);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 40 * kSizeDummyEntry);
|
||||
size_t prev_pinned = cache->GetPinnedUsage();
|
||||
ASSERT_GE(prev_pinned, 10 * 1024 * 1024);
|
||||
|
||||
// Some insert will fail
|
||||
wbf->ReserveMem(10 * 1024 * 1024);
|
||||
ASSERT_LE(cache->GetPinnedUsage(), 12 * 1024 * 1024);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 80 * kSizeDummyEntry);
|
||||
|
||||
// Increase capacity so next insert will succeed
|
||||
cache->SetCapacity(30 * 1024 * 1024);
|
||||
wbf->ReserveMem(10 * 1024 * 1024);
|
||||
ASSERT_GT(cache->GetPinnedUsage(), 20 * 1024 * 1024);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 120 * kSizeDummyEntry);
|
||||
|
||||
// Gradually release 20 MB
|
||||
for (int i = 0; i < 40; i++) {
|
||||
@@ -173,6 +191,7 @@ TEST_F(WriteBufferManagerTest, CacheFull) {
|
||||
}
|
||||
ASSERT_GE(cache->GetPinnedUsage(), 10 * 1024 * 1024);
|
||||
ASSERT_LT(cache->GetPinnedUsage(), 20 * 1024 * 1024);
|
||||
ASSERT_EQ(wbf->dummy_entries_in_cache_usage(), 95 * kSizeDummyEntry);
|
||||
}
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
#include "monitoring/histogram.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "monitoring/histogram.h"
|
||||
#include "monitoring/histogram_windowing.h"
|
||||
#include "test_util/mock_time_env.h"
|
||||
#include "test_util/testharness.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -16,16 +19,21 @@ class HistogramTest : public testing::Test {};
|
||||
namespace {
|
||||
const double kIota = 0.1;
|
||||
const HistogramBucketMapper bucketMapper;
|
||||
Env* env = Env::Default();
|
||||
MockTimeEnv* env = new MockTimeEnv(Env::Default());
|
||||
}
|
||||
|
||||
void PopulateHistogram(Histogram& histogram,
|
||||
uint64_t low, uint64_t high, uint64_t loop = 1) {
|
||||
Random rnd(test::RandomSeed());
|
||||
for (; loop > 0; loop--) {
|
||||
for (uint64_t i = low; i <= high; i++) {
|
||||
histogram.Add(i);
|
||||
// sleep a random microseconds [0-10)
|
||||
env->MockSleepForMicroseconds(rnd.Uniform(10));
|
||||
}
|
||||
}
|
||||
// make sure each data population at least take some time
|
||||
env->MockSleepForMicroseconds(1);
|
||||
}
|
||||
|
||||
void BasicOperation(Histogram& histogram) {
|
||||
@@ -131,23 +139,23 @@ TEST_F(HistogramTest, HistogramWindowingExpire) {
|
||||
|
||||
HistogramWindowingImpl
|
||||
histogramWindowing(num_windows, micros_per_window, min_num_per_window);
|
||||
|
||||
histogramWindowing.TEST_UpdateEnv(env);
|
||||
PopulateHistogram(histogramWindowing, 1, 1, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 100);
|
||||
ASSERT_EQ(histogramWindowing.min(), 1);
|
||||
ASSERT_EQ(histogramWindowing.max(), 1);
|
||||
ASSERT_EQ(histogramWindowing.Average(), 1);
|
||||
|
||||
PopulateHistogram(histogramWindowing, 2, 2, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 200);
|
||||
ASSERT_EQ(histogramWindowing.min(), 1);
|
||||
ASSERT_EQ(histogramWindowing.max(), 2);
|
||||
ASSERT_EQ(histogramWindowing.Average(), 1.5);
|
||||
|
||||
PopulateHistogram(histogramWindowing, 3, 3, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 300);
|
||||
ASSERT_EQ(histogramWindowing.min(), 1);
|
||||
ASSERT_EQ(histogramWindowing.max(), 3);
|
||||
@@ -155,7 +163,7 @@ TEST_F(HistogramTest, HistogramWindowingExpire) {
|
||||
|
||||
// dropping oldest window with value 1, remaining 2 ~ 4
|
||||
PopulateHistogram(histogramWindowing, 4, 4, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 300);
|
||||
ASSERT_EQ(histogramWindowing.min(), 2);
|
||||
ASSERT_EQ(histogramWindowing.max(), 4);
|
||||
@@ -163,7 +171,7 @@ TEST_F(HistogramTest, HistogramWindowingExpire) {
|
||||
|
||||
// dropping oldest window with value 2, remaining 3 ~ 5
|
||||
PopulateHistogram(histogramWindowing, 5, 5, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 300);
|
||||
ASSERT_EQ(histogramWindowing.min(), 3);
|
||||
ASSERT_EQ(histogramWindowing.max(), 5);
|
||||
@@ -179,18 +187,20 @@ TEST_F(HistogramTest, HistogramWindowingMerge) {
|
||||
histogramWindowing(num_windows, micros_per_window, min_num_per_window);
|
||||
HistogramWindowingImpl
|
||||
otherWindowing(num_windows, micros_per_window, min_num_per_window);
|
||||
histogramWindowing.TEST_UpdateEnv(env);
|
||||
otherWindowing.TEST_UpdateEnv(env);
|
||||
|
||||
PopulateHistogram(histogramWindowing, 1, 1, 100);
|
||||
PopulateHistogram(otherWindowing, 1, 1, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
|
||||
PopulateHistogram(histogramWindowing, 2, 2, 100);
|
||||
PopulateHistogram(otherWindowing, 2, 2, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
|
||||
PopulateHistogram(histogramWindowing, 3, 3, 100);
|
||||
PopulateHistogram(otherWindowing, 3, 3, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
|
||||
histogramWindowing.Merge(otherWindowing);
|
||||
ASSERT_EQ(histogramWindowing.num(), 600);
|
||||
@@ -200,14 +210,14 @@ TEST_F(HistogramTest, HistogramWindowingMerge) {
|
||||
|
||||
// dropping oldest window with value 1, remaining 2 ~ 4
|
||||
PopulateHistogram(histogramWindowing, 4, 4, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 500);
|
||||
ASSERT_EQ(histogramWindowing.min(), 2);
|
||||
ASSERT_EQ(histogramWindowing.max(), 4);
|
||||
|
||||
// dropping oldest window with value 2, remaining 3 ~ 5
|
||||
PopulateHistogram(histogramWindowing, 5, 5, 100);
|
||||
env->SleepForMicroseconds(micros_per_window);
|
||||
env->MockSleepForMicroseconds(micros_per_window);
|
||||
ASSERT_EQ(histogramWindowing.num(), 400);
|
||||
ASSERT_EQ(histogramWindowing.min(), 3);
|
||||
ASSERT_EQ(histogramWindowing.max(), 5);
|
||||
|
||||
@@ -44,7 +44,11 @@ public:
|
||||
virtual double StandardDeviation() const override;
|
||||
virtual void Data(HistogramData* const data) const override;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
void TEST_UpdateEnv(Env* env) { env_ = env; }
|
||||
#endif // NDEBUG
|
||||
|
||||
private:
|
||||
void TimerTick();
|
||||
void SwapHistoryBucket();
|
||||
inline uint64_t current_window() const {
|
||||
|
||||
+26
-30
@@ -2414,14 +2414,10 @@ TEST_F(OptionsOldApiTest, ColumnFamilyOptionsSerialization) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
class OptionsParserTest : public testing::Test {
|
||||
public:
|
||||
OptionsParserTest() {
|
||||
env_.reset(new test::StringEnv(Env::Default()));
|
||||
fs_.reset(new LegacyFileSystemWrapper(env_.get()));
|
||||
}
|
||||
OptionsParserTest() { fs_.reset(new test::StringFS(FileSystem::Default())); }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<test::StringEnv> env_;
|
||||
std::unique_ptr<LegacyFileSystemWrapper> fs_;
|
||||
std::shared_ptr<test::StringFS> fs_;
|
||||
};
|
||||
|
||||
TEST_F(OptionsParserTest, Comment) {
|
||||
@@ -2450,7 +2446,7 @@ TEST_F(OptionsParserTest, Comment) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_OK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2481,7 +2477,7 @@ TEST_F(OptionsParserTest, ExtraSpace) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_OK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2499,7 +2495,7 @@ TEST_F(OptionsParserTest, MissingDBOptions) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_NOK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2529,7 +2525,7 @@ TEST_F(OptionsParserTest, DoubleDBOptions) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_NOK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2557,7 +2553,7 @@ TEST_F(OptionsParserTest, NoDefaultCFOptions) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_NOK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2587,7 +2583,7 @@ TEST_F(OptionsParserTest, DefaultCFOptionsMustBeTheFirst) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_NOK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2616,7 +2612,7 @@ TEST_F(OptionsParserTest, DuplicateCFOptions) {
|
||||
"[CFOptions \"something_else\"]\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_NOK(
|
||||
parser.Parse(kTestFileName, fs_.get(), false, 4096 /* readahead_size */));
|
||||
@@ -2684,12 +2680,12 @@ TEST_F(OptionsParserTest, IgnoreUnknownOptions) {
|
||||
" # if a section is blank, we will use the default\n";
|
||||
|
||||
const std::string kTestFileName = "test-rocksdb-options.ini";
|
||||
auto s = env_->FileExists(kTestFileName);
|
||||
auto s = fs_->FileExists(kTestFileName, IOOptions(), nullptr);
|
||||
ASSERT_TRUE(s.ok() || s.IsNotFound());
|
||||
if (s.ok()) {
|
||||
ASSERT_OK(env_->DeleteFile(kTestFileName));
|
||||
ASSERT_OK(fs_->DeleteFile(kTestFileName, IOOptions(), nullptr));
|
||||
}
|
||||
ASSERT_OK(env_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
ASSERT_OK(fs_->WriteToNewFile(kTestFileName, options_file_content));
|
||||
RocksDBOptionsParser parser;
|
||||
ASSERT_NOK(parser.Parse(kTestFileName, fs_.get(), false,
|
||||
4096 /* readahead_size */));
|
||||
@@ -2737,7 +2733,7 @@ TEST_F(OptionsParserTest, ParseVersion) {
|
||||
snprintf(buffer, kLength - 1, file_template.c_str(), iv.c_str());
|
||||
|
||||
parser.Reset();
|
||||
ASSERT_OK(env_->WriteToNewFile(iv, buffer));
|
||||
ASSERT_OK(fs_->WriteToNewFile(iv, buffer));
|
||||
ASSERT_NOK(parser.Parse(iv, fs_.get(), false, 0 /* readahead_size */));
|
||||
}
|
||||
|
||||
@@ -2746,7 +2742,7 @@ TEST_F(OptionsParserTest, ParseVersion) {
|
||||
for (auto vv : valid_versions) {
|
||||
snprintf(buffer, kLength - 1, file_template.c_str(), vv.c_str());
|
||||
parser.Reset();
|
||||
ASSERT_OK(env_->WriteToNewFile(vv, buffer));
|
||||
ASSERT_OK(fs_->WriteToNewFile(vv, buffer));
|
||||
ASSERT_OK(parser.Parse(vv, fs_.get(), false, 0 /* readahead_size */));
|
||||
}
|
||||
}
|
||||
@@ -2855,37 +2851,37 @@ TEST_F(OptionsParserTest, Readahead) {
|
||||
kOptionsFileName, fs_.get()));
|
||||
|
||||
uint64_t file_size = 0;
|
||||
ASSERT_OK(env_->GetFileSize(kOptionsFileName, &file_size));
|
||||
ASSERT_OK(
|
||||
fs_->GetFileSize(kOptionsFileName, IOOptions(), &file_size, nullptr));
|
||||
assert(file_size > 0);
|
||||
|
||||
RocksDBOptionsParser parser;
|
||||
|
||||
env_->num_seq_file_read_ = 0;
|
||||
fs_->num_seq_file_read_ = 0;
|
||||
size_t readahead_size = 128 * 1024;
|
||||
|
||||
ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false, readahead_size));
|
||||
ASSERT_EQ(env_->num_seq_file_read_.load(),
|
||||
ASSERT_EQ(fs_->num_seq_file_read_.load(),
|
||||
(file_size - 1) / readahead_size + 1);
|
||||
|
||||
env_->num_seq_file_read_.store(0);
|
||||
fs_->num_seq_file_read_.store(0);
|
||||
readahead_size = 1024 * 1024;
|
||||
ASSERT_OK(parser.Parse(kOptionsFileName, fs_.get(), false, readahead_size));
|
||||
ASSERT_EQ(env_->num_seq_file_read_.load(),
|
||||
ASSERT_EQ(fs_->num_seq_file_read_.load(),
|
||||
(file_size - 1) / readahead_size + 1);
|
||||
|
||||
// Tiny readahead. 8 KB is read each time.
|
||||
env_->num_seq_file_read_.store(0);
|
||||
fs_->num_seq_file_read_.store(0);
|
||||
ASSERT_OK(
|
||||
parser.Parse(kOptionsFileName, fs_.get(), false, 1 /* readahead_size */));
|
||||
ASSERT_GE(env_->num_seq_file_read_.load(), file_size / (8 * 1024));
|
||||
ASSERT_LT(env_->num_seq_file_read_.load(), file_size / (8 * 1024) * 2);
|
||||
ASSERT_GE(fs_->num_seq_file_read_.load(), file_size / (8 * 1024));
|
||||
ASSERT_LT(fs_->num_seq_file_read_.load(), file_size / (8 * 1024) * 2);
|
||||
|
||||
// Disable readahead means 512KB readahead.
|
||||
env_->num_seq_file_read_.store(0);
|
||||
fs_->num_seq_file_read_.store(0);
|
||||
ASSERT_OK(
|
||||
parser.Parse(kOptionsFileName, fs_.get(), false, 0 /* readahead_size */));
|
||||
ASSERT_GE(env_->num_seq_file_read_.load(),
|
||||
(file_size - 1) / (512 * 1024) + 1);
|
||||
ASSERT_GE(fs_->num_seq_file_read_.load(), (file_size - 1) / (512 * 1024) + 1);
|
||||
}
|
||||
|
||||
TEST_F(OptionsParserTest, DumpAndParse) {
|
||||
@@ -3083,7 +3079,7 @@ class OptionsSanityCheckTest : public OptionsParserTest {
|
||||
}
|
||||
|
||||
Status PersistCFOptions(const ColumnFamilyOptions& cf_opts) {
|
||||
Status s = env_->DeleteFile(kOptionsFileName);
|
||||
Status s = fs_->DeleteFile(kOptionsFileName, IOOptions(), nullptr);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <rocksdb/env.h>
|
||||
#include "port/win/env_win.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "test_util/sync_point.h"
|
||||
#include "util/compression_context_cache.h"
|
||||
#include "util/thread_local.h"
|
||||
|
||||
Loaded 100 of 141 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user