mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-08 15:15:23 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6999a230ba | |||
| 6880d2f545 | |||
| b46e796c99 | |||
| 7f64b56f6b | |||
| f2ebb6745a |
+1
-8
@@ -14,7 +14,6 @@
|
||||
# 3. Run cmake to generate project files for Windows, add more options to enable required third-party libraries.
|
||||
# See thirdparty.inc for more information.
|
||||
# sample command: cmake -G "Visual Studio 12 Win64" -DGFLAGS=1 -DSNAPPY=1 -DJEMALLOC=1 ..
|
||||
# OR for VS Studio 15 cmake -G "Visual Studio 14 Win64" -DGFLAGS=1 -DSNAPPY=1 -DJEMALLOC=1 ..
|
||||
# 4. Then build the project in debug mode (you may want to add /m[:<N>] flag to run msbuild in <N> parallel threads
|
||||
# or simply /m ot use all avail cores)
|
||||
# msbuild rocksdb.sln
|
||||
@@ -59,8 +58,7 @@ add_custom_command(OUTPUT ${BUILD_VERSION_CC}
|
||||
add_custom_target(GenerateBuildVersion DEPENDS ${BUILD_VERSION_CC})
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /EHsc /GS /Gd /GR /GF /fp:precise /Zc:wchar_t /Zc:forScope /errorReport:queue")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W3 /WX /wd4127 /wd4244 /wd4267 /wd4800 /wd4996")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FC /d2Zi+ /W3 /WX /wd4127 /wd4244 /wd4267 /wd4800 /wd4804 /wd4996")
|
||||
|
||||
# Used to run CI build and tests so we can run faster
|
||||
set(OPTIMIZE_DEBUG_DEFAULT 0) # Debug build is unoptimized by default use -DOPTDBG=1 to optimize
|
||||
@@ -220,7 +218,6 @@ set(SOURCES
|
||||
util/options_sanity_check.cc
|
||||
util/perf_context.cc
|
||||
util/perf_level.cc
|
||||
util/random.cc
|
||||
util/rate_limiter.cc
|
||||
util/skiplistrep.cc
|
||||
util/slice.cc
|
||||
@@ -252,7 +249,6 @@ set(SOURCES
|
||||
utilities/merge_operators/string_append/stringappend2.cc
|
||||
utilities/merge_operators/put.cc
|
||||
utilities/merge_operators/uint64add.cc
|
||||
utilities/options/options_util.cc
|
||||
utilities/redis/redis_lists.cc
|
||||
utilities/spatialdb/spatial_db.cc
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector.cc
|
||||
@@ -326,14 +322,12 @@ set(TESTS
|
||||
db/file_indexer_test.cc
|
||||
db/filename_test.cc
|
||||
db/flush_job_test.cc
|
||||
db/inlineskiplist_test.cc
|
||||
db/listener_test.cc
|
||||
db/log_test.cc
|
||||
db/manual_compaction_test.cc
|
||||
db/memtable_list_test.cc
|
||||
db/merge_test.cc
|
||||
db/merge_helper_test.cc
|
||||
db/options_file_test.cc
|
||||
db/perf_context_test.cc
|
||||
db/plain_table_db_test.cc
|
||||
db/prefix_test.cc
|
||||
@@ -386,7 +380,6 @@ set(TESTS
|
||||
utilities/geodb/geodb_test.cc
|
||||
utilities/memory/memory_test.cc
|
||||
utilities/merge_operators/string_append/stringappend_test.cc
|
||||
utilities/options/options_util_test.cc
|
||||
utilities/redis/redis_lists_test.cc
|
||||
utilities/spatialdb/spatial_db_test.cc
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector_test.cc
|
||||
|
||||
-12
@@ -1,28 +1,16 @@
|
||||
# Rocksdb Change Log
|
||||
|
||||
## 4.3.0 (12/8/2015)
|
||||
### New Features
|
||||
* CompactionFilter has new member function called IgnoreSnapshots which allows CompactionFilter to be called even if there are snapshots later than the key.
|
||||
* RocksDB will now persist options under the same directory as the RocksDB database on successful DB::Open, CreateColumnFamily, DropColumnFamily, and SetOptions.
|
||||
* Introduce LoadLatestOptions() in rocksdb/utilities/options_util.h. This function can construct the latest DBOptions / ColumnFamilyOptions used by the specified RocksDB intance.
|
||||
* Introduce CheckOptionsCompatibility() in rocksdb/utilities/options_util.h. This function checks whether the input set of options is able to open the specified DB successfully.
|
||||
|
||||
### Public API Changes
|
||||
* When options.db_write_buffer_size triggers, only the column family with the largest column family size will be flushed, not all the column families.
|
||||
|
||||
## 4.2.0 (11/9/2015)
|
||||
### New Features
|
||||
* Introduce CreateLoggerFromOptions(), this function create a Logger for provided DBOptions.
|
||||
* Add GetAggregatedIntProperty(), which returns the sum of the GetIntProperty of all the column families.
|
||||
* Add MemoryUtil in rocksdb/utilities/memory.h. It currently offers a way to get the memory usage by type from a list rocksdb instances.
|
||||
|
||||
### Public API Changes
|
||||
* CompactionFilter::Context includes information of Column Family ID
|
||||
* The need-compaction hint given by TablePropertiesCollector::NeedCompact() will be persistent and recoverable after DB recovery. This introduces a breaking format change. If you use this experimental feature, including NewCompactOnDeletionCollectorFactory() in the new version, you may not be able to directly downgrade the DB back to version 4.0 or lower.
|
||||
* TablePropertiesCollectorFactory::CreateTablePropertiesCollector() now takes an option Context, containing the information of column family ID for the file being written.
|
||||
* Remove DefaultCompactionFilterFactory.
|
||||
|
||||
|
||||
## 4.1.0 (10/8/2015)
|
||||
### New Features
|
||||
* Added single delete operation as a more efficient way to delete keys that have not been overwritten.
|
||||
|
||||
@@ -187,6 +187,10 @@ default: all
|
||||
WARNING_FLAGS = -W -Wextra -Wall -Wsign-compare -Wshadow \
|
||||
-Wno-unused-parameter
|
||||
|
||||
ifndef DISABLE_WARNING_AS_ERROR
|
||||
WARNING_FLAGS += -Werror
|
||||
endif
|
||||
|
||||
CFLAGS += $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CCFLAGS) $(OPT)
|
||||
CXXFLAGS += $(WARNING_FLAGS) -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers
|
||||
|
||||
@@ -270,7 +274,6 @@ TESTS = \
|
||||
block_based_filter_block_test \
|
||||
full_filter_block_test \
|
||||
histogram_test \
|
||||
inlineskiplist_test \
|
||||
log_test \
|
||||
manual_compaction_test \
|
||||
memenv_test \
|
||||
@@ -280,7 +283,6 @@ TESTS = \
|
||||
memory_test \
|
||||
merge_test \
|
||||
merger_test \
|
||||
options_file_test \
|
||||
redis_test \
|
||||
reduce_levels_test \
|
||||
plain_table_db_test \
|
||||
@@ -308,7 +310,6 @@ TESTS = \
|
||||
rate_limiter_test \
|
||||
delete_scheduler_test \
|
||||
options_test \
|
||||
options_util_test \
|
||||
event_logger_test \
|
||||
cuckoo_table_builder_test \
|
||||
cuckoo_table_reader_test \
|
||||
@@ -342,7 +343,6 @@ TOOLS = \
|
||||
rocksdb_dump \
|
||||
rocksdb_undump
|
||||
|
||||
# TODO: add back forward_iterator_bench, after making it build in all environemnts.
|
||||
BENCHMARKS = db_bench table_reader_bench cache_bench memtablerep_bench
|
||||
|
||||
# if user didn't config LIBNAME, set the default
|
||||
@@ -604,7 +604,7 @@ asan_crash_test:
|
||||
$(MAKE) clean
|
||||
|
||||
valgrind_check: $(TESTS)
|
||||
for t in $(filter-out %skiplist_test,$(TESTS)); do \
|
||||
for t in $(filter-out skiplist_test,$(TESTS)); do \
|
||||
$(VALGRIND_VER) $(VALGRIND_OPTS) ./$$t; \
|
||||
ret_code=$$?; \
|
||||
if [ $$ret_code -ne 0 ]; then \
|
||||
@@ -861,9 +861,6 @@ table_test: table/table_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
block_test: table/block_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
inlineskiplist_test: db/inlineskiplist_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
skiplist_test: db/skiplist_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -903,9 +900,6 @@ merge_test: db/merge_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
merger_test: table/merger_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
options_file_test: db/options_file_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
deletefile_test: db/deletefile_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
@@ -939,9 +933,6 @@ compact_files_test: db/compact_files_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
options_test: util/options_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
options_util_test: utilities/options/options_util_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
event_logger_test: util/event_logger_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(AM_LINK)
|
||||
|
||||
|
||||
+2
-6
@@ -2,14 +2,10 @@ version: 1.0.{build}
|
||||
before_build:
|
||||
- md %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cmake -G "Visual Studio 12 Win64" -DOPTDBG=1 ..
|
||||
- cmake -G "Visual Studio 12 Win64" ..
|
||||
- cd ..
|
||||
build:
|
||||
project: build\rocksdb.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
test:
|
||||
test_script:
|
||||
- ps: build_tools\run_ci_db_test.ps1 -EnableRerun -Run db_test -Exclude DBTest.Randomized,DBTest.FileCreationRandomFailure -Concurrency 18
|
||||
- ps: build_tools\run_ci_db_test.ps1 -Run env_test -Concurrency 1
|
||||
|
||||
test: off
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
version: 1.0.{build}
|
||||
before_build:
|
||||
- md %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\build
|
||||
- cmake -G "Visual Studio 12 Win64" -DOPTDBG=1 ..
|
||||
- cd ..
|
||||
build:
|
||||
project: build\rocksdb.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
test:
|
||||
test_script:
|
||||
- ps: build_tools\run_ci_db_test.ps1
|
||||
notifications:
|
||||
- provider: Email
|
||||
to:
|
||||
- svmtrocksdb@microsoft.com
|
||||
subject: "Build {{status}}"
|
||||
message: "{{message}}, {{commitId}}, ..."
|
||||
on_build_success: false
|
||||
on_build_failure: true
|
||||
on_build_status_changed: true
|
||||
@@ -52,7 +52,12 @@ if [ -z "$ROCKSDB_NO_FBCODE" -a -d /mnt/gvfs/third-party ]; then
|
||||
FBCODE_BUILD="true"
|
||||
# If we're compiling with TSAN we need pic build
|
||||
PIC_BUILD=$COMPILE_WITH_TSAN
|
||||
source "$PWD/build_tools/fbcode_config.sh"
|
||||
if [ -z "$ROCKSDB_FBCODE_BUILD_WITH_481" ]; then
|
||||
source "$PWD/build_tools/fbcode_config.sh"
|
||||
else
|
||||
# we need this to build with MySQL. Don't use for other purposes.
|
||||
source "$PWD/build_tools/fbcode_config4.8.1.sh"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Delete existing output, if it exists
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
GCC_BASE=/mnt/gvfs/third-party2/gcc/7331085db891a2ef4a88a48a751d834e8d68f4cb/7.x/centos7-native/b2ef2b6
|
||||
CLANG_BASE=/mnt/gvfs/third-party2/llvm-fb/963d9aeda70cc4779885b1277484fe7544a04e3e/9.0.0/platform007/9e92d53/
|
||||
LIBGCC_BASE=/mnt/gvfs/third-party2/libgcc/6ace84e956873d53638c738b6f65f3f469cca74c/7.x/platform007/5620abc
|
||||
GLIBC_BASE=/mnt/gvfs/third-party2/glibc/192b0f42d63dcf6210d6ceae387b49af049e6e0c/2.26/platform007/f259413
|
||||
SNAPPY_BASE=/mnt/gvfs/third-party2/snappy/7f9bdaada18f59bc27ec2b0871eb8a6144343aef/1.1.3/platform007/ca4da3d
|
||||
ZLIB_BASE=/mnt/gvfs/third-party2/zlib/2d9f0b9a4274cc21f61272a9e89bdb859bce8f1f/1.2.8/platform007/ca4da3d
|
||||
BZIP2_BASE=/mnt/gvfs/third-party2/bzip2/dc49a21c5fceec6456a7a28a94dcd16690af1337/1.0.6/platform007/ca4da3d
|
||||
LZ4_BASE=/mnt/gvfs/third-party2/lz4/0f607f8fc442ea7d6b876931b1898bb573d5e5da/1.9.1/platform007/ca4da3d
|
||||
ZSTD_BASE=/mnt/gvfs/third-party2/zstd/ca22bc441a4eb709e9e0b1f9fec9750fed7b31c5/1.4.x/platform007/15a3614
|
||||
GFLAGS_BASE=/mnt/gvfs/third-party2/gflags/0b9929d2588991c65a57168bf88aff2db87c5d48/2.2.0/platform007/ca4da3d
|
||||
JEMALLOC_BASE=/mnt/gvfs/third-party2/jemalloc/c26f08f47ac35fc31da2633b7da92d6b863246eb/master/platform007/c26c002
|
||||
NUMA_BASE=/mnt/gvfs/third-party2/numa/3f3fb57a5ccc5fd21c66416c0b83e0aa76a05376/2.0.11/platform007/ca4da3d
|
||||
LIBUNWIND_BASE=/mnt/gvfs/third-party2/libunwind/40c73d874898b386a71847f1b99115d93822d11f/1.4/platform007/6f3e0a9
|
||||
TBB_BASE=/mnt/gvfs/third-party2/tbb/4ce8e8dba77cdbd81b75d6f0c32fd7a1b76a11ec/2018_U5/platform007/ca4da3d
|
||||
KERNEL_HEADERS_BASE=/mnt/gvfs/third-party2/kernel-headers/fb251ecd2f5ae16f8671f7014c246e52a748fe0b/fb/platform007/da39a3e
|
||||
BINUTILS_BASE=/mnt/gvfs/third-party2/binutils/ab9f09bba370e7066cafd4eb59752db93f2e8312/2.29.1/platform007/15a3614
|
||||
VALGRIND_BASE=/mnt/gvfs/third-party2/valgrind/d42d152a15636529b0861ec493927200ebebca8e/3.15.0/platform007/ca4da3d
|
||||
LUA_BASE=/mnt/gvfs/third-party2/lua/f0cd714433206d5139df61659eb7b28b1dea6683/5.3.4/platform007/5007832
|
||||
@@ -6,147 +6,128 @@
|
||||
# Environment variables that change the behavior of this script:
|
||||
# PIC_BUILD -- if true, it will only take pic versions of libraries from fbcode. libraries that don't have pic variant will not be included
|
||||
|
||||
|
||||
BASEDIR=`dirname $BASH_SOURCE`
|
||||
source "$BASEDIR/dependencies.sh"
|
||||
|
||||
CFLAGS=""
|
||||
|
||||
# libgcc
|
||||
LIBGCC_INCLUDE="$LIBGCC_BASE/include/c++/7.3.0"
|
||||
LIBGCC_LIBS=" -L $LIBGCC_BASE/lib"
|
||||
# location of libgcc
|
||||
LIBGCC_BASE="/mnt/gvfs/third-party2/libgcc/0473c80518a10d6efcbe24c5eeca3fb4ec9b519c/4.9.x/gcc-4.9-glibc-2.20/e1a7e4e"
|
||||
LIBGCC_INCLUDE="$LIBGCC_BASE/include"
|
||||
LIBGCC_LIBS=" -L $LIBGCC_BASE/libs"
|
||||
|
||||
# glibc
|
||||
GLIBC_INCLUDE="$GLIBC_BASE/include"
|
||||
GLIBC_LIBS=" -L $GLIBC_BASE/lib"
|
||||
# location of glibc
|
||||
GLIBC_REV=7397bed99280af5d9543439cdb7d018af7542720
|
||||
GLIBC_INCLUDE="/mnt/gvfs/third-party2/glibc/$GLIBC_REV/2.20/gcc-4.9-glibc-2.20/99df8fc/include"
|
||||
GLIBC_LIBS=" -L /mnt/gvfs/third-party2/glibc/$GLIBC_REV/2.20/gcc-4.9-glibc-2.20/99df8fc/lib"
|
||||
|
||||
SNAPPY_INCLUDE=" -I /mnt/gvfs/third-party2/snappy/b0f269b3ca47770121aa159b99e1d8d2ab260e1f/1.0.3/gcc-4.9-glibc-2.20/c32916f/include/"
|
||||
|
||||
# snappy
|
||||
SNAPPY_INCLUDE=" -I $SNAPPY_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy.a"
|
||||
SNAPPY_LIBS=" /mnt/gvfs/third-party2/snappy/b0f269b3ca47770121aa159b99e1d8d2ab260e1f/1.0.3/gcc-4.9-glibc-2.20/c32916f/lib/libsnappy.a"
|
||||
else
|
||||
SNAPPY_LIBS=" $SNAPPY_BASE/lib/libsnappy_pic.a"
|
||||
SNAPPY_LIBS=" /mnt/gvfs/third-party2/snappy/b0f269b3ca47770121aa159b99e1d8d2ab260e1f/1.0.3/gcc-4.9-glibc-2.20/c32916f/lib/libsnappy_pic.a"
|
||||
fi
|
||||
|
||||
CFLAGS+=" -DSNAPPY"
|
||||
|
||||
if test -z $PIC_BUILD; then
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_INCLUDE=" -I $ZLIB_BASE/include/"
|
||||
ZLIB_LIBS=" $ZLIB_BASE/lib/libz.a"
|
||||
ZLIB_INCLUDE=" -I /mnt/gvfs/third-party2/zlib/feb983d9667f4cf5e9da07ce75abc824764b67a1/1.2.8/gcc-4.9-glibc-2.20/4230243/include/"
|
||||
ZLIB_LIBS=" /mnt/gvfs/third-party2/zlib/feb983d9667f4cf5e9da07ce75abc824764b67a1/1.2.8/gcc-4.9-glibc-2.20/4230243/lib/libz.a"
|
||||
CFLAGS+=" -DZLIB"
|
||||
|
||||
# location of bzip headers and libraries
|
||||
BZIP_INCLUDE=" -I $BZIP2_BASE/include/"
|
||||
BZIP_LIBS=" $BZIP2_BASE/lib/libbz2.a"
|
||||
BZIP_INCLUDE=" -I /mnt/gvfs/third-party2/bzip2/af004cceebb2dfd173ca29933ea5915e727aad2f/1.0.6/gcc-4.9-glibc-2.20/4230243/include/"
|
||||
BZIP_LIBS=" /mnt/gvfs/third-party2/bzip2/af004cceebb2dfd173ca29933ea5915e727aad2f/1.0.6/gcc-4.9-glibc-2.20/4230243/lib/libbz2.a"
|
||||
CFLAGS+=" -DBZIP2"
|
||||
|
||||
LZ4_INCLUDE=" -I $LZ4_BASE/include/"
|
||||
LZ4_LIBS=" $LZ4_BASE/lib/liblz4.a"
|
||||
LZ4_INCLUDE=" -I /mnt/gvfs/third-party2/lz4/79d2943e2dd7208a3e0b06cf95e9f85f05fe9e1b/r124/gcc-4.9-glibc-2.20/4230243/include/"
|
||||
LZ4_LIBS=" /mnt/gvfs/third-party2/lz4/79d2943e2dd7208a3e0b06cf95e9f85f05fe9e1b/r124/gcc-4.9-glibc-2.20/4230243/lib/liblz4.a"
|
||||
CFLAGS+=" -DLZ4"
|
||||
fi
|
||||
|
||||
ZSTD_INCLUDE=" -I $ZSTD_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd.a"
|
||||
else
|
||||
ZSTD_LIBS=" $ZSTD_BASE/lib/libzstd_pic.a"
|
||||
ZSTD_REV=810b81b4705def5243e998b54701f3c504e4009e
|
||||
ZSTD_INCLUDE=" -I /mnt/gvfs/third-party2/zstd/$ZSTD_REV/0.4.2/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
ZSTD_LIBS=" /mnt/gvfs/third-party2/zstd/$ZSTD_REV/0.4.2/gcc-4.8.1-glibc-2.17/c3f970a/lib/libzstd.a"
|
||||
CFLAGS+=" -DZSTD"
|
||||
fi
|
||||
CFLAGS+=" -DZSTD"
|
||||
|
||||
# location of gflags headers and libraries
|
||||
GFLAGS_INCLUDE=" -I $GFLAGS_BASE/include/"
|
||||
GFLAGS_INCLUDE=" -I /mnt/gvfs/third-party2/gflags/0fa60e2b88de3e469db6c482d6e6dac72f5d65f9/1.6/gcc-4.9-glibc-2.20/4230243/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
GFLAGS_LIBS=" $GFLAGS_BASE/lib/libgflags.a"
|
||||
GFLAGS_LIBS=" /mnt/gvfs/third-party2/gflags/0fa60e2b88de3e469db6c482d6e6dac72f5d65f9/1.6/gcc-4.9-glibc-2.20/4230243/lib/libgflags.a"
|
||||
else
|
||||
GFLAGS_LIBS=" $GFLAGS_BASE/lib/libgflags_pic.a"
|
||||
GFLAGS_LIBS=" /mnt/gvfs/third-party2/gflags/0fa60e2b88de3e469db6c482d6e6dac72f5d65f9/1.6/gcc-4.9-glibc-2.20/4230243/lib/libgflags_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DGFLAGS=gflags"
|
||||
CFLAGS+=" -DGFLAGS=google"
|
||||
|
||||
# location of jemalloc
|
||||
JEMALLOC_INCLUDE=" -I $JEMALLOC_BASE/include/"
|
||||
JEMALLOC_LIB=" $JEMALLOC_BASE/lib/libjemalloc.a"
|
||||
JEMALLOC_INCLUDE=" -I /mnt/gvfs/third-party2/jemalloc/bcd68e5e419efa4e61b9486d6854564d6d75a0b5/3.6.0/gcc-4.9-glibc-2.20/2aafc78/include/"
|
||||
JEMALLOC_LIB=" /mnt/gvfs/third-party2/jemalloc/bcd68e5e419efa4e61b9486d6854564d6d75a0b5/3.6.0/gcc-4.9-glibc-2.20/2aafc78/lib/libjemalloc.a"
|
||||
|
||||
if test -z $PIC_BUILD; then
|
||||
# location of numa
|
||||
NUMA_INCLUDE=" -I $NUMA_BASE/include/"
|
||||
NUMA_LIB=" $NUMA_BASE/lib/libnuma.a"
|
||||
NUMA_INCLUDE=" -I /mnt/gvfs/third-party2/numa/bbefc39ecbf31d0ca184168eb613ef8d397790ee/2.0.8/gcc-4.9-glibc-2.20/4230243/include/"
|
||||
NUMA_LIB=" /mnt/gvfs/third-party2/numa/bbefc39ecbf31d0ca184168eb613ef8d397790ee/2.0.8/gcc-4.9-glibc-2.20/4230243/lib/libnuma.a"
|
||||
CFLAGS+=" -DNUMA"
|
||||
|
||||
# location of libunwind
|
||||
LIBUNWIND="$LIBUNWIND_BASE/lib/libunwind.a"
|
||||
LIBUNWIND="/mnt/gvfs/third-party2/libunwind/1de3b75e0afedfe5585b231bbb340ec7a1542335/1.1/gcc-4.9-glibc-2.20/34235e8/lib/libunwind.a"
|
||||
fi
|
||||
|
||||
# location of TBB
|
||||
TBB_INCLUDE=" -isystem $TBB_BASE/include/"
|
||||
if test -z $PIC_BUILD; then
|
||||
TBB_LIBS="$TBB_BASE/lib/libtbb.a"
|
||||
else
|
||||
TBB_LIBS="$TBB_BASE/lib/libtbb_pic.a"
|
||||
fi
|
||||
CFLAGS+=" -DTBB"
|
||||
|
||||
# use Intel SSE support for checksum calculations
|
||||
export USE_SSE=1
|
||||
|
||||
BINUTILS="$BINUTILS_BASE/bin"
|
||||
BINUTILS="/mnt/gvfs/third-party2/binutils/0b6ad0c88ddd903333a48ae8bff134efac468e4a/2.25/centos6-native/da39a3e/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE $TBB_INCLUDE"
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE"
|
||||
|
||||
GCC_BASE="/mnt/gvfs/third-party2/gcc/1c67a0b88f64d4d9ced0382d141c76aaa7d62fba/4.9.x/centos6-native/1317bc4"
|
||||
STDLIBS="-L $GCC_BASE/lib64"
|
||||
|
||||
CLANG_BIN="$CLANG_BASE/bin"
|
||||
CLANG_LIB="$CLANG_BASE/lib"
|
||||
CLANG_SRC="$CLANG_BASE/../../src"
|
||||
|
||||
CLANG_BASE="/mnt/gvfs/third-party2/clang/d81444dd214df3d2466734de45bb264a0486acc3/dev"
|
||||
CLANG_BIN="$CLANG_BASE/centos6-native/af4b1a0/bin"
|
||||
CLANG_ANALYZER="$CLANG_BIN/clang++"
|
||||
CLANG_SCAN_BUILD="$CLANG_SRC/llvm/tools/clang/tools/scan-build/bin/scan-build"
|
||||
CLANG_SCAN_BUILD="$CLANG_BASE/src/clang/tools/scan-build/scan-build"
|
||||
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
# gcc
|
||||
CC="$GCC_BASE/bin/gcc"
|
||||
CXX="$GCC_BASE/bin/g++"
|
||||
|
||||
|
||||
CFLAGS+=" -B$BINUTILS/gold"
|
||||
CFLAGS+=" -isystem $LIBGCC_INCLUDE"
|
||||
CFLAGS+=" -isystem $GLIBC_INCLUDE"
|
||||
JEMALLOC=1
|
||||
CFLAGS+=" -isystem $LIBGCC_INCLUDE"
|
||||
else
|
||||
# clang
|
||||
CLANG_INCLUDE="$CLANG_LIB/clang/stable/include"
|
||||
# clang
|
||||
CLANG_INCLUDE="$CLANG_BASE/gcc-4.9-glibc-2.20/74c386f/lib/clang/dev/include/"
|
||||
CC="$CLANG_BIN/clang"
|
||||
CXX="$CLANG_BIN/clang++"
|
||||
|
||||
KERNEL_HEADERS_INCLUDE="$KERNEL_HEADERS_BASE/include"
|
||||
KERNEL_HEADERS_INCLUDE="/mnt/gvfs/third-party2/kernel-headers/ffd14f660a43c4b92717986b1bba66722ef089d0/3.2.18_70_fbk11_00129_gc8882d0/gcc-4.9-glibc-2.20/da39a3e/include"
|
||||
|
||||
CFLAGS+=" -B$BINUTILS/gold -nostdinc -nostdlib"
|
||||
CFLAGS+=" -isystem $LIBGCC_BASE/include/c++/7.x "
|
||||
CFLAGS+=" -isystem $LIBGCC_BASE/include/c++/7.x/x86_64-facebook-linux "
|
||||
CFLAGS+=" -isystem $LIBGCC_BASE/include/c++/4.9.x "
|
||||
CFLAGS+=" -isystem $LIBGCC_BASE/include/c++/4.9.x/x86_64-facebook-linux "
|
||||
CFLAGS+=" -isystem $GLIBC_INCLUDE"
|
||||
CFLAGS+=" -isystem $LIBGCC_INCLUDE"
|
||||
CFLAGS+=" -isystem $CLANG_INCLUDE"
|
||||
CFLAGS+=" -isystem $KERNEL_HEADERS_INCLUDE/linux "
|
||||
CFLAGS+=" -isystem $KERNEL_HEADERS_INCLUDE "
|
||||
CFLAGS+=" -Wno-expansion-to-defined "
|
||||
CXXFLAGS="-nostdinc++"
|
||||
fi
|
||||
|
||||
CFLAGS+=" $DEPS_INCLUDE"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE -DROCKSDB_RANGESYNC_PRESENT -DROCKSDB_SCHED_GETCPU_PRESENT -DROCKSDB_SUPPORT_THREAD_LOCAL -DHAVE_SSE42"
|
||||
CFLAGS+=" -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DROCKSDB_FALLOCATE_PRESENT -DROCKSDB_MALLOC_USABLE_SIZE"
|
||||
CXXFLAGS+=" $CFLAGS"
|
||||
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB $TBB_LIBS"
|
||||
EXEC_LDFLAGS+=" -B$BINUTILS/gold"
|
||||
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,/usr/local/fbcode/platform007/lib/ld.so"
|
||||
EXEC_LDFLAGS=" $SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $NUMA_LIB"
|
||||
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,/usr/local/fbcode/gcc-4.9-glibc-2.20/lib/ld.so"
|
||||
EXEC_LDFLAGS+=" $LIBUNWIND"
|
||||
EXEC_LDFLAGS+=" -Wl,-rpath=/usr/local/fbcode/platform007/lib"
|
||||
# required by libtbb
|
||||
EXEC_LDFLAGS+=" -ldl"
|
||||
EXEC_LDFLAGS+=" -Wl,-rpath=/usr/local/fbcode/gcc-4.9-glibc-2.20/lib"
|
||||
|
||||
PLATFORM_LDFLAGS="$LIBGCC_LIBS $GLIBC_LIBS $STDLIBS -lgcc -lstdc++"
|
||||
|
||||
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS $TBB_LIBS"
|
||||
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS"
|
||||
|
||||
VALGRIND_VER="$VALGRIND_BASE/bin/"
|
||||
VALGRIND_VER="/mnt/gvfs/third-party2/valgrind/6c45ef049cbf11c2df593addb712cd891049e737/3.10.0/gcc-4.9-glibc-2.20/4230243/bin/"
|
||||
|
||||
export CC CXX AR CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD
|
||||
export CC CXX AR CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE CLANG_ANALYZER CLANG_SCAN_BUILD
|
||||
|
||||
@@ -5,66 +5,61 @@
|
||||
# uses jemalloc
|
||||
|
||||
# location of libgcc
|
||||
LIBGCC_BASE="/mnt/gvfs/third-party2/libgcc/d00277f4559e261ed0a81f30f23c0ce5564e359e/4.8.1/gcc-4.8.1-glibc-2.17/8aac7fc"
|
||||
LIBGCC_BASE="/mnt/gvfs/third-party2/libgcc/7712e757d7355cb51292454ee0b7b46a467fdfed/4.8.1/gcc-4.8.1-glibc-2.17/8aac7fc"
|
||||
LIBGCC_INCLUDE="$LIBGCC_BASE/include"
|
||||
LIBGCC_LIBS=" -L $LIBGCC_BASE/libs"
|
||||
|
||||
# location of glibc
|
||||
GLIBC_REV=0600c95b31226b5e535614c590677d87c62d8016
|
||||
GLIBC_REV=6e40560b4e0b6d690fd1cf8c7a43ad7452b04cfa
|
||||
GLIBC_INCLUDE="/mnt/gvfs/third-party2/glibc/$GLIBC_REV/2.17/gcc-4.8.1-glibc-2.17/99df8fc/include"
|
||||
GLIBC_LIBS=" -L /mnt/gvfs/third-party2/glibc/$GLIBC_REV/2.17/gcc-4.8.1-glibc-2.17/99df8fc/lib"
|
||||
|
||||
# location of snappy headers and libraries
|
||||
SNAPPY_REV=cbf6f1f209e5bd160bdc5d971744e039f36b1566
|
||||
SNAPPY_INCLUDE=" -I /mnt/gvfs/third-party2/snappy/$SNAPPY_REV/1.1.3/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
SNAPPY_LIBS=" /mnt/gvfs/third-party2/snappy/$SNAPPY_REV/1.1.3/gcc-4.8.1-glibc-2.17/c3f970a/lib/libsnappy.a"
|
||||
SNAPPY_INCLUDE=" -I /mnt/gvfs/third-party2/snappy/aef17f6c0b44b4fe408bd06f67c93701ab0a6ceb/1.0.3/gcc-4.8.1-glibc-2.17/43d84e2/include"
|
||||
SNAPPY_LIBS=" /mnt/gvfs/third-party2/snappy/aef17f6c0b44b4fe408bd06f67c93701ab0a6ceb/1.0.3/gcc-4.8.1-glibc-2.17/43d84e2/lib/libsnappy.a"
|
||||
|
||||
# location of zlib headers and libraries
|
||||
ZLIB_REV=6d39cb54708049f527e713ad19f2aadb9d3667e8
|
||||
ZLIB_INCLUDE=" -I /mnt/gvfs/third-party2/zlib/$ZLIB_REV/1.2.8/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
ZLIB_LIBS=" /mnt/gvfs/third-party2/zlib/$ZLIB_REV/1.2.8/gcc-4.8.1-glibc-2.17/c3f970a/lib/libz.a"
|
||||
ZLIB_INCLUDE=" -I /mnt/gvfs/third-party2/zlib/25c6216928b4d77b59ddeca0990ff6fe9ac16b81/1.2.5/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
ZLIB_LIBS=" /mnt/gvfs/third-party2/zlib/25c6216928b4d77b59ddeca0990ff6fe9ac16b81/1.2.5/gcc-4.8.1-glibc-2.17/c3f970a/lib/libz.a"
|
||||
|
||||
# location of bzip headers and libraries
|
||||
BZIP_REV=d6c789bfc2ec4c51a63d66df2878926b8158cde8
|
||||
BZIP_INCLUDE=" -I /mnt/gvfs/third-party2/bzip2/$BZIP_REV/1.0.6/gcc-4.8.1-glibc-2.17/c3f970a/include/"
|
||||
BZIP_LIBS=" /mnt/gvfs/third-party2/bzip2/$BZIP_REV/1.0.6/gcc-4.8.1-glibc-2.17/c3f970a/lib/libbz2.a"
|
||||
BZIP_INCLUDE=" -I /mnt/gvfs/third-party2/bzip2/c9ef7629c2aa0024f7a416e87602f06eb88f5eac/1.0.6/gcc-4.8.1-glibc-2.17/c3f970a/include/"
|
||||
BZIP_LIBS=" /mnt/gvfs/third-party2/bzip2/c9ef7629c2aa0024f7a416e87602f06eb88f5eac/1.0.6/gcc-4.8.1-glibc-2.17/c3f970a/lib/libbz2.a"
|
||||
|
||||
LZ4_REV=6858fac689e0f92e584224d91bdb0e39f6c8320d
|
||||
LZ4_INCLUDE=" -I /mnt/gvfs/third-party2/lz4/$LZ4_REV/r131/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
LZ4_LIBS=" /mnt/gvfs/third-party2/lz4/$LZ4_REV/r131/gcc-4.8.1-glibc-2.17/c3f970a/lib/liblz4.a"
|
||||
LZ4_REV=065ec7e38fe83329031f6668c43bef83eff5808b
|
||||
LZ4_INCLUDE=" -I /mnt/gvfs/third-party2/lz4/$LZ4_REV/r108/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
LZ4_LIBS=" /mnt/gvfs/third-party2/lz4/$LZ4_REV/r108/gcc-4.8.1-glibc-2.17/c3f970a/lib/liblz4.a"
|
||||
|
||||
ZSTD_REV=810b81b4705def5243e998b54701f3c504e4009e
|
||||
ZSTD_INCLUDE=" -I /mnt/gvfs/third-party2/zstd/$ZSTD_REV/0.4.2/gcc-4.8.1-glibc-2.17/c3f970a/include"
|
||||
ZSTD_LIBS=" /mnt/gvfs/third-party2/zstd/$ZSTD_REV/0.4.2/gcc-4.8.1-glibc-2.17/c3f970a/lib/libzstd.a"
|
||||
|
||||
# location of gflags headers and libraries
|
||||
GFLAGS_REV=c7275a4ceae0aca0929e56964a31dafc53c1ee96
|
||||
GFLAGS_INCLUDE=" -I /mnt/gvfs/third-party2/gflags/$GFLAGS_REV/2.1.1/gcc-4.8.1-glibc-2.17/c3f970a/include/"
|
||||
GFLAGS_LIBS=" /mnt/gvfs/third-party2/gflags/$GFLAGS_REV/2.1.1/gcc-4.8.1-glibc-2.17/c3f970a/lib/libgflags.a"
|
||||
GFLAGS_INCLUDE=" -I /mnt/gvfs/third-party2/gflags/1ad047a6e6f6673991918ecadc670868205a243a/1.6/gcc-4.8.1-glibc-2.17/c3f970a/include/"
|
||||
GFLAGS_LIBS=" /mnt/gvfs/third-party2/gflags/1ad047a6e6f6673991918ecadc670868205a243a/1.6/gcc-4.8.1-glibc-2.17/c3f970a/lib/libgflags.a"
|
||||
|
||||
# location of jemalloc
|
||||
JEMALLOC_REV=c370265e58c4b6602e798df23335a1e9913dae52
|
||||
JEMALLOC_INCLUDE=" -I /mnt/gvfs/third-party2/jemalloc/$JEMALLOC_REV/4.0.3/gcc-4.8.1-glibc-2.17/8d31e51/include"
|
||||
JEMALLOC_LIB="/mnt/gvfs/third-party2/jemalloc/$JEMALLOC_REV/4.0.3/gcc-4.8.1-glibc-2.17/8d31e51/lib/libjemalloc.a"
|
||||
JEMALLOC_INCLUDE=" -I /mnt/gvfs/third-party2/jemalloc/3691c776ac26dd8781e84f8888b6a0fbdbc0a9ed/dev/gcc-4.8.1-glibc-2.17/4d53c6f/include"
|
||||
JEMALLOC_LIB="/mnt/gvfs/third-party2/jemalloc/3691c776ac26dd8781e84f8888b6a0fbdbc0a9ed/dev/gcc-4.8.1-glibc-2.17/4d53c6f/lib/libjemalloc.a"
|
||||
|
||||
# location of numa
|
||||
NUMA_REV=ae54a5ed22cdabb1c6446dce4e8ffae5b4446d73
|
||||
NUMA_REV=829d10dac0230f99cd7e1778869d2adf3da24b65
|
||||
NUMA_INCLUDE=" -I /mnt/gvfs/third-party2/numa/$NUMA_REV/2.0.8/gcc-4.8.1-glibc-2.17/c3f970a/include/"
|
||||
NUMA_LIB=" /mnt/gvfs/third-party2/numa/$NUMA_REV/2.0.8/gcc-4.8.1-glibc-2.17/c3f970a/lib/libnuma.a"
|
||||
|
||||
# location of libunwind
|
||||
LIBUNWIND_REV=121f1a75c4414683aea8c70b761bfaf187f7c1a3
|
||||
LIBUNWIND="/mnt/gvfs/third-party2/libunwind/$LIBUNWIND_REV/trunk/gcc-4.8.1-glibc-2.17/675d945/lib/libunwind.a"
|
||||
LIBUNWIND_REV=2c060e64064559905d46fd194000d61592087bdc
|
||||
LIBUNWIND="/mnt/gvfs/third-party2/libunwind/$LIBUNWIND_REV/1.1/gcc-4.8.1-glibc-2.17/675d945/lib/libunwind.a"
|
||||
|
||||
# use Intel SSE support for checksum calculations
|
||||
export USE_SSE=1
|
||||
|
||||
BINUTILS="/mnt/gvfs/third-party2/binutils/75670d0d8ef4891fd1ec2a7513ef01cd002c823b/2.25/centos6-native/da39a3e/bin"
|
||||
BINUTILS="/mnt/gvfs/third-party2/binutils/2aff2e7b474cd3e6ab23495ad1224b7d214b9f8e/2.21.1/centos6-native/da39a3e/bin"
|
||||
AR="$BINUTILS/ar"
|
||||
|
||||
DEPS_INCLUDE="$SNAPPY_INCLUDE $ZLIB_INCLUDE $BZIP_INCLUDE $LZ4_INCLUDE $ZSTD_INCLUDE $GFLAGS_INCLUDE $NUMA_INCLUDE"
|
||||
|
||||
GCC_BASE="/mnt/gvfs/third-party2/gcc/c0064002d2609ab649603f769f0bd110bbe48029/4.8.1/centos6-native/cc6c9dc"
|
||||
GCC_BASE="/mnt/gvfs/third-party2/gcc/1ec615e23800f0815d474478ba476a0adc3fe788/4.8.1/centos6-native/cc6c9dc"
|
||||
STDLIBS="-L $GCC_BASE/lib64"
|
||||
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
@@ -77,12 +72,12 @@ if [ -z "$USE_CLANG" ]; then
|
||||
CFLAGS+=" -isystem $LIBGCC_INCLUDE"
|
||||
else
|
||||
# clang
|
||||
CLANG_BASE="/mnt/gvfs/third-party2/clang/ab054e9a490a8fd4537c0b6ec56e5c91c0f81c91/3.4"
|
||||
CLANG_BASE="/mnt/gvfs/third-party2/clang/9ab68376f938992c4eb5946ca68f90c3185cffc8/3.4"
|
||||
CLANG_INCLUDE="$CLANG_BASE/gcc-4.8.1-glibc-2.17/fb0f730/lib/clang/3.4/include"
|
||||
CC="$CLANG_BASE/centos6-native/9cefd8a/bin/clang"
|
||||
CXX="$CLANG_BASE/centos6-native/9cefd8a/bin/clang++"
|
||||
|
||||
KERNEL_HEADERS_INCLUDE="/mnt/gvfs/third-party2/kernel-headers/1a48835975c66d30e47770ec419758ed3b9ba010/3.10.62-62_fbk17_03959_ge29cc63/gcc-4.8.1-glibc-2.17/da39a3e/include/"
|
||||
KERNEL_HEADERS_INCLUDE="/mnt/gvfs/third-party2/kernel-headers/a683ed7135276731065a9d76d3016c9731f4e2f9/3.2.18_70_fbk11_00129_gc8882d0/gcc-4.8.1-glibc-2.17/da39a3e/include/"
|
||||
|
||||
CFLAGS="-B$BINUTILS/gold -nostdinc -nostdlib"
|
||||
CFLAGS+=" -isystem $LIBGCC_BASE/include/c++/4.8.1 "
|
||||
@@ -109,7 +104,7 @@ PLATFORM_LDFLAGS="$LIBGCC_LIBS $GLIBC_LIBS $STDLIBS -lgcc -lstdc++"
|
||||
|
||||
EXEC_LDFLAGS_SHARED="$SNAPPY_LIBS $ZLIB_LIBS $BZIP_LIBS $LZ4_LIBS $ZSTD_LIBS $GFLAGS_LIBS"
|
||||
|
||||
VALGRIND_REV=af85c56f424cd5edfc2c97588299b44ecdec96bb
|
||||
VALGRIND_REV=b2a9f85e4b70cd03abc85a7f3027fbc4cef35bd0
|
||||
VALGRIND_VER="/mnt/gvfs/third-party2/valgrind/$VALGRIND_REV/3.8.1/gcc-4.8.1-glibc-2.17/c3f970a/bin/"
|
||||
|
||||
export CC CXX AR CFLAGS CXXFLAGS EXEC_LDFLAGS EXEC_LDFLAGS_SHARED VALGRIND_VER JEMALLOC_LIB JEMALLOC_INCLUDE
|
||||
|
||||
+93
-138
@@ -5,15 +5,13 @@
|
||||
# Run the script from the enlistment
|
||||
Param(
|
||||
[switch]$EnableJE = $false, # Use je executable
|
||||
[switch]$EnableRerun = $false, # Rerun failed tests sequentially at the end
|
||||
[string]$WorkFolder = "", # Direct tests to use that folder
|
||||
[int]$Limit = -1, # -1 means run all otherwise limit for testing purposes
|
||||
[string]$Exclude = "", # Expect a comma separated list, no spaces
|
||||
[string]$Run = "db_test", # Run db_test|tests|testname1,testname2...
|
||||
[string]$Run = "db_test", # Run db_test|tests
|
||||
# Number of async tasks that would run concurrently. Recommend a number below 64.
|
||||
# However, CPU utlization really depends on the storage media. Recommend ram based disk.
|
||||
# a value of 1 will run everything serially
|
||||
[int]$Concurrency = 16
|
||||
[int]$Concurrency = 62
|
||||
)
|
||||
|
||||
# Folders and commands must be fullpath to run assuming
|
||||
@@ -54,7 +52,7 @@ if($EnableJE) {
|
||||
}
|
||||
|
||||
Write-Output "Root: $RootFolder, WorkFolder: $WorkFolder"
|
||||
Write-Output "Binaries: $BinariesFolder db_test: $db_test"
|
||||
Write-Output "Binaries: $BinariesFolder exe: $db_test"
|
||||
|
||||
#Exclusions that we do not want to run
|
||||
$ExcludeTests = New-Object System.Collections.Generic.HashSet[string]
|
||||
@@ -62,7 +60,7 @@ $ExcludeTests = New-Object System.Collections.Generic.HashSet[string]
|
||||
|
||||
if($Exclude -ne "") {
|
||||
Write-Host "Exclude: $Exclude"
|
||||
$l = $Exclude -split ' '
|
||||
$l = $Exclude -split ','
|
||||
ForEach($t in $l) { $ExcludeTests.Add($t) | Out-Null }
|
||||
}
|
||||
|
||||
@@ -114,69 +112,48 @@ function Normalize-DbTests($HashTable) {
|
||||
|
||||
$test_log = $test -replace '[\./]','_'
|
||||
$test_log += ".log"
|
||||
$log_path = -join ($LogFolder, $test_log)
|
||||
|
||||
# Add to a hashtable
|
||||
$HashTable.Add($test, $log_path);
|
||||
$HashTable.Add($test, $test_log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# The function removes trailing .exe siffix if any,
|
||||
# creates a name for the log file
|
||||
function MakeAndAdd([string]$token, $HashTable) {
|
||||
$test_name = $token -replace '.exe$', ''
|
||||
$log_name = -join ($test_name, ".log")
|
||||
$log_path = -join ($LogFolder, $log_name)
|
||||
if(!$ExcludeTests.Contains($test_name)) {
|
||||
$HashTable.Add($test_name, $log_path)
|
||||
} else {
|
||||
Write-Warning "Test $test_name is excluded"
|
||||
}
|
||||
}
|
||||
|
||||
# The function scans build\Debug folder to discover
|
||||
# Test executables. It then populates a table with
|
||||
# Test executable name -> Log file
|
||||
function Discover-TestBinaries([string]$Pattern, $HashTable) {
|
||||
function Discover-TestBinaries($HashTable) {
|
||||
|
||||
$Exclusions = @("db_test*", "db_sanity_test*")
|
||||
|
||||
$p = -join ($BinariesFolder, $pattern)
|
||||
|
||||
Write-Host "Path: $p"
|
||||
if($EnableJE) {
|
||||
$p = -join ($BinariesFolder, "*_test_je.exe")
|
||||
} else {
|
||||
$p = -join ($BinariesFolder, "*_test.exe")
|
||||
}
|
||||
|
||||
dir -Path $p -Exclude $Exclusions | ForEach-Object {
|
||||
MakeAndAdd -token ($_.Name) -HashTable $HashTable
|
||||
$t = ($_.Name) -replace '.exe$', ''
|
||||
if($ExcludeTests.Contains($t)) {
|
||||
continue
|
||||
}
|
||||
$test_log = -join ($t, ".log")
|
||||
$HashTable.Add($t, $test_log)
|
||||
}
|
||||
}
|
||||
|
||||
$TestsToRun = [ordered]@{}
|
||||
$TestToLog = [ordered]@{}
|
||||
|
||||
if($Run -ceq "db_test") {
|
||||
Normalize-DbTests -HashTable $TestsToRun
|
||||
Normalize-DbTests -HashTable $TestToLog
|
||||
} elseif($Run -ceq "tests") {
|
||||
if($EnableJE) {
|
||||
$pattern = "*_test_je.exe"
|
||||
} else {
|
||||
$pattern = "*_test.exe"
|
||||
}
|
||||
Discover-TestBinaries -Pattern $pattern -HashTable $TestsToRun
|
||||
Discover-TestBinaries -HashTable $TestToLog
|
||||
} else {
|
||||
|
||||
$test_list = $Run -split ' '
|
||||
|
||||
ForEach($t in $test_list) {
|
||||
MakeAndAdd -token $t -HashTable $TestsToRun
|
||||
}
|
||||
Write-Warning "Invalid -Run option value"
|
||||
exit 2
|
||||
}
|
||||
|
||||
$NumTestsToStart = $TestsToRun.Count
|
||||
if($Limit -ge 0 -and $NumTestsToStart -gt $Limit) {
|
||||
$NumTestsToStart = $Limit
|
||||
}
|
||||
|
||||
Write-Host "Attempting to start: $NumTestsToStart tests"
|
||||
Write-Host "Attempting to start: " ($TestToLog.Count) " tests"
|
||||
|
||||
# Invoke a test with a filter and redirect all output
|
||||
$InvokeTestCase = {
|
||||
@@ -190,123 +167,101 @@ $InvokeTestAsync = {
|
||||
&$exe > $log 2>&1
|
||||
}
|
||||
|
||||
# Hash that contains tests to rerun if any failed
|
||||
# Those tests will be rerun sequentially
|
||||
$Rerun = [ordered]@{}
|
||||
$jobs = @()
|
||||
$JobToLog = @{}
|
||||
# Test limiting factor here
|
||||
$count = 0
|
||||
# Overall status
|
||||
|
||||
[bool]$success = $true;
|
||||
|
||||
function RunJobs($TestToLog, [int]$ConcurrencyVal, [bool]$AddForRerun)
|
||||
{
|
||||
# Array to wait for any of the running jobs
|
||||
# Wait for all to finish and get the results
|
||||
while(($JobToLog.Count -gt 0) -or
|
||||
($TestToLog.Count -gt 0)) {
|
||||
|
||||
# Make sure we have maximum concurrent jobs running if anything
|
||||
# and the $Limit either not set or allows to proceed
|
||||
while(($JobToLog.Count -lt $Concurrency) -and
|
||||
(($TestToLog.Count -gt 0) -and
|
||||
(($Limit -lt 0) -or ($count -lt $Limit)))) {
|
||||
|
||||
|
||||
# We only need the first key
|
||||
foreach($key in $TestToLog.keys) {
|
||||
$k = $key
|
||||
break
|
||||
}
|
||||
|
||||
Write-Host "Starting $k"
|
||||
$log_path = -join ($LogFolder, ($TestToLog.$k))
|
||||
|
||||
if($Run -ceq "db_test") {
|
||||
$job = Start-Job -Name $k -ScriptBlock $InvokeTestCase -ArgumentList @($db_test,$k,$log_path)
|
||||
} else {
|
||||
[string]$Exe = -Join ($BinariesFolder, $k)
|
||||
$job = Start-Job -Name $k -ScriptBlock $InvokeTestAsync -ArgumentList @($exe,$log_path)
|
||||
}
|
||||
|
||||
$JobToLog.Add($job, $log_path)
|
||||
$TestToLog.Remove($k)
|
||||
|
||||
++$count
|
||||
}
|
||||
|
||||
if($JobToLog.Count -lt 1) {
|
||||
break
|
||||
}
|
||||
|
||||
$jobs = @()
|
||||
# Hash JobToLog
|
||||
$JobToLog = @{}
|
||||
foreach($k in $JobToLog.Keys) { $jobs += $k }
|
||||
|
||||
# Wait for all to finish and get the results
|
||||
while(($JobToLog.Count -gt 0) -or
|
||||
($TestToLog.Count -gt 0)) {
|
||||
$completed = Wait-Job -Job $jobs -Any
|
||||
$log = $JobToLog[$completed]
|
||||
$JobToLog.Remove($completed)
|
||||
|
||||
# Make sure we have maximum concurrent jobs running if anything
|
||||
# and the $Limit either not set or allows to proceed
|
||||
while(($JobToLog.Count -lt $ConcurrencyVal) -and
|
||||
(($TestToLog.Count -gt 0) -and
|
||||
(($Limit -lt 0) -or ($count -lt $Limit)))) {
|
||||
$message = -join @($completed.Name, " State: ", ($completed.State))
|
||||
|
||||
$log_content = @(Get-Content $log)
|
||||
|
||||
# We only need the first key
|
||||
foreach($key in $TestToLog.keys) {
|
||||
$k = $key
|
||||
if($completed.State -ne "Completed") {
|
||||
$success = $false
|
||||
Write-Warning $message
|
||||
$log_content | Write-Warning
|
||||
} else {
|
||||
# Scan the log. If we find PASSED and no occurence of FAILED
|
||||
# then it is a success
|
||||
[bool]$pass_found = $false
|
||||
ForEach($l in $log_content) {
|
||||
|
||||
if(($l -match "^\[\s+FAILED") -or
|
||||
($l -match "Assertion failed:")) {
|
||||
$pass_found = $false
|
||||
break
|
||||
}
|
||||
|
||||
Write-Host "Starting $k"
|
||||
$log_path = ($TestToLog.$k)
|
||||
|
||||
if($Run -ceq "db_test") {
|
||||
$job = Start-Job -Name $k -ScriptBlock $InvokeTestCase -ArgumentList @($db_test,$k,$log_path)
|
||||
} else {
|
||||
[string]$Exe = -Join ($BinariesFolder, $k)
|
||||
$job = Start-Job -Name $k -ScriptBlock $InvokeTestAsync -ArgumentList @($exe,$log_path)
|
||||
if(($l -match "^\[\s+PASSED") -or
|
||||
($l -match " : PASSED$") -or
|
||||
($l -match "^PASSED") -or
|
||||
($l -match "Passed all tests!") ) {
|
||||
$pass_found = $true
|
||||
}
|
||||
|
||||
$JobToLog.Add($job, $log_path)
|
||||
$TestToLog.Remove($k)
|
||||
|
||||
++$count
|
||||
}
|
||||
|
||||
if($JobToLog.Count -lt 1) {
|
||||
break
|
||||
}
|
||||
|
||||
$jobs = @()
|
||||
foreach($k in $JobToLog.Keys) { $jobs += $k }
|
||||
|
||||
$completed = Wait-Job -Job $jobs -Any
|
||||
$log = $JobToLog[$completed]
|
||||
$JobToLog.Remove($completed)
|
||||
|
||||
$message = -join @($completed.Name, " State: ", ($completed.State))
|
||||
|
||||
$log_content = @(Get-Content $log)
|
||||
|
||||
if($completed.State -ne "Completed") {
|
||||
$success = $false
|
||||
if(!$pass_found) {
|
||||
$success = $false;
|
||||
Write-Warning $message
|
||||
$log_content | Write-Warning
|
||||
} else {
|
||||
# Scan the log. If we find PASSED and no occurence of FAILED
|
||||
# then it is a success
|
||||
[bool]$pass_found = $false
|
||||
ForEach($l in $log_content) {
|
||||
|
||||
if(($l -match "^\[\s+FAILED") -or
|
||||
($l -match "Assertion failed:")) {
|
||||
$pass_found = $false
|
||||
break
|
||||
}
|
||||
|
||||
if(($l -match "^\[\s+PASSED") -or
|
||||
($l -match " : PASSED$") -or
|
||||
($l -match "^PASS$") -or # Special c_test case
|
||||
($l -match "Passed all tests!") ) {
|
||||
$pass_found = $true
|
||||
}
|
||||
}
|
||||
|
||||
if(!$pass_found) {
|
||||
$success = $false;
|
||||
Write-Warning $message
|
||||
$log_content | Write-Warning
|
||||
if($AddForRerun) {
|
||||
$Rerun.Add($completed.Name, $log)
|
||||
}
|
||||
} else {
|
||||
Write-Host $message
|
||||
}
|
||||
Write-Host $message
|
||||
}
|
||||
|
||||
# Remove cached job info from the system
|
||||
# Should be no output
|
||||
Receive-Job -Job $completed | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
RunJobs -TestToLog $TestsToRun -ConcurrencyVal $Concurrency -AddForRerun $EnableRerun
|
||||
|
||||
if($Rerun.Count -gt 0) {
|
||||
Write-Host "Rerunning " ($Rerun.Count) " tests sequentially"
|
||||
$success = $true
|
||||
$count = 0
|
||||
RunJobs -TestToLog $Rerun -ConcurrencyVal 1 -AddForRerun $false
|
||||
# Remove cached job info from the system
|
||||
# Should be no output
|
||||
Receive-Job -Job $completed | Out-Null
|
||||
}
|
||||
|
||||
Get-Date
|
||||
|
||||
|
||||
if(!$success) {
|
||||
# This does not succeed killing off jobs quick
|
||||
# So we simply exit
|
||||
|
||||
@@ -175,12 +175,6 @@ ColumnFamilyOptions SanitizeOptions(const DBOptions& db_options,
|
||||
result.level0_stop_writes_trigger = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
if (result.level0_file_num_compaction_trigger == 0) {
|
||||
Warn(db_options.info_log.get(),
|
||||
"level0_file_num_compaction_trigger cannot be 0");
|
||||
result.level0_file_num_compaction_trigger = 1;
|
||||
}
|
||||
|
||||
if (result.level0_stop_writes_trigger <
|
||||
result.level0_slowdown_writes_trigger ||
|
||||
result.level0_slowdown_writes_trigger <
|
||||
|
||||
@@ -57,7 +57,6 @@ class ColumnFamilyTest : public testing::Test {
|
||||
env_ = new EnvCounter(Env::Default());
|
||||
dbname_ = test::TmpDir() + "/column_family_test";
|
||||
db_options_.create_if_missing = true;
|
||||
db_options_.fail_if_options_file_error = true;
|
||||
db_options_.env = env_;
|
||||
DestroyDB(dbname_, Options(db_options_, column_family_options_));
|
||||
}
|
||||
@@ -68,9 +67,7 @@ class ColumnFamilyTest : public testing::Test {
|
||||
|
||||
void Close() {
|
||||
for (auto h : handles_) {
|
||||
if (h) {
|
||||
delete h;
|
||||
}
|
||||
delete h;
|
||||
}
|
||||
handles_.clear();
|
||||
names_.clear();
|
||||
@@ -722,7 +719,7 @@ TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) {
|
||||
two.max_write_buffer_number = 10;
|
||||
two.min_write_buffer_number_to_merge = 3;
|
||||
two.max_write_buffer_number_to_maintain = 2;
|
||||
three.write_buffer_size = 4096 * 22;
|
||||
three.write_buffer_size = 4096 * 22 + 2048;
|
||||
three.arena_block_size = 4096;
|
||||
three.max_write_buffer_number = 10;
|
||||
three.min_write_buffer_number_to_merge = 4;
|
||||
@@ -747,15 +744,15 @@ TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) {
|
||||
env_->SleepForMicroseconds(micros_wait_for_flush);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 2, 0});
|
||||
AssertCountLiveLogFiles(4);
|
||||
PutRandomData(3, 93, 990);
|
||||
PutRandomData(3, 91, 990);
|
||||
env_->SleepForMicroseconds(micros_wait_for_flush);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 2, 1});
|
||||
AssertCountLiveLogFiles(5);
|
||||
PutRandomData(3, 88, 990);
|
||||
PutRandomData(3, 90, 990);
|
||||
env_->SleepForMicroseconds(micros_wait_for_flush);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 2, 2});
|
||||
AssertCountLiveLogFiles(6);
|
||||
PutRandomData(3, 88, 990);
|
||||
PutRandomData(3, 90, 990);
|
||||
env_->SleepForMicroseconds(micros_wait_for_flush);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 2, 3});
|
||||
AssertCountLiveLogFiles(7);
|
||||
@@ -767,11 +764,11 @@ TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) {
|
||||
WaitForFlush(2);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 0, 3});
|
||||
AssertCountLiveLogFiles(9);
|
||||
PutRandomData(3, 88, 990);
|
||||
PutRandomData(3, 90, 990);
|
||||
WaitForFlush(3);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 0, 0});
|
||||
AssertCountLiveLogFiles(10);
|
||||
PutRandomData(3, 88, 990);
|
||||
PutRandomData(3, 90, 990);
|
||||
env_->SleepForMicroseconds(micros_wait_for_flush);
|
||||
AssertNumberOfImmutableMemtables({0, 1, 0, 1});
|
||||
AssertCountLiveLogFiles(11);
|
||||
@@ -779,9 +776,9 @@ TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) {
|
||||
WaitForFlush(1);
|
||||
AssertNumberOfImmutableMemtables({0, 0, 0, 1});
|
||||
AssertCountLiveLogFiles(5);
|
||||
PutRandomData(3, 88 * 3, 990);
|
||||
PutRandomData(3, 90 * 3, 990);
|
||||
WaitForFlush(3);
|
||||
PutRandomData(3, 88 * 4, 990);
|
||||
PutRandomData(3, 90 * 4, 990);
|
||||
WaitForFlush(3);
|
||||
AssertNumberOfImmutableMemtables({0, 0, 0, 0});
|
||||
AssertCountLiveLogFiles(12);
|
||||
@@ -1262,90 +1259,6 @@ TEST_F(ColumnFamilyTest, FlushAndDropRaceCondition) {
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
// skipped as persisting options is not supported in ROCKSDB_LITE
|
||||
namespace {
|
||||
std::atomic<int> test_stage(0);
|
||||
const int kMainThreadStartPersistingOptionsFile = 1;
|
||||
const int kChildThreadFinishDroppingColumnFamily = 2;
|
||||
const int kChildThreadWaitingMainThreadPersistOptions = 3;
|
||||
void DropSingleColumnFamily(ColumnFamilyTest* cf_test, int cf_id,
|
||||
std::vector<Comparator*>* comparators) {
|
||||
while (test_stage < kMainThreadStartPersistingOptionsFile) {
|
||||
Env::Default()->SleepForMicroseconds(100);
|
||||
}
|
||||
cf_test->DropColumnFamilies({cf_id});
|
||||
if ((*comparators)[cf_id]) {
|
||||
delete (*comparators)[cf_id];
|
||||
(*comparators)[cf_id] = nullptr;
|
||||
}
|
||||
test_stage = kChildThreadFinishDroppingColumnFamily;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_F(ColumnFamilyTest, CreateAndDropRace) {
|
||||
const int kCfCount = 5;
|
||||
std::vector<ColumnFamilyOptions> cf_opts;
|
||||
std::vector<Comparator*> comparators;
|
||||
for (int i = 0; i < kCfCount; ++i) {
|
||||
cf_opts.emplace_back();
|
||||
comparators.push_back(new test::SimpleSuffixReverseComparator());
|
||||
cf_opts.back().comparator = comparators.back();
|
||||
}
|
||||
db_options_.create_if_missing = true;
|
||||
db_options_.create_missing_column_families = true;
|
||||
|
||||
auto main_thread_id = std::this_thread::get_id();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack("PersistRocksDBOptions:start",
|
||||
[&](void* arg) {
|
||||
auto current_thread_id = std::this_thread::get_id();
|
||||
// If it's the main thread hitting this sync-point, then it
|
||||
// will be blocked until some other thread update the test_stage.
|
||||
if (main_thread_id == current_thread_id) {
|
||||
test_stage = kMainThreadStartPersistingOptionsFile;
|
||||
while (test_stage < kChildThreadFinishDroppingColumnFamily) {
|
||||
Env::Default()->SleepForMicroseconds(100);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"WriteThread::EnterUnbatched:Wait", [&](void* arg) {
|
||||
// This means a thread doing DropColumnFamily() is waiting for
|
||||
// other thread to finish persisting options.
|
||||
// In such case, we update the test_stage to unblock the main thread.
|
||||
test_stage = kChildThreadWaitingMainThreadPersistOptions;
|
||||
|
||||
// Note that based on the test setting, this must not be the
|
||||
// main thread.
|
||||
ASSERT_NE(main_thread_id, std::this_thread::get_id());
|
||||
});
|
||||
|
||||
// Create a database with four column families
|
||||
Open({"default", "one", "two", "three"},
|
||||
{cf_opts[0], cf_opts[1], cf_opts[2], cf_opts[3]});
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// Start a thread that will drop the first column family
|
||||
// and its comparator
|
||||
std::thread drop_cf_thread(DropSingleColumnFamily, this, 1, &comparators);
|
||||
|
||||
DropColumnFamilies({2});
|
||||
|
||||
drop_cf_thread.join();
|
||||
Close();
|
||||
Destroy();
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
for (auto* comparator : comparators) {
|
||||
if (comparator) {
|
||||
delete comparator;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/sync_point.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace rocksdb {
|
||||
@@ -54,62 +53,6 @@ class FlushedFileCollector : public EventListener {
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
TEST_F(CompactFilesTest, L0ConflictsFiles) {
|
||||
Options options;
|
||||
// to trigger compaction more easily
|
||||
const int kWriteBufferSize = 10000;
|
||||
const int kLevel0Trigger = 2;
|
||||
options.create_if_missing = true;
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
// Small slowdown and stop trigger for experimental purpose.
|
||||
options.level0_slowdown_writes_trigger = 20;
|
||||
options.level0_stop_writes_trigger = 20;
|
||||
options.level0_stop_writes_trigger = 20;
|
||||
options.write_buffer_size = kWriteBufferSize;
|
||||
options.level0_file_num_compaction_trigger = kLevel0Trigger;
|
||||
options.compression = kNoCompression;
|
||||
|
||||
DB* db = nullptr;
|
||||
DestroyDB(db_name_, options);
|
||||
Status s = DB::Open(options, db_name_, &db);
|
||||
assert(s.ok());
|
||||
assert(db);
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->LoadDependency({
|
||||
{"CompactFilesImpl:0", "BackgroundCallCompaction:0"},
|
||||
{"BackgroundCallCompaction:1", "CompactFilesImpl:1"},
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// create couple files
|
||||
// Background compaction starts and waits in BackgroundCallCompaction:0
|
||||
for (int i = 0; i < kLevel0Trigger * 4; ++i) {
|
||||
db->Put(WriteOptions(), ToString(i), "");
|
||||
db->Put(WriteOptions(), ToString(100 - i), "");
|
||||
db->Flush(FlushOptions());
|
||||
}
|
||||
|
||||
rocksdb::ColumnFamilyMetaData meta;
|
||||
db->GetColumnFamilyMetaData(&meta);
|
||||
std::string file1;
|
||||
for (auto& file : meta.levels[0].files) {
|
||||
ASSERT_EQ(0, meta.levels[0].level);
|
||||
if (file1 == "") {
|
||||
file1 = file.db_path + "/" + file.name;
|
||||
} else {
|
||||
std::string file2 = file.db_path + "/" + file.name;
|
||||
// Another thread starts a compact files and creates an L0 compaction
|
||||
// The background compaction then notices that there is an L0 compaction
|
||||
// already in progress and doesn't do an L0 compaction
|
||||
// Once the background compaction finishes, the compact files finishes
|
||||
ASSERT_OK(
|
||||
db->CompactFiles(rocksdb::CompactionOptions(), {file1, file2}, 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete db;
|
||||
}
|
||||
|
||||
TEST_F(CompactFilesTest, ObsoleteFiles) {
|
||||
Options options;
|
||||
// to trigger compaction more easily
|
||||
|
||||
@@ -42,11 +42,6 @@ CompactionIterator::CompactionIterator(
|
||||
earliest_snapshot_ = snapshots_->at(0);
|
||||
latest_snapshot_ = snapshots_->back();
|
||||
}
|
||||
if (compaction_filter_ != nullptr && compaction_filter_->IgnoreSnapshots()) {
|
||||
ignore_snapshots_ = true;
|
||||
} else {
|
||||
ignore_snapshots_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CompactionIterator::ResetRecordCounts() {
|
||||
@@ -145,8 +140,7 @@ void CompactionIterator::NextFromInput() {
|
||||
current_user_key_snapshot_ = 0;
|
||||
// apply the compaction filter to the first occurrence of the user key
|
||||
if (compaction_filter_ != nullptr && ikey_.type == kTypeValue &&
|
||||
(visible_at_tip_ || ikey_.sequence > latest_snapshot_ ||
|
||||
ignore_snapshots_)) {
|
||||
(visible_at_tip_ || ikey_.sequence > latest_snapshot_)) {
|
||||
// If the user has specified a compaction filter and the sequence
|
||||
// number is greater than any external snapshot, then invoke the
|
||||
// filter. If the return value of the compaction filter is true,
|
||||
@@ -176,9 +170,6 @@ void CompactionIterator::NextFromInput() {
|
||||
} else {
|
||||
// Update the current key to reflect the new sequence number/type without
|
||||
// copying the user key.
|
||||
// TODO(rven): Compaction filter does not process keys in this path
|
||||
// Need to have the compaction filter process multiple versions
|
||||
// if we have versions on both sides of a snapshot
|
||||
current_key_.UpdateInternalKey(ikey_.sequence, ikey_.type);
|
||||
key_ = current_key_.GetKey();
|
||||
ikey_.user_key = current_key_.GetUserKey();
|
||||
|
||||
@@ -98,7 +98,6 @@ class CompactionIterator {
|
||||
SequenceNumber visible_at_tip_;
|
||||
SequenceNumber earliest_snapshot_;
|
||||
SequenceNumber latest_snapshot_;
|
||||
bool ignore_snapshots_;
|
||||
|
||||
// State
|
||||
//
|
||||
|
||||
+4
-19
@@ -255,30 +255,16 @@ Compaction* CompactionPicker::FormCompaction(
|
||||
const CompactionOptions& compact_options,
|
||||
const std::vector<CompactionInputFiles>& input_files, int output_level,
|
||||
VersionStorageInfo* vstorage, const MutableCFOptions& mutable_cf_options,
|
||||
uint32_t output_path_id) {
|
||||
uint32_t output_path_id) const {
|
||||
uint64_t max_grandparent_overlap_bytes =
|
||||
output_level + 1 < vstorage->num_levels() ?
|
||||
mutable_cf_options.MaxGrandParentOverlapBytes(output_level + 1) :
|
||||
std::numeric_limits<uint64_t>::max();
|
||||
assert(input_files.size());
|
||||
|
||||
// TODO(rven ): we might be able to run concurrent level 0 compaction
|
||||
// if the key ranges of the two compactions do not overlap, but for now
|
||||
// we do not allow it.
|
||||
if ((input_files[0].level == 0) && !level0_compactions_in_progress_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto c = new Compaction(
|
||||
return new Compaction(
|
||||
vstorage, mutable_cf_options, input_files, output_level,
|
||||
compact_options.output_file_size_limit, max_grandparent_overlap_bytes,
|
||||
output_path_id, compact_options.compression, /* grandparents */ {}, true);
|
||||
|
||||
// If it's level 0 compaction, make sure we don't execute any other level 0
|
||||
// compactions in parallel
|
||||
if ((c != nullptr) && (input_files[0].level == 0)) {
|
||||
level0_compactions_in_progress_.insert(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
Status CompactionPicker::GetCompactionInputsFromFileNumbers(
|
||||
@@ -1248,9 +1234,8 @@ Compaction* UniversalCompactionPicker::PickCompaction(
|
||||
std::vector<SortedRun> sorted_runs =
|
||||
CalculateSortedRuns(*vstorage, ioptions_);
|
||||
|
||||
if (sorted_runs.size() == 0 ||
|
||||
sorted_runs.size() <
|
||||
(unsigned int)mutable_cf_options.level0_file_num_compaction_trigger) {
|
||||
if (sorted_runs.size() <
|
||||
(unsigned int)mutable_cf_options.level0_file_num_compaction_trigger) {
|
||||
LogToBuffer(log_buffer, "[%s] Universal: nothing to do\n", cf_name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class CompactionPicker {
|
||||
const CompactionOptions& compact_options,
|
||||
const std::vector<CompactionInputFiles>& input_files, int output_level,
|
||||
VersionStorageInfo* vstorage, const MutableCFOptions& mutable_cf_options,
|
||||
uint32_t output_path_id);
|
||||
uint32_t output_path_id) const;
|
||||
|
||||
// Converts a set of compaction input file numbers into
|
||||
// a list of CompactionInputFiles.
|
||||
|
||||
+2
-10
@@ -232,16 +232,8 @@ class CorruptionTest : public testing::Test {
|
||||
|
||||
// Return the value to associate with the specified key
|
||||
Slice Value(int k, std::string* storage) {
|
||||
if (k == 0) {
|
||||
// Ugh. Random seed of 0 used to produce no entropy. This code
|
||||
// preserves the implementation that was in place when all of the
|
||||
// magic values in this file were picked.
|
||||
*storage = std::string(kValueSize, ' ');
|
||||
return Slice(*storage);
|
||||
} else {
|
||||
Random r(k);
|
||||
return test::RandomString(&r, kValueSize, storage);
|
||||
}
|
||||
Random r(k);
|
||||
return test::RandomString(&r, kValueSize, storage);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-3
@@ -376,8 +376,8 @@ DEFINE_int32(compaction_readahead_size, 0, "Compaction readahead size");
|
||||
DEFINE_int32(random_access_max_buffer_size, 1024 * 1024,
|
||||
"Maximum windows randomaccess buffer size");
|
||||
|
||||
DEFINE_int32(writable_file_max_buffer_size, 1024 * 1024,
|
||||
"Maximum write buffer for Writable File");
|
||||
DEFINE_int32(writable_file_max_buffer_size, 1024 * 1024,
|
||||
"Maximum write buffer for Writeable File");
|
||||
|
||||
DEFINE_int32(skip_table_builder_flush, false, "Skip flushing block in "
|
||||
"table builder ");
|
||||
@@ -2448,7 +2448,7 @@ class Benchmark {
|
||||
block_based_options.block_size = FLAGS_block_size;
|
||||
block_based_options.block_restart_interval = FLAGS_block_restart_interval;
|
||||
block_based_options.filter_policy = filter_policy_;
|
||||
block_based_options.skip_table_builder_flush =
|
||||
block_based_options.skip_table_builder_flush =
|
||||
FLAGS_skip_table_builder_flush;
|
||||
block_based_options.format_version = 2;
|
||||
options.table_factory.reset(
|
||||
|
||||
@@ -47,24 +47,6 @@ class DeleteFilter : public CompactionFilter {
|
||||
virtual const char* Name() const override { return "DeleteFilter"; }
|
||||
};
|
||||
|
||||
class DeleteISFilter : public CompactionFilter {
|
||||
public:
|
||||
virtual bool Filter(int level, const Slice& key, const Slice& value,
|
||||
std::string* new_value,
|
||||
bool* value_changed) const override {
|
||||
cfilter_count++;
|
||||
int i = std::stoi(key.ToString());
|
||||
if (i > 5 && i <= 105) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IgnoreSnapshots() const override { return true; }
|
||||
|
||||
virtual const char* Name() const override { return "DeleteFilter"; }
|
||||
};
|
||||
|
||||
class DelayFilter : public CompactionFilter {
|
||||
public:
|
||||
explicit DelayFilter(DBTestBase* d) : db_test(d) {}
|
||||
@@ -159,21 +141,6 @@ class DeleteFilterFactory : public CompactionFilterFactory {
|
||||
virtual const char* Name() const override { return "DeleteFilterFactory"; }
|
||||
};
|
||||
|
||||
// Delete Filter Factory which ignores snapshots
|
||||
class DeleteISFilterFactory : public CompactionFilterFactory {
|
||||
public:
|
||||
virtual std::unique_ptr<CompactionFilter> CreateCompactionFilter(
|
||||
const CompactionFilter::Context& context) override {
|
||||
if (context.is_manual_compaction) {
|
||||
return std::unique_ptr<CompactionFilter>(new DeleteISFilter());
|
||||
} else {
|
||||
return std::unique_ptr<CompactionFilter>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char* Name() const override { return "DeleteFilterFactory"; }
|
||||
};
|
||||
|
||||
class DelayFilterFactory : public CompactionFilterFactory {
|
||||
public:
|
||||
explicit DelayFilterFactory(DBTestBase* d) : db_test(d) {}
|
||||
@@ -653,68 +620,6 @@ TEST_F(DBTestCompactionFilter, CompactionFilterSnapshot) {
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
ASSERT_EQ(0U, CountLiveFiles());
|
||||
}
|
||||
|
||||
// Compaction filters should only be applied to records that are newer than the
|
||||
// latest snapshot. However, if the compaction filter asks to ignore snapshots
|
||||
// records newer than the snapshot will also be processed
|
||||
TEST_F(DBTestCompactionFilter, CompactionFilterIgnoreSnapshot) {
|
||||
std::string five = ToString(5);
|
||||
Options options;
|
||||
options.compaction_filter_factory = std::make_shared<DeleteISFilterFactory>();
|
||||
options.disable_auto_compactions = true;
|
||||
options.create_if_missing = true;
|
||||
options = CurrentOptions(options);
|
||||
DestroyAndReopen(options);
|
||||
|
||||
// Put some data.
|
||||
const Snapshot* snapshot = nullptr;
|
||||
for (int table = 0; table < 4; ++table) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Put(ToString(table * 100 + i), "val");
|
||||
}
|
||||
Flush();
|
||||
|
||||
if (table == 0) {
|
||||
snapshot = db_->GetSnapshot();
|
||||
}
|
||||
}
|
||||
assert(snapshot != nullptr);
|
||||
|
||||
cfilter_count = 0;
|
||||
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||
// The filter should delete 40 records.
|
||||
ASSERT_EQ(40U, cfilter_count);
|
||||
|
||||
{
|
||||
// Scan the entire database as of the snapshot to ensure
|
||||
// that nothing is left
|
||||
ReadOptions read_options;
|
||||
read_options.snapshot = snapshot;
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
iter->SeekToFirst();
|
||||
int count = 0;
|
||||
while (iter->Valid()) {
|
||||
count++;
|
||||
iter->Next();
|
||||
}
|
||||
ASSERT_EQ(count, 6);
|
||||
read_options.snapshot = 0;
|
||||
std::unique_ptr<Iterator> iter1(db_->NewIterator(read_options));
|
||||
iter1->SeekToFirst();
|
||||
count = 0;
|
||||
while (iter1->Valid()) {
|
||||
count++;
|
||||
iter1->Next();
|
||||
}
|
||||
// We have deleted 10 keys from 40 using the compaction filter
|
||||
// Keys 6-9 before the snapshot and 100-105 after the snapshot
|
||||
ASSERT_EQ(count, 30);
|
||||
}
|
||||
|
||||
// Release the snapshot and compact again -> now all records should be
|
||||
// removed.
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -239,12 +239,9 @@ TEST_F(DBCompactionTest, SkipStatsUpdateTest) {
|
||||
env_->random_file_open_counter_.store(0);
|
||||
Reopen(options);
|
||||
|
||||
// As stats-update is disabled, we expect a very low number of
|
||||
// random file open.
|
||||
// Note that this number must be changed accordingly if we change
|
||||
// the number of files needed to be opened in the DB::Open process.
|
||||
const int kMaxFileOpenCount = 10;
|
||||
ASSERT_LT(env_->random_file_open_counter_.load(), kMaxFileOpenCount);
|
||||
// As stats-update is disabled, we expect a very low
|
||||
// number of random file open.
|
||||
ASSERT_LT(env_->random_file_open_counter_.load(), 5);
|
||||
|
||||
// Repeat the reopen process, but this time we enable
|
||||
// stats-update.
|
||||
@@ -254,7 +251,7 @@ TEST_F(DBCompactionTest, SkipStatsUpdateTest) {
|
||||
|
||||
// Since we do a normal stats update on db-open, there
|
||||
// will be more random open files.
|
||||
ASSERT_GT(env_->random_file_open_counter_.load(), kMaxFileOpenCount);
|
||||
ASSERT_GT(env_->random_file_open_counter_.load(), 5);
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, TestTableReaderForCompaction) {
|
||||
@@ -461,15 +458,12 @@ TEST_F(DBCompactionTest, DisableStatsUpdateReopen) {
|
||||
|
||||
|
||||
TEST_P(DBCompactionTestWithParam, CompactionTrigger) {
|
||||
const int kNumKeysPerFile = 100;
|
||||
|
||||
Options options;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
options.num_levels = 3;
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
options.max_subcompactions = max_subcompactions_;
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(kNumKeysPerFile));
|
||||
options = CurrentOptions(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
@@ -479,24 +473,20 @@ TEST_P(DBCompactionTestWithParam, CompactionTrigger) {
|
||||
num++) {
|
||||
std::vector<std::string> values;
|
||||
// Write 100KB (100 values, each 1K)
|
||||
for (int i = 0; i < kNumKeysPerFile; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
values.push_back(RandomString(&rnd, 990));
|
||||
ASSERT_OK(Put(1, Key(i), values[i]));
|
||||
}
|
||||
// put extra key to trigger flush
|
||||
ASSERT_OK(Put(1, "", ""));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), num + 1);
|
||||
}
|
||||
|
||||
// generate one more file in level-0, and should trigger level-0 compaction
|
||||
std::vector<std::string> values;
|
||||
for (int i = 0; i < kNumKeysPerFile; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
values.push_back(RandomString(&rnd, 990));
|
||||
ASSERT_OK(Put(1, Key(i), values[i]));
|
||||
}
|
||||
// put extra key to trigger flush
|
||||
ASSERT_OK(Put(1, "", ""));
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
|
||||
@@ -856,8 +846,6 @@ TEST_P(DBCompactionTestWithParam, LevelCompactionThirdPath) {
|
||||
options.db_paths.emplace_back(dbname_, 500 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 4 * 1024 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -973,8 +961,6 @@ TEST_P(DBCompactionTestWithParam, LevelCompactionPathUse) {
|
||||
options.db_paths.emplace_back(dbname_, 500 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 4 * 1024 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -1615,8 +1601,6 @@ TEST_P(DBCompactionTestWithParam, CompressLevelCompaction) {
|
||||
return;
|
||||
}
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.write_buffer_size = 110 << 10; // 110KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
|
||||
+46
-286
@@ -19,7 +19,6 @@
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -85,8 +84,6 @@
|
||||
#include "util/log_buffer.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include "util/options_helper.h"
|
||||
#include "util/options_parser.h"
|
||||
#include "util/perf_context_imp.h"
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/string_util.h"
|
||||
@@ -737,12 +734,8 @@ void DBImpl::PurgeObsoleteFiles(const JobContext& state) {
|
||||
// Also, SetCurrentFile creates a temp file when writing out new
|
||||
// manifest, which is equal to state.pending_manifest_file_number. We
|
||||
// should not delete that file
|
||||
//
|
||||
// TODO(yhchiang): carefully modify the third condition to safely
|
||||
// remove the temp options files.
|
||||
keep = (sst_live_map.find(number) != sst_live_map.end()) ||
|
||||
(number == state.pending_manifest_file_number) ||
|
||||
(to_delete.find(kOptionsFileNamePrefix) != std::string::npos);
|
||||
(number == state.pending_manifest_file_number);
|
||||
break;
|
||||
case kInfoLogFile:
|
||||
keep = true;
|
||||
@@ -754,7 +747,6 @@ void DBImpl::PurgeObsoleteFiles(const JobContext& state) {
|
||||
case kDBLockFile:
|
||||
case kIdentityFile:
|
||||
case kMetaDatabase:
|
||||
case kOptionsFile:
|
||||
keep = true;
|
||||
break;
|
||||
}
|
||||
@@ -1772,9 +1764,7 @@ Status DBImpl::CompactFilesImpl(
|
||||
c.reset(cfd->compaction_picker()->FormCompaction(
|
||||
compact_options, input_files, output_level, version->storage_info(),
|
||||
*cfd->GetLatestMutableCFOptions(), output_path_id));
|
||||
if (!c) {
|
||||
return Status::Aborted("Another Level 0 compaction is running");
|
||||
}
|
||||
assert(c);
|
||||
c->SetInputVersion(version);
|
||||
// deletion compaction currently not allowed in CompactFiles.
|
||||
assert(!c->deletion_compaction());
|
||||
@@ -1803,8 +1793,6 @@ Status DBImpl::CompactFilesImpl(
|
||||
compaction_job.Prepare();
|
||||
|
||||
mutex_.Unlock();
|
||||
TEST_SYNC_POINT("CompactFilesImpl:0");
|
||||
TEST_SYNC_POINT("CompactFilesImpl:1");
|
||||
compaction_job.Run();
|
||||
mutex_.Lock();
|
||||
|
||||
@@ -1850,9 +1838,6 @@ Status DBImpl::PauseBackgroundWork() {
|
||||
|
||||
Status DBImpl::ContinueBackgroundWork() {
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
if (bg_work_paused_ == 0) {
|
||||
return Status::InvalidArgument();
|
||||
}
|
||||
assert(bg_work_paused_ > 0);
|
||||
bg_work_paused_--;
|
||||
if (bg_work_paused_ == 0) {
|
||||
@@ -1930,22 +1915,12 @@ Status DBImpl::SetOptions(ColumnFamilyHandle* column_family,
|
||||
|
||||
MutableCFOptions new_options;
|
||||
Status s;
|
||||
Status persist_options_status;
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
s = cfd->SetOptions(options_map);
|
||||
if (s.ok()) {
|
||||
new_options = *cfd->GetLatestMutableCFOptions();
|
||||
}
|
||||
if (s.ok()) {
|
||||
// Persist RocksDB options under the single write thread
|
||||
WriteThread::Writer w;
|
||||
write_thread_.EnterUnbatched(&w, &mutex_);
|
||||
|
||||
persist_options_status = WriteOptionsFile();
|
||||
|
||||
write_thread_.ExitUnbatched(&w);
|
||||
}
|
||||
}
|
||||
|
||||
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
|
||||
@@ -1960,16 +1935,6 @@ Status DBImpl::SetOptions(ColumnFamilyHandle* column_family,
|
||||
db_options_.info_log, "[%s] SetOptions succeeded",
|
||||
cfd->GetName().c_str());
|
||||
new_options.Dump(db_options_.info_log.get());
|
||||
if (!persist_options_status.ok()) {
|
||||
if (db_options_.fail_if_options_file_error) {
|
||||
s = Status::IOError(
|
||||
"SetOptions succeeded, but unable to persist options",
|
||||
persist_options_status.ToString());
|
||||
}
|
||||
Warn(db_options_.info_log,
|
||||
"Unable to persist options in SetOptions() -- %s",
|
||||
persist_options_status.ToString().c_str());
|
||||
}
|
||||
} else {
|
||||
Log(InfoLogLevel::WARN_LEVEL, db_options_.info_log,
|
||||
"[%s] SetOptions failed", cfd->GetName().c_str());
|
||||
@@ -2341,24 +2306,6 @@ Status DBImpl::WaitForFlushMemTable(ColumnFamilyData* cfd) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Status DBImpl::EnableAutoCompaction(
|
||||
const std::vector<ColumnFamilyHandle*>& column_family_handles) {
|
||||
Status s;
|
||||
for (auto cf_ptr : column_family_handles) {
|
||||
// check options here, enable only if didn't initially disable
|
||||
if (s.ok()) {
|
||||
s = this->SetOptions(cf_ptr, {{"disable_auto_compactions", "false"}});
|
||||
}
|
||||
}
|
||||
|
||||
if (s.ok()) {
|
||||
InstrumentedMutexLock guard_lock(&mutex_);
|
||||
MaybeScheduleFlushOrCompaction();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void DBImpl::MaybeScheduleFlushOrCompaction() {
|
||||
mutex_.AssertHeld();
|
||||
if (!opened_successfully_) {
|
||||
@@ -2591,7 +2538,7 @@ void DBImpl::BackgroundCallFlush() {
|
||||
void DBImpl::BackgroundCallCompaction() {
|
||||
bool made_progress = false;
|
||||
JobContext job_context(next_job_id_.fetch_add(1), true);
|
||||
TEST_SYNC_POINT("BackgroundCallCompaction:0");
|
||||
|
||||
MaybeDumpStats();
|
||||
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, db_options_.info_log.get());
|
||||
{
|
||||
@@ -2603,7 +2550,6 @@ void DBImpl::BackgroundCallCompaction() {
|
||||
|
||||
assert(bg_compaction_scheduled_);
|
||||
Status s = BackgroundCompaction(&made_progress, &job_context, &log_buffer);
|
||||
TEST_SYNC_POINT("BackgroundCallCompaction:1");
|
||||
if (!s.ok() && !s.IsShutdownInProgress()) {
|
||||
// Wait a little bit before retrying background compaction in
|
||||
// case this is an environmental problem and we do not want to
|
||||
@@ -3453,7 +3399,6 @@ Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& cf_options,
|
||||
const std::string& column_family_name,
|
||||
ColumnFamilyHandle** handle) {
|
||||
Status s;
|
||||
Status persist_options_status;
|
||||
*handle = nullptr;
|
||||
|
||||
s = CheckCompressionSupported(cf_options);
|
||||
@@ -3486,12 +3431,6 @@ Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& cf_options,
|
||||
s = versions_->LogAndApply(
|
||||
nullptr, MutableCFOptions(opt, ImmutableCFOptions(opt)), &edit,
|
||||
&mutex_, directories_.GetDbDir(), false, &cf_options);
|
||||
|
||||
if (s.ok()) {
|
||||
// If the column family was created successfully, we then persist
|
||||
// the updated RocksDB options under the same single write thread
|
||||
persist_options_status = WriteOptionsFile();
|
||||
}
|
||||
write_thread_.ExitUnbatched(&w);
|
||||
}
|
||||
if (s.ok()) {
|
||||
@@ -3521,17 +3460,6 @@ Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& cf_options,
|
||||
if (s.ok()) {
|
||||
NewThreadStatusCfInfo(
|
||||
reinterpret_cast<ColumnFamilyHandleImpl*>(*handle)->cfd());
|
||||
if (!persist_options_status.ok()) {
|
||||
if (db_options_.fail_if_options_file_error) {
|
||||
s = Status::IOError(
|
||||
"ColumnFamily has been created, but unable to persist"
|
||||
"options in CreateColumnFamily()",
|
||||
persist_options_status.ToString().c_str());
|
||||
}
|
||||
Warn(db_options_.info_log,
|
||||
"Unable to persist options in CreateColumnFamily() -- %s",
|
||||
persist_options_status.ToString().c_str());
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -3550,7 +3478,6 @@ Status DBImpl::DropColumnFamily(ColumnFamilyHandle* column_family) {
|
||||
edit.SetColumnFamily(cfd->GetID());
|
||||
|
||||
Status s;
|
||||
Status options_persist_status;
|
||||
{
|
||||
InstrumentedMutexLock l(&mutex_);
|
||||
if (cfd->IsDropped()) {
|
||||
@@ -3562,11 +3489,6 @@ Status DBImpl::DropColumnFamily(ColumnFamilyHandle* column_family) {
|
||||
write_thread_.EnterUnbatched(&w, &mutex_);
|
||||
s = versions_->LogAndApply(cfd, *cfd->GetLatestMutableCFOptions(),
|
||||
&edit, &mutex_);
|
||||
if (s.ok()) {
|
||||
// If the column family was dropped successfully, we then persist
|
||||
// the updated RocksDB options under the same single write thread
|
||||
options_persist_status = WriteOptionsFile();
|
||||
}
|
||||
write_thread_.ExitUnbatched(&w);
|
||||
}
|
||||
|
||||
@@ -3594,19 +3516,8 @@ Status DBImpl::DropColumnFamily(ColumnFamilyHandle* column_family) {
|
||||
max_total_in_memory_state_ -= mutable_cf_options->write_buffer_size *
|
||||
mutable_cf_options->max_write_buffer_number;
|
||||
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
|
||||
"Dropped column family with id %u\n", cfd->GetID());
|
||||
|
||||
if (!options_persist_status.ok()) {
|
||||
if (db_options_.fail_if_options_file_error) {
|
||||
s = Status::IOError(
|
||||
"ColumnFamily has been dropped, but unable to persist "
|
||||
"options in DropColumnFamily()",
|
||||
options_persist_status.ToString().c_str());
|
||||
}
|
||||
Warn(db_options_.info_log,
|
||||
"Unable to persist options in DropColumnFamily() -- %s",
|
||||
options_persist_status.ToString().c_str());
|
||||
}
|
||||
"Dropped column family with id %u\n",
|
||||
cfd->GetID());
|
||||
} else {
|
||||
Log(InfoLogLevel::ERROR_LEVEL, db_options_.info_log,
|
||||
"Dropping column family with id %u FAILED -- %s\n",
|
||||
@@ -3956,36 +3867,25 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
MaybeScheduleFlushOrCompaction();
|
||||
} else if (UNLIKELY(write_buffer_.ShouldFlush())) {
|
||||
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
|
||||
"Flushing column family with largest mem table size. Write buffer is "
|
||||
"using %" PRIu64 " bytes out of a total of %" PRIu64 ".",
|
||||
"Flushing all column families. Write buffer is using %" PRIu64
|
||||
" bytes out of a total of %" PRIu64 ".",
|
||||
write_buffer_.memory_usage(), write_buffer_.buffer_size());
|
||||
// no need to refcount because drop is happening in write thread, so can't
|
||||
// happen while we're in the write thread
|
||||
ColumnFamilyData* largest_cfd = nullptr;
|
||||
size_t largest_cfd_size = 0;
|
||||
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
if (cfd->IsDropped()) {
|
||||
continue;
|
||||
}
|
||||
if (!cfd->mem()->IsEmpty()) {
|
||||
// We only consider active mem table, hoping immutable memtable is
|
||||
// already in the process of flushing.
|
||||
size_t cfd_size = cfd->mem()->ApproximateMemoryUsage();
|
||||
if (largest_cfd == nullptr || cfd_size > largest_cfd_size) {
|
||||
largest_cfd = cfd;
|
||||
largest_cfd_size = cfd_size;
|
||||
status = SwitchMemtable(cfd, &context);
|
||||
if (!status.ok()) {
|
||||
break;
|
||||
}
|
||||
cfd->imm()->FlushRequested();
|
||||
SchedulePendingFlush(cfd);
|
||||
}
|
||||
}
|
||||
if (largest_cfd != nullptr) {
|
||||
status = SwitchMemtable(largest_cfd, &context);
|
||||
if (status.ok()) {
|
||||
largest_cfd->imm()->FlushRequested();
|
||||
SchedulePendingFlush(largest_cfd);
|
||||
MaybeScheduleFlushOrCompaction();
|
||||
}
|
||||
}
|
||||
MaybeScheduleFlushOrCompaction();
|
||||
}
|
||||
|
||||
if (UNLIKELY(status.ok() && !bg_error_.ok())) {
|
||||
@@ -4048,48 +3948,33 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
// At this point the mutex is unlocked
|
||||
|
||||
if (status.ok()) {
|
||||
int total_count = 0;
|
||||
uint64_t total_byte_size = 0;
|
||||
for (auto b : write_batch_group) {
|
||||
total_count += WriteBatchInternal::Count(b);
|
||||
total_byte_size = WriteBatchInternal::AppendedByteSize(
|
||||
total_byte_size, WriteBatchInternal::ByteSize(b));
|
||||
WriteBatch* updates = nullptr;
|
||||
if (write_batch_group.size() == 1) {
|
||||
updates = write_batch_group[0];
|
||||
} else {
|
||||
updates = &tmp_batch_;
|
||||
for (size_t i = 0; i < write_batch_group.size(); ++i) {
|
||||
WriteBatchInternal::Append(updates, write_batch_group[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const SequenceNumber current_sequence = last_sequence + 1;
|
||||
last_sequence += total_count;
|
||||
|
||||
WriteBatchInternal::SetSequence(updates, current_sequence);
|
||||
int my_batch_count = WriteBatchInternal::Count(updates);
|
||||
last_sequence += my_batch_count;
|
||||
const uint64_t batch_size = WriteBatchInternal::ByteSize(updates);
|
||||
// Record statistics
|
||||
RecordTick(stats_, NUMBER_KEYS_WRITTEN, total_count);
|
||||
RecordTick(stats_, BYTES_WRITTEN, total_byte_size);
|
||||
PERF_TIMER_STOP(write_pre_and_post_process_time);
|
||||
|
||||
RecordTick(stats_, NUMBER_KEYS_WRITTEN, my_batch_count);
|
||||
RecordTick(stats_, BYTES_WRITTEN, batch_size);
|
||||
if (write_options.disableWAL) {
|
||||
flush_on_destroy_ = true;
|
||||
}
|
||||
PERF_TIMER_STOP(write_pre_and_post_process_time);
|
||||
|
||||
uint64_t log_size = 0;
|
||||
if (!write_options.disableWAL) {
|
||||
PERF_TIMER_GUARD(write_wal_time);
|
||||
|
||||
WriteBatch* merged_batch = nullptr;
|
||||
if (write_batch_group.size() == 1) {
|
||||
merged_batch = write_batch_group[0];
|
||||
} else {
|
||||
// WAL needs all of the batches flattened into a single batch.
|
||||
// We could avoid copying here with an iov-like AddRecord
|
||||
// interface
|
||||
merged_batch = &tmp_batch_;
|
||||
for (auto b : write_batch_group) {
|
||||
WriteBatchInternal::Append(merged_batch, b);
|
||||
}
|
||||
}
|
||||
WriteBatchInternal::SetSequence(merged_batch, current_sequence);
|
||||
|
||||
assert(WriteBatchInternal::Count(merged_batch) == total_count);
|
||||
assert(WriteBatchInternal::ByteSize(merged_batch) == total_byte_size);
|
||||
|
||||
Slice log_entry = WriteBatchInternal::Contents(merged_batch);
|
||||
Slice log_entry = WriteBatchInternal::Contents(updates);
|
||||
status = logs_.back().writer->AddRecord(log_entry);
|
||||
total_log_size_ += log_entry.size();
|
||||
alive_log_files_.back().AddSize(log_entry.size());
|
||||
@@ -4119,41 +4004,34 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
|
||||
status = directories_.GetWalDir()->Fsync();
|
||||
}
|
||||
}
|
||||
|
||||
if (merged_batch == &tmp_batch_) {
|
||||
tmp_batch_.Clear();
|
||||
}
|
||||
}
|
||||
if (status.ok()) {
|
||||
PERF_TIMER_GUARD(write_memtable_time);
|
||||
|
||||
status = WriteBatchInternal::InsertInto(
|
||||
write_batch_group, current_sequence, column_family_memtables_.get(),
|
||||
write_options.ignore_missing_column_families,
|
||||
/*log_number*/ 0, this, /*dont_filter_deletes*/ false);
|
||||
|
||||
// A non-OK status here indicates that the state implied by the
|
||||
// WAL has diverged from the in-memory state. This could be
|
||||
// because of a corrupt write_batch (very bad), or because the
|
||||
// client specified an invalid column family and didn't specify
|
||||
// ignore_missing_column_families.
|
||||
updates, column_family_memtables_.get(),
|
||||
write_options.ignore_missing_column_families, 0, this, false);
|
||||
// A non-OK status here indicates iteration failure (either in-memory
|
||||
// writebatch corruption (very bad), or the client specified invalid
|
||||
// column family). This will later on trigger bg_error_.
|
||||
//
|
||||
// Is setting bg_error_ enough here? This will at least stop
|
||||
// compaction and fail any further writes.
|
||||
if (!status.ok() && bg_error_.ok()) {
|
||||
bg_error_ = status;
|
||||
}
|
||||
// Note that existing logic was not sound. Any partial failure writing
|
||||
// into the memtable would result in a state that some write ops might
|
||||
// have succeeded in memtable but Status reports error for all writes.
|
||||
|
||||
SetTickerCount(stats_, SEQUENCE_NUMBER, last_sequence);
|
||||
}
|
||||
PERF_TIMER_START(write_pre_and_post_process_time);
|
||||
if (updates == &tmp_batch_) {
|
||||
tmp_batch_.Clear();
|
||||
}
|
||||
mutex_.Lock();
|
||||
|
||||
// internal stats
|
||||
default_cf_internal_stats_->AddDBStats(InternalStats::BYTES_WRITTEN,
|
||||
total_byte_size);
|
||||
default_cf_internal_stats_->AddDBStats(
|
||||
InternalStats::BYTES_WRITTEN, batch_size);
|
||||
default_cf_internal_stats_->AddDBStats(InternalStats::NUMBER_KEYS_WRITTEN,
|
||||
total_count);
|
||||
my_batch_count);
|
||||
if (!write_options.disableWAL) {
|
||||
if (write_options.sync) {
|
||||
default_cf_internal_stats_->AddDBStats(InternalStats::WAL_FILE_SYNCED,
|
||||
@@ -5042,13 +4920,7 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
}
|
||||
}
|
||||
TEST_SYNC_POINT("DBImpl::Open:Opened");
|
||||
Status persist_options_status;
|
||||
if (s.ok()) {
|
||||
// Persist RocksDB Options before scheduling the compaction.
|
||||
// The WriteOptionsFile() will release and lock the mutex internally.
|
||||
persist_options_status = impl->WriteOptionsFile();
|
||||
|
||||
*dbptr = impl;
|
||||
impl->opened_successfully_ = true;
|
||||
impl->MaybeScheduleFlushOrCompaction();
|
||||
}
|
||||
@@ -5058,24 +4930,14 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
|
||||
Log(InfoLogLevel::INFO_LEVEL, impl->db_options_.info_log, "DB pointer %p",
|
||||
impl);
|
||||
LogFlush(impl->db_options_.info_log);
|
||||
if (!persist_options_status.ok()) {
|
||||
if (db_options.fail_if_options_file_error) {
|
||||
s = Status::IOError(
|
||||
"DB::Open() failed --- Unable to persist Options file",
|
||||
persist_options_status.ToString());
|
||||
}
|
||||
Warn(impl->db_options_.info_log,
|
||||
"Unable to persist options in DB::Open() -- %s",
|
||||
persist_options_status.ToString().c_str());
|
||||
}
|
||||
}
|
||||
if (!s.ok()) {
|
||||
|
||||
*dbptr = impl;
|
||||
} else {
|
||||
for (auto* h : *handles) {
|
||||
delete h;
|
||||
}
|
||||
handles->clear();
|
||||
delete impl;
|
||||
*dbptr = nullptr;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -5172,7 +5034,6 @@ Status DestroyDB(const std::string& dbname, const Options& options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ignore case where no archival directory is present.
|
||||
env->DeleteDir(archivedir);
|
||||
|
||||
@@ -5184,107 +5045,6 @@ Status DestroyDB(const std::string& dbname, const Options& options) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Status DBImpl::WriteOptionsFile() {
|
||||
#ifndef ROCKSDB_LITE
|
||||
mutex_.AssertHeld();
|
||||
|
||||
std::vector<std::string> cf_names;
|
||||
std::vector<ColumnFamilyOptions> cf_opts;
|
||||
|
||||
// This part requires mutex to protect the column family options
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
if (cfd->IsDropped()) {
|
||||
continue;
|
||||
}
|
||||
cf_names.push_back(cfd->GetName());
|
||||
cf_opts.push_back(BuildColumnFamilyOptions(
|
||||
*cfd->options(), *cfd->GetLatestMutableCFOptions()));
|
||||
}
|
||||
|
||||
// Unlock during expensive operations. New writes cannot get here
|
||||
// because the single write thread ensures all new writes get queued.
|
||||
mutex_.Unlock();
|
||||
|
||||
std::string file_name =
|
||||
TempOptionsFileName(GetName(), versions_->NewFileNumber());
|
||||
Status s = PersistRocksDBOptions(GetDBOptions(), cf_names, cf_opts, file_name,
|
||||
GetEnv());
|
||||
|
||||
if (s.ok()) {
|
||||
s = RenameTempFileToOptionsFile(file_name);
|
||||
}
|
||||
mutex_.Lock();
|
||||
return s;
|
||||
#else
|
||||
return Status::OK();
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
namespace {
|
||||
void DeleteOptionsFilesHelper(const std::map<uint64_t, std::string>& filenames,
|
||||
const size_t num_files_to_keep,
|
||||
const std::shared_ptr<Logger>& info_log,
|
||||
Env* env) {
|
||||
if (filenames.size() <= num_files_to_keep) {
|
||||
return;
|
||||
}
|
||||
for (auto iter = std::next(filenames.begin(), num_files_to_keep);
|
||||
iter != filenames.end(); ++iter) {
|
||||
if (!env->DeleteFile(iter->second).ok()) {
|
||||
Warn(info_log, "Unable to delete options file %s", iter->second.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
Status DBImpl::DeleteObsoleteOptionsFiles() {
|
||||
#ifndef ROCKSDB_LITE
|
||||
std::vector<std::string> filenames;
|
||||
// use ordered map to store keep the filenames sorted from the newest
|
||||
// to the oldest.
|
||||
std::map<uint64_t, std::string> options_filenames;
|
||||
Status s;
|
||||
s = GetEnv()->GetChildren(GetName(), &filenames);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
for (auto& filename : filenames) {
|
||||
uint64_t file_number;
|
||||
FileType type;
|
||||
if (ParseFileName(filename, &file_number, &type) && type == kOptionsFile) {
|
||||
options_filenames.insert(
|
||||
{std::numeric_limits<uint64_t>::max() - file_number,
|
||||
GetName() + "/" + filename});
|
||||
}
|
||||
}
|
||||
|
||||
// Keeps the latest 2 Options file
|
||||
const size_t kNumOptionsFilesKept = 2;
|
||||
DeleteOptionsFilesHelper(options_filenames, kNumOptionsFilesKept,
|
||||
db_options_.info_log, GetEnv());
|
||||
return Status::OK();
|
||||
#else
|
||||
return Status::OK();
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
Status DBImpl::RenameTempFileToOptionsFile(const std::string& file_name) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
Status s;
|
||||
std::string options_file_name =
|
||||
OptionsFileName(GetName(), versions_->NewFileNumber());
|
||||
// Retry if the file name happen to conflict with an existing one.
|
||||
s = GetEnv()->RenameFile(file_name, options_file_name);
|
||||
|
||||
DeleteObsoleteOptionsFiles();
|
||||
return s;
|
||||
#else
|
||||
return Status::OK();
|
||||
#endif // !ROCKSDB_LITE
|
||||
}
|
||||
|
||||
#if ROCKSDB_USING_THREAD_STATUS
|
||||
|
||||
void DBImpl::NewThreadStatusCfInfo(
|
||||
|
||||
@@ -144,9 +144,6 @@ class DBImpl : public DB {
|
||||
virtual Status PauseBackgroundWork() override;
|
||||
virtual Status ContinueBackgroundWork() override;
|
||||
|
||||
virtual Status EnableAutoCompaction(
|
||||
const std::vector<ColumnFamilyHandle*>& column_family_handles) override;
|
||||
|
||||
using DB::SetOptions;
|
||||
Status SetOptions(
|
||||
ColumnFamilyHandle* column_family,
|
||||
@@ -317,10 +314,6 @@ class DBImpl : public DB {
|
||||
|
||||
Cache* TEST_table_cache() { return table_cache_.get(); }
|
||||
|
||||
const WriteController& TEST_write_controler() const {
|
||||
return write_controller_;
|
||||
}
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
// Returns the list of live files in 'live' and the list
|
||||
@@ -405,17 +398,6 @@ class DBImpl : public DB {
|
||||
SuperVersion* super_version,
|
||||
Arena* arena);
|
||||
|
||||
// Except in DB::Open(), WriteOptionsFile can only be called when:
|
||||
// 1. WriteThread::Writer::EnterUnbatched() is used.
|
||||
// 2. db_mutex is held
|
||||
Status WriteOptionsFile();
|
||||
|
||||
// The following two functions can only be called when:
|
||||
// 1. WriteThread::Writer::EnterUnbatched() is used.
|
||||
// 2. db_mutex is NOT held
|
||||
Status RenameTempFileToOptionsFile(const std::string& file_name);
|
||||
Status DeleteObsoleteOptionsFiles();
|
||||
|
||||
void NotifyOnFlushCompleted(ColumnFamilyData* cfd, FileMetaData* file_meta,
|
||||
const MutableCFOptions& mutable_cf_options,
|
||||
int job_id, TableProperties prop);
|
||||
@@ -570,13 +552,8 @@ class DBImpl : public DB {
|
||||
// Lock over the persistent DB state. Non-nullptr iff successfully acquired.
|
||||
FileLock* db_lock_;
|
||||
|
||||
// The mutex for options file related operations.
|
||||
// NOTE: should never acquire options_file_mutex_ and mutex_ at the
|
||||
// same time.
|
||||
InstrumentedMutex options_files_mutex_;
|
||||
// State below is protected by mutex_
|
||||
InstrumentedMutex mutex_;
|
||||
|
||||
std::atomic<bool> shutting_down_;
|
||||
// This condition variable is signaled on these conditions:
|
||||
// * whenever bg_compaction_scheduled_ goes down to 0
|
||||
|
||||
+1
-10
@@ -186,18 +186,9 @@ void DBIter::Next() {
|
||||
if (!iter_->Valid()) {
|
||||
iter_->SeekToFirst();
|
||||
}
|
||||
} else if (iter_->Valid() && !current_entry_is_merged_) {
|
||||
// If the current value is not a merge, the iter position is the
|
||||
// current key, which is already returned. We can safely issue a
|
||||
// Next() without checking the current key.
|
||||
// If the current key is a merge, very likely iter already points
|
||||
// to the next internal position.
|
||||
iter_->Next();
|
||||
PERF_COUNTER_ADD(internal_key_skipped_count, 1);
|
||||
}
|
||||
|
||||
// Now we point to the next internal position, for both of merge and
|
||||
// not merge cases.
|
||||
// If the current value is merged, we might already hit end of iter_
|
||||
if (!iter_->Valid()) {
|
||||
valid_ = false;
|
||||
return;
|
||||
|
||||
@@ -92,10 +92,6 @@ TablePropertiesCollection
|
||||
DBTablePropertiesTest::TestGetPropertiesOfTablesInRange(
|
||||
std::vector<Range> ranges, std::size_t* num_properties,
|
||||
std::size_t* num_files) {
|
||||
|
||||
// Since we deref zero element in the vector it can not be empty
|
||||
// otherwise we pass an address to some random memory
|
||||
EXPECT_GT(ranges.size(), 0U);
|
||||
// run the query
|
||||
TablePropertiesCollection props;
|
||||
EXPECT_OK(db_->GetPropertiesOfTablesInRange(
|
||||
@@ -105,10 +101,10 @@ DBTablePropertiesTest::TestGetPropertiesOfTablesInRange(
|
||||
// only which fall within requested ranges
|
||||
std::vector<LiveFileMetaData> vmd;
|
||||
db_->GetLiveFilesMetaData(&vmd);
|
||||
for (auto& md : vmd) {
|
||||
for (auto md : vmd) {
|
||||
std::string fn = md.db_path + md.name;
|
||||
bool in_range = false;
|
||||
for (auto& r : ranges) {
|
||||
for (auto r : ranges) {
|
||||
// smallestkey < limit && largestkey >= start
|
||||
if (r.limit.compare(md.smallestkey) >= 0 &&
|
||||
r.start.compare(md.largestkey) <= 0) {
|
||||
@@ -191,20 +187,11 @@ TEST_F(DBTablePropertiesTest, GetPropertiesOfTablesInRange) {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
// create a bunch of ranges
|
||||
std::vector<std::string> random_keys;
|
||||
// Random returns numbers with zero included
|
||||
// when we pass empty ranges TestGetPropertiesOfTablesInRange()
|
||||
// derefs random memory in the empty ranges[0]
|
||||
// so want to be greater than zero and even since
|
||||
// the below loop requires that random_keys.size() to be even.
|
||||
auto n = 2 * (rnd.Uniform(50) + 1);
|
||||
|
||||
auto n = 2 * rnd.Uniform(50);
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
random_keys.push_back(test::RandomKey(&rnd, 5));
|
||||
}
|
||||
|
||||
ASSERT_GT(random_keys.size(), 0U);
|
||||
ASSERT_EQ((random_keys.size() % 2), 0U);
|
||||
|
||||
std::vector<Range> ranges;
|
||||
auto it = random_keys.begin();
|
||||
while (it != random_keys.end()) {
|
||||
|
||||
@@ -140,8 +140,6 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
std::unique_ptr<Iterator> iterh(db_->NewIterator(read_options, handles_[1]));
|
||||
std::string value(1024, 'a');
|
||||
bool file_iters_deleted = false;
|
||||
bool file_iters_renewed_null = false;
|
||||
bool file_iters_renewed_copy = false;
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"ForwardIterator::SeekInternal:Return", [&](void* arg) {
|
||||
ForwardIterator* fiter = reinterpret_cast<ForwardIterator*>(arg);
|
||||
@@ -154,12 +152,6 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
ASSERT_TRUE(!file_iters_deleted ||
|
||||
fiter->TEST_CheckDeletedIters(&deleted_iters, &num_iters));
|
||||
});
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"ForwardIterator::RenewIterators:Null",
|
||||
[&](void* arg) { file_iters_renewed_null = true; });
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"ForwardIterator::RenewIterators:Copy",
|
||||
[&](void* arg) { file_iters_renewed_copy = true; });
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
const int num_records = 1000;
|
||||
for (int i = 1; i < num_records; ++i) {
|
||||
@@ -211,8 +203,6 @@ TEST_F(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
|
||||
ASSERT_LE(num_iters, 1);
|
||||
file_iters_deleted = false;
|
||||
}
|
||||
ASSERT_TRUE(file_iters_renewed_null);
|
||||
ASSERT_TRUE(file_iters_renewed_copy);
|
||||
iter = 0;
|
||||
itern = 0;
|
||||
iterh = 0;
|
||||
|
||||
+59
-198
@@ -1910,10 +1910,9 @@ TEST_F(DBTest, IterReseek) {
|
||||
DestroyAndReopen(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
// insert three keys with same userkey and verify that
|
||||
// insert two keys with same userkey and verify that
|
||||
// reseek is not invoked. For each of these test cases,
|
||||
// verify that we can find the next key "b".
|
||||
ASSERT_OK(Put(1, "a", "zero"));
|
||||
ASSERT_OK(Put(1, "a", "one"));
|
||||
ASSERT_OK(Put(1, "a", "two"));
|
||||
ASSERT_OK(Put(1, "b", "bone"));
|
||||
@@ -2382,9 +2381,9 @@ TEST_F(DBTest, NumImmutableMemTable) {
|
||||
ASSERT_EQ(num, "0");
|
||||
ASSERT_TRUE(dbfull()->GetProperty(
|
||||
handles_[1], "rocksdb.cur-size-active-mem-table", &num));
|
||||
// "192" is the size of the metadata of an empty skiplist, this would
|
||||
// "200" is the size of the metadata of an empty skiplist, this would
|
||||
// break if we change the default skiplist implementation
|
||||
ASSERT_EQ(num, "192");
|
||||
ASSERT_EQ(num, "200");
|
||||
|
||||
uint64_t int_num;
|
||||
uint64_t base_total_size;
|
||||
@@ -4936,7 +4935,7 @@ TEST_F(DBTest, SharedWriteBuffer) {
|
||||
options.write_buffer_size = 500000; // this is never hit
|
||||
CreateAndReopenWithCF({"pikachu", "dobrynia", "nikitich"}, options);
|
||||
|
||||
// Trigger a flush on CF "nikitich"
|
||||
// Trigger a flush on every CF
|
||||
ASSERT_OK(Put(0, Key(1), DummyString(1)));
|
||||
ASSERT_OK(Put(1, Key(1), DummyString(1)));
|
||||
ASSERT_OK(Put(3, Key(1), DummyString(90000)));
|
||||
@@ -4948,107 +4947,65 @@ TEST_F(DBTest, SharedWriteBuffer) {
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
|
||||
{
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
|
||||
static_cast<uint64_t>(0));
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(0));
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(0));
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
static_cast<uint64_t>(1));
|
||||
}
|
||||
|
||||
// "dobrynia": 20KB
|
||||
// Flush 'dobrynia'
|
||||
// Flush 'dobrynia' and 'nikitich'
|
||||
ASSERT_OK(Put(2, Key(2), DummyString(50000)));
|
||||
ASSERT_OK(Put(3, Key(2), DummyString(40000)));
|
||||
ASSERT_OK(Put(2, Key(3), DummyString(20000)));
|
||||
ASSERT_OK(Put(3, Key(2), DummyString(40000)));
|
||||
ASSERT_OK(Put(2, Key(2), DummyString(70000)));
|
||||
ASSERT_OK(Put(0, Key(1), DummyString(1)));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
|
||||
{
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
|
||||
static_cast<uint64_t>(0));
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(0));
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(1));
|
||||
static_cast<uint64_t>(2));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
static_cast<uint64_t>(1));
|
||||
static_cast<uint64_t>(2));
|
||||
}
|
||||
|
||||
// "nikitich" still has has data of 80KB
|
||||
// Inserting Data in "dobrynia" triggers "nikitich" flushing.
|
||||
ASSERT_OK(Put(3, Key(2), DummyString(40000)));
|
||||
// Make 'dobrynia' and 'nikitich' both take up 40% of space
|
||||
// When 'pikachu' puts us over 100%, all 3 flush.
|
||||
ASSERT_OK(Put(2, Key(2), DummyString(40000)));
|
||||
ASSERT_OK(Put(0, Key(1), DummyString(1)));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
|
||||
{
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
|
||||
static_cast<uint64_t>(0));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(0));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
static_cast<uint64_t>(2));
|
||||
}
|
||||
|
||||
// "dobrynia" still has 40KB
|
||||
ASSERT_OK(Put(1, Key(2), DummyString(20000)));
|
||||
ASSERT_OK(Put(0, Key(1), DummyString(10000)));
|
||||
ASSERT_OK(Put(0, Key(1), DummyString(1)));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[0]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
|
||||
// This should triggers no flush
|
||||
{
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
|
||||
static_cast<uint64_t>(0));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(0));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(2));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(3));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
static_cast<uint64_t>(3));
|
||||
}
|
||||
|
||||
// "default": 10KB, "pikachu": 20KB, "dobrynia": 40KB
|
||||
ASSERT_OK(Put(1, Key(2), DummyString(40000)));
|
||||
ASSERT_OK(Put(0, Key(1), DummyString(1)));
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[0]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
|
||||
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
|
||||
// This should triggers flush of "pikachu"
|
||||
{
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
|
||||
static_cast<uint64_t>(0));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
static_cast<uint64_t>(2));
|
||||
}
|
||||
|
||||
// "default": 10KB, "dobrynia": 40KB
|
||||
// Some remaining writes so 'default', 'dobrynia' and 'nikitich' flush on
|
||||
// closure.
|
||||
// Some remaining writes so 'default' and 'nikitich' flush on closure.
|
||||
ASSERT_OK(Put(3, Key(1), DummyString(1)));
|
||||
ReopenWithColumnFamilies({"default", "pikachu", "dobrynia", "nikitich"},
|
||||
options);
|
||||
{
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(1));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(2));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
|
||||
static_cast<uint64_t>(2));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
|
||||
static_cast<uint64_t>(3));
|
||||
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
|
||||
static_cast<uint64_t>(4));
|
||||
}
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
@@ -5850,11 +5807,6 @@ class ModelDB: public DB {
|
||||
return Status::NotSupported("Not supported operation.");
|
||||
}
|
||||
|
||||
Status EnableAutoCompaction(
|
||||
const std::vector<ColumnFamilyHandle*>& column_family_handles) override {
|
||||
return Status::NotSupported("Not supported operation.");
|
||||
}
|
||||
|
||||
using DB::NumberLevels;
|
||||
virtual int NumberLevels(ColumnFamilyHandle* column_family) override {
|
||||
return 1;
|
||||
@@ -7514,14 +7466,8 @@ TEST_F(DBTest, DynamicLevelCompressionPerLevel2) {
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ASSERT_OK(Put(Key(keys[i]), RandomString(&rnd, 200)));
|
||||
|
||||
if (i % 25 == 0) {
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
}
|
||||
}
|
||||
|
||||
Flush();
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
|
||||
@@ -7698,25 +7644,28 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
// Clean up memtable and L0. Block compaction threads. If continue to write
|
||||
// and flush memtables. We should see put stop after 8 memtable flushes
|
||||
// since level0_stop_writes_trigger = 8
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
// Block compaction
|
||||
test::SleepingBackgroundTask sleeping_task_low;
|
||||
env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task_low,
|
||||
Env::Priority::LOW);
|
||||
sleeping_task_low.WaitUntilSleeping();
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->SetCallBack(
|
||||
"DBImpl::DelayWrite:Wait",
|
||||
[&](void* arg) { sleeping_task_low.WakeUp(); });
|
||||
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
int count = 0;
|
||||
Random rnd(301);
|
||||
WriteOptions wo;
|
||||
while (count < 64) {
|
||||
ASSERT_OK(Put(Key(count), RandomString(&rnd, 1024), wo));
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
count++;
|
||||
if (dbfull()->TEST_write_controler().IsStopped()) {
|
||||
sleeping_task_low.WakeUp();
|
||||
if (sleeping_task_low.WokenUp()) {
|
||||
break;
|
||||
}
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
count++;
|
||||
}
|
||||
// Stop trigger = 8
|
||||
ASSERT_EQ(count, 8);
|
||||
@@ -7729,7 +7678,6 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
ASSERT_OK(dbfull()->SetOptions({
|
||||
{"level0_stop_writes_trigger", "6"}
|
||||
}));
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
|
||||
@@ -7737,16 +7685,14 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
sleeping_task_low.Reset();
|
||||
env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task_low,
|
||||
Env::Priority::LOW);
|
||||
sleeping_task_low.WaitUntilSleeping();
|
||||
count = 0;
|
||||
while (count < 64) {
|
||||
ASSERT_OK(Put(Key(count), RandomString(&rnd, 1024), wo));
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
count++;
|
||||
if (dbfull()->TEST_write_controler().IsStopped()) {
|
||||
sleeping_task_low.WakeUp();
|
||||
if (sleeping_task_low.WokenUp()) {
|
||||
break;
|
||||
}
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQ(count, 6);
|
||||
// Unblock
|
||||
@@ -7786,6 +7732,8 @@ TEST_F(DBTest, DynamicCompactionOptions) {
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_LT(NumTableFilesAtLevel(0), 4);
|
||||
|
||||
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
@@ -8289,18 +8237,16 @@ TEST_F(DBTest, CloseSpeedup) {
|
||||
Destroy(options);
|
||||
}
|
||||
|
||||
class DelayedMergeOperator : public MergeOperator {
|
||||
class DelayedMergeOperator : public AssociativeMergeOperator {
|
||||
private:
|
||||
DBTest* db_test_;
|
||||
|
||||
public:
|
||||
explicit DelayedMergeOperator(DBTest* d) : db_test_(d) {}
|
||||
virtual bool FullMerge(const Slice& key, const Slice* existing_value,
|
||||
const std::deque<std::string>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* logger) const override {
|
||||
virtual bool Merge(const Slice& key, const Slice* existing_value,
|
||||
const Slice& value, std::string* new_value,
|
||||
Logger* logger) const override {
|
||||
db_test_->env_->addon_time_.fetch_add(1000);
|
||||
*new_value = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8316,8 +8262,6 @@ TEST_F(DBTest, MergeTestTime) {
|
||||
// Enable time profiling
|
||||
SetPerfLevel(kEnableTime);
|
||||
this->env_->addon_time_.store(0);
|
||||
this->env_->time_elapse_only_sleep_ = true;
|
||||
this->env_->no_sleep_ = true;
|
||||
Options options;
|
||||
options = CurrentOptions(options);
|
||||
options.statistics = rocksdb::CreateDBStatistics();
|
||||
@@ -8338,7 +8282,8 @@ TEST_F(DBTest, MergeTestTime) {
|
||||
std::string result;
|
||||
db_->Get(opt, "foo", &result);
|
||||
|
||||
ASSERT_EQ(1000000, TestGetTickerCount(options, MERGE_OPERATION_TOTAL_TIME));
|
||||
ASSERT_LT(TestGetTickerCount(options, MERGE_OPERATION_TOTAL_TIME), 2800000);
|
||||
ASSERT_GT(TestGetTickerCount(options, MERGE_OPERATION_TOTAL_TIME), 1200000);
|
||||
|
||||
ReadOptions read_options;
|
||||
std::unique_ptr<Iterator> iter(db_->NewIterator(read_options));
|
||||
@@ -8349,11 +8294,12 @@ TEST_F(DBTest, MergeTestTime) {
|
||||
}
|
||||
|
||||
ASSERT_EQ(1, count);
|
||||
ASSERT_EQ(2000000, TestGetTickerCount(options, MERGE_OPERATION_TOTAL_TIME));
|
||||
|
||||
ASSERT_LT(TestGetTickerCount(options, MERGE_OPERATION_TOTAL_TIME), 6000000);
|
||||
ASSERT_GT(TestGetTickerCount(options, MERGE_OPERATION_TOTAL_TIME), 3200000);
|
||||
#if ROCKSDB_USING_THREAD_STATUS
|
||||
ASSERT_GT(TestGetTickerCount(options, FLUSH_WRITE_BYTES), 0);
|
||||
#endif // ROCKSDB_USING_THREAD_STATUS
|
||||
this->env_->time_elapse_only_sleep_ = false;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
@@ -8629,12 +8575,10 @@ TEST_F(DBTest, SuggestCompactRangeTest) {
|
||||
};
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(DBTestBase::kNumKeysByGenerateNewRandomFile));
|
||||
options.compaction_style = kCompactionStyleLevel;
|
||||
options.compaction_filter_factory.reset(
|
||||
new CompactionFilterFactoryGetContext());
|
||||
options.write_buffer_size = 200 << 10;
|
||||
options.write_buffer_size = 100 << 10;
|
||||
options.arena_block_size = 4 << 10;
|
||||
options.level0_file_num_compaction_trigger = 4;
|
||||
options.num_levels = 4;
|
||||
@@ -8689,12 +8633,10 @@ TEST_F(DBTest, SuggestCompactRangeTest) {
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
}
|
||||
|
||||
// All files are compacted
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(1));
|
||||
ASSERT_EQ("0,0,13", FilesPerLevel(0));
|
||||
|
||||
GenerateNewRandomFile(&rnd);
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ("1,0,13", FilesPerLevel(0));
|
||||
|
||||
// nonoverlapping with the file on level 0
|
||||
Slice start("a"), end("b");
|
||||
@@ -8702,7 +8644,7 @@ TEST_F(DBTest, SuggestCompactRangeTest) {
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
|
||||
// should not compact the level 0 file
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ("1,0,13", FilesPerLevel(0));
|
||||
|
||||
start = Slice("j");
|
||||
end = Slice("m");
|
||||
@@ -8712,8 +8654,7 @@ TEST_F(DBTest, SuggestCompactRangeTest) {
|
||||
options.compaction_filter_factory.get()));
|
||||
|
||||
// now it should compact the level 0 file
|
||||
ASSERT_EQ(0, NumTableFilesAtLevel(0));
|
||||
ASSERT_EQ(1, NumTableFilesAtLevel(1));
|
||||
ASSERT_EQ("0,1,13", FilesPerLevel(0));
|
||||
}
|
||||
|
||||
TEST_F(DBTest, PromoteL0) {
|
||||
@@ -8815,7 +8756,7 @@ TEST_F(DBTest, LargeBatchWithColumnFamilies) {
|
||||
for (int pass = 1; pass <= 3; pass++) {
|
||||
WriteBatch batch;
|
||||
size_t write_size = 1024 * 1024 * (5 + i);
|
||||
fprintf(stderr, "prepare: %" ROCKSDB_PRIszt " MB, pass:%d\n", (write_size / 1024 / 1024),
|
||||
fprintf(stderr, "prepare: %ld MB, pass:%d\n", (write_size / 1024 / 1024),
|
||||
pass);
|
||||
for (;;) {
|
||||
std::string data(3000, j++ % 127 + 20);
|
||||
@@ -8825,7 +8766,7 @@ TEST_F(DBTest, LargeBatchWithColumnFamilies) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "write: %" ROCKSDB_PRIszt " MB\n", (batch.GetDataSize() / 1024 / 1024));
|
||||
fprintf(stderr, "write: %ld MB\n", (batch.GetDataSize() / 1024 / 1024));
|
||||
ASSERT_OK(dbfull()->Write(WriteOptions(), &batch));
|
||||
fprintf(stderr, "done\n");
|
||||
}
|
||||
@@ -10534,86 +10475,6 @@ TEST_F(DBTest, WalFilterTestWithChangeBatchExtraKeys) {
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
class SliceTransformLimitedDomain : public SliceTransform {
|
||||
const char* Name() const override { return "SliceTransformLimitedDomain"; }
|
||||
|
||||
Slice Transform(const Slice& src) const override {
|
||||
return Slice(src.data(), 5);
|
||||
}
|
||||
|
||||
bool InDomain(const Slice& src) const override {
|
||||
// prefix will be x????
|
||||
return src.size() >= 5 && src[0] == 'x';
|
||||
}
|
||||
|
||||
bool InRange(const Slice& dst) const override {
|
||||
// prefix will be x????
|
||||
return dst.size() == 5 && dst[0] == 'x';
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DBTest, PrefixExtractorFullFilter) {
|
||||
BlockBasedTableOptions bbto;
|
||||
// Full Filter Block
|
||||
bbto.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, false));
|
||||
bbto.whole_key_filtering = false;
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.prefix_extractor = std::make_shared<SliceTransformLimitedDomain>();
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("x1111_AAAA", "val1"));
|
||||
ASSERT_OK(Put("x1112_AAAA", "val2"));
|
||||
ASSERT_OK(Put("x1113_AAAA", "val3"));
|
||||
ASSERT_OK(Put("x1114_AAAA", "val4"));
|
||||
// Not in domain, wont be added to filter
|
||||
ASSERT_OK(Put("zzzzz_AAAA", "val5"));
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
ASSERT_EQ(Get("x1111_AAAA"), "val1");
|
||||
ASSERT_EQ(Get("x1112_AAAA"), "val2");
|
||||
ASSERT_EQ(Get("x1113_AAAA"), "val3");
|
||||
ASSERT_EQ(Get("x1114_AAAA"), "val4");
|
||||
// Was not added to filter but rocksdb will try to read it from the filter
|
||||
ASSERT_EQ(Get("zzzzz_AAAA"), "val5");
|
||||
}
|
||||
|
||||
TEST_F(DBTest, PrefixExtractorBlockFilter) {
|
||||
BlockBasedTableOptions bbto;
|
||||
// Block Filter Block
|
||||
bbto.filter_policy.reset(rocksdb::NewBloomFilterPolicy(10, true));
|
||||
|
||||
Options options = CurrentOptions();
|
||||
options.prefix_extractor = std::make_shared<SliceTransformLimitedDomain>();
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||
|
||||
DestroyAndReopen(options);
|
||||
|
||||
ASSERT_OK(Put("x1113_AAAA", "val3"));
|
||||
ASSERT_OK(Put("x1114_AAAA", "val4"));
|
||||
// Not in domain, wont be added to filter
|
||||
ASSERT_OK(Put("zzzzz_AAAA", "val1"));
|
||||
ASSERT_OK(Put("zzzzz_AAAB", "val2"));
|
||||
ASSERT_OK(Put("zzzzz_AAAC", "val3"));
|
||||
ASSERT_OK(Put("zzzzz_AAAD", "val4"));
|
||||
|
||||
ASSERT_OK(Flush());
|
||||
|
||||
std::vector<std::string> iter_res;
|
||||
auto iter = db_->NewIterator(ReadOptions());
|
||||
// Seek to a key that was not in Domain
|
||||
for (iter->Seek("zzzzz_AAAA"); iter->Valid(); iter->Next()) {
|
||||
iter_res.emplace_back(iter->value().ToString());
|
||||
}
|
||||
|
||||
std::vector<std::string> expected_res = {"val1", "val2", "val3", "val4"};
|
||||
ASSERT_EQ(iter_res, expected_res);
|
||||
delete iter;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
class BloomStatsTestWithParam
|
||||
: public DBTest,
|
||||
@@ -10744,7 +10605,7 @@ TEST_P(BloomStatsTestWithParam, BloomStatsTestWithIter) {
|
||||
|
||||
iter.reset(dbfull()->NewIterator(ReadOptions()));
|
||||
|
||||
// Check SST bloom stats
|
||||
// check SST bloom stats
|
||||
iter->Seek(key1);
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
|
||||
+3
-8
@@ -18,7 +18,6 @@ SpecialEnv::SpecialEnv(Env* base)
|
||||
rnd_(301),
|
||||
sleep_counter_(this),
|
||||
addon_time_(0),
|
||||
time_elapse_only_sleep_(false),
|
||||
no_sleep_(false) {
|
||||
delay_sstable_sync_.store(false, std::memory_order_release);
|
||||
drop_writes_.store(false, std::memory_order_release);
|
||||
@@ -56,7 +55,6 @@ DBTestBase::DBTestBase(const std::string path)
|
||||
EXPECT_OK(DestroyDB(dbname_, options));
|
||||
db_ = nullptr;
|
||||
Reopen(options);
|
||||
Random::GetTLSInstance()->Reset(0xdeadbeef);
|
||||
}
|
||||
|
||||
DBTestBase::~DBTestBase() {
|
||||
@@ -369,7 +367,6 @@ Options DBTestBase::CurrentOptions(
|
||||
}
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
options.fail_if_options_file_error = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -833,7 +830,7 @@ int DBTestBase::GetSstFileCount(std::string path) {
|
||||
// this will generate non-overlapping files since it keeps increasing key_idx
|
||||
void DBTestBase::GenerateNewFile(int cf, Random* rnd, int* key_idx,
|
||||
bool nowait) {
|
||||
for (int i = 0; i < KNumKeysByGenerateNewFile; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ASSERT_OK(Put(cf, Key(*key_idx), RandomString(rnd, (i == 99) ? 1 : 990)));
|
||||
(*key_idx)++;
|
||||
}
|
||||
@@ -845,7 +842,7 @@ void DBTestBase::GenerateNewFile(int cf, Random* rnd, int* key_idx,
|
||||
|
||||
// this will generate non-overlapping files since it keeps increasing key_idx
|
||||
void DBTestBase::GenerateNewFile(Random* rnd, int* key_idx, bool nowait) {
|
||||
for (int i = 0; i < KNumKeysByGenerateNewFile; i++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ASSERT_OK(Put(Key(*key_idx), RandomString(rnd, (i == 99) ? 1 : 990)));
|
||||
(*key_idx)++;
|
||||
}
|
||||
@@ -855,10 +852,8 @@ void DBTestBase::GenerateNewFile(Random* rnd, int* key_idx, bool nowait) {
|
||||
}
|
||||
}
|
||||
|
||||
const int DBTestBase::kNumKeysByGenerateNewRandomFile = 51;
|
||||
|
||||
void DBTestBase::GenerateNewRandomFile(Random* rnd, bool nowait) {
|
||||
for (int i = 0; i < kNumKeysByGenerateNewRandomFile; i++) {
|
||||
for (int i = 0; i < 51; i++) {
|
||||
ASSERT_OK(Put("key" + RandomString(rnd, 7), RandomString(rnd, 2000)));
|
||||
}
|
||||
ASSERT_OK(Put("key" + RandomString(rnd, 7), RandomString(rnd, 200)));
|
||||
|
||||
+5
-95
@@ -118,84 +118,6 @@ struct OptionsOverride {
|
||||
|
||||
} // namespace anon
|
||||
|
||||
// A hacky skip list mem table that triggers flush after number of entries.
|
||||
class SpecialMemTableRep : public MemTableRep {
|
||||
public:
|
||||
explicit SpecialMemTableRep(MemTableAllocator* allocator,
|
||||
MemTableRep* memtable, int num_entries_flush)
|
||||
: MemTableRep(allocator),
|
||||
memtable_(memtable),
|
||||
num_entries_flush_(num_entries_flush),
|
||||
num_entries_(0) {}
|
||||
|
||||
virtual KeyHandle Allocate(const size_t len, char** buf) override {
|
||||
return memtable_->Allocate(len, buf);
|
||||
}
|
||||
|
||||
// Insert key into the list.
|
||||
// REQUIRES: nothing that compares equal to key is currently in the list.
|
||||
virtual void Insert(KeyHandle handle) override {
|
||||
memtable_->Insert(handle);
|
||||
num_entries_++;
|
||||
}
|
||||
|
||||
// Returns true iff an entry that compares equal to key is in the list.
|
||||
virtual bool Contains(const char* key) const override {
|
||||
return memtable_->Contains(key);
|
||||
}
|
||||
|
||||
virtual size_t ApproximateMemoryUsage() override {
|
||||
// Return a high memory usage when number of entries exceeds the threshold
|
||||
// to trigger a flush.
|
||||
return (num_entries_ < num_entries_flush_) ? 0 : 1024 * 1024 * 1024;
|
||||
}
|
||||
|
||||
virtual void Get(const LookupKey& k, void* callback_args,
|
||||
bool (*callback_func)(void* arg,
|
||||
const char* entry)) override {
|
||||
memtable_->Get(k, callback_args, callback_func);
|
||||
}
|
||||
|
||||
uint64_t ApproximateNumEntries(const Slice& start_ikey,
|
||||
const Slice& end_ikey) override {
|
||||
return memtable_->ApproximateNumEntries(start_ikey, end_ikey);
|
||||
}
|
||||
|
||||
virtual MemTableRep::Iterator* GetIterator(Arena* arena = nullptr) override {
|
||||
return memtable_->GetIterator(arena);
|
||||
}
|
||||
|
||||
virtual ~SpecialMemTableRep() override {}
|
||||
|
||||
private:
|
||||
unique_ptr<MemTableRep> memtable_;
|
||||
int num_entries_flush_;
|
||||
int num_entries_;
|
||||
};
|
||||
|
||||
// The factory for the hacky skip list mem table that triggers flush after
|
||||
// number of entries exceeds a threshold.
|
||||
class SpecialSkipListFactory : public MemTableRepFactory {
|
||||
public:
|
||||
// After number of inserts exceeds `num_entries_flush` in a mem table, trigger
|
||||
// flush.
|
||||
explicit SpecialSkipListFactory(int num_entries_flush)
|
||||
: num_entries_flush_(num_entries_flush) {}
|
||||
|
||||
virtual MemTableRep* CreateMemTableRep(
|
||||
const MemTableRep::KeyComparator& compare, MemTableAllocator* allocator,
|
||||
const SliceTransform* transform, Logger* logger) override {
|
||||
return new SpecialMemTableRep(
|
||||
allocator, factory_.CreateMemTableRep(compare, allocator, transform, 0),
|
||||
num_entries_flush_);
|
||||
}
|
||||
virtual const char* Name() const override { return "SkipListFactory"; }
|
||||
|
||||
private:
|
||||
SkipListFactory factory_;
|
||||
int num_entries_flush_;
|
||||
};
|
||||
|
||||
// Special Env used to delay background operations
|
||||
class SpecialEnv : public EnvWrapper {
|
||||
public:
|
||||
@@ -405,19 +327,15 @@ class SpecialEnv : public EnvWrapper {
|
||||
|
||||
virtual void SleepForMicroseconds(int micros) override {
|
||||
sleep_counter_.Increment();
|
||||
if (no_sleep_ || time_elapse_only_sleep_) {
|
||||
if (no_sleep_) {
|
||||
addon_time_.fetch_add(micros);
|
||||
}
|
||||
if (!no_sleep_) {
|
||||
} else {
|
||||
target()->SleepForMicroseconds(micros);
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status GetCurrentTime(int64_t* unix_time) override {
|
||||
Status s;
|
||||
if (!time_elapse_only_sleep_) {
|
||||
s = target()->GetCurrentTime(unix_time);
|
||||
}
|
||||
Status s = target()->GetCurrentTime(unix_time);
|
||||
if (s.ok()) {
|
||||
*unix_time += addon_time_.load();
|
||||
}
|
||||
@@ -425,13 +343,11 @@ class SpecialEnv : public EnvWrapper {
|
||||
}
|
||||
|
||||
virtual uint64_t NowNanos() override {
|
||||
return (time_elapse_only_sleep_ ? 0 : target()->NowNanos()) +
|
||||
addon_time_.load() * 1000;
|
||||
return target()->NowNanos() + addon_time_.load() * 1000;
|
||||
}
|
||||
|
||||
virtual uint64_t NowMicros() override {
|
||||
return (time_elapse_only_sleep_ ? 0 : target()->NowMicros()) +
|
||||
addon_time_.load();
|
||||
return target()->NowMicros() + addon_time_.load();
|
||||
}
|
||||
|
||||
Random rnd_;
|
||||
@@ -483,9 +399,6 @@ class SpecialEnv : public EnvWrapper {
|
||||
std::function<void()>* table_write_callback_;
|
||||
|
||||
std::atomic<int64_t> addon_time_;
|
||||
|
||||
bool time_elapse_only_sleep_;
|
||||
|
||||
bool no_sleep_;
|
||||
|
||||
std::atomic<bool> is_wal_sync_thread_safe_{true};
|
||||
@@ -709,9 +622,6 @@ class DBTestBase : public testing::Test {
|
||||
|
||||
void GenerateNewFile(int fd, Random* rnd, int* key_idx, bool nowait = false);
|
||||
|
||||
static const int kNumKeysByGenerateNewRandomFile;
|
||||
static const int KNumKeysByGenerateNewFile = 100;
|
||||
|
||||
void GenerateNewRandomFile(Random* rnd, bool nowait = false);
|
||||
|
||||
std::string IterStatus(Iterator* iter);
|
||||
|
||||
@@ -112,44 +112,6 @@ class DelayFilterFactory : public CompactionFilterFactory {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Make sure we don't trigger a problem if the trigger conditon is given
|
||||
// to be 0, which is invalid.
|
||||
TEST_P(DBTestUniversalCompaction, UniversalCompactionSingleSortedRun) {
|
||||
Options options;
|
||||
options = CurrentOptions(options);
|
||||
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.num_levels = num_levels_;
|
||||
// Config universal compaction to always compact to one single sorted run.
|
||||
options.level0_file_num_compaction_trigger = 0;
|
||||
options.compaction_options_universal.size_ratio = 10;
|
||||
options.compaction_options_universal.min_merge_width = 2;
|
||||
options.compaction_options_universal.max_size_amplification_percent = 1;
|
||||
|
||||
options.write_buffer_size = 105 << 10; // 105KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
options.target_file_size_base = 32 << 10; // 32KB
|
||||
// trigger compaction if there are >= 4 files
|
||||
KeepFilterFactory* filter = new KeepFilterFactory(true);
|
||||
filter->expect_manual_compaction_.store(false);
|
||||
options.compaction_filter_factory.reset(filter);
|
||||
|
||||
DestroyAndReopen(options);
|
||||
ASSERT_EQ(1, db_->GetOptions().level0_file_num_compaction_trigger);
|
||||
|
||||
Random rnd(301);
|
||||
int key_idx = 0;
|
||||
|
||||
filter->expect_full_compaction_.store(true);
|
||||
|
||||
for (int num = 0; num < 16; num++) {
|
||||
// Write 100KB file. And immediately it should be compacted to one file.
|
||||
GenerateNewFile(&rnd, &key_idx);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(NumSortedRuns(0), 1);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(kailiu) The tests on UniversalCompaction has some issues:
|
||||
// 1. A lot of magic numbers ("11" or "12").
|
||||
// 2. Made assumption on the memtable flush conditions, which may change from
|
||||
@@ -157,7 +119,6 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionSingleSortedRun) {
|
||||
TEST_P(DBTestUniversalCompaction, UniversalCompactionTrigger) {
|
||||
Options options;
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.compaction_options_universal.size_ratio = 5;
|
||||
options.num_levels = num_levels_;
|
||||
options.write_buffer_size = 105 << 10; // 105KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
@@ -890,10 +851,7 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionFourPaths) {
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 300 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_3", 500 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_4", 1024 * 1024 * 1024);
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.compaction_options_universal.size_ratio = 5;
|
||||
options.write_buffer_size = 110 << 10; // 105KB
|
||||
options.arena_block_size = 4 << 10;
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
@@ -1010,15 +968,13 @@ TEST_P(DBTestUniversalCompaction, IncreaseUniversalCompactionNumLevels) {
|
||||
int max_key1 = 200;
|
||||
int max_key2 = 600;
|
||||
int max_key3 = 800;
|
||||
const int KNumKeysPerFile = 10;
|
||||
|
||||
// Stage 1: open a DB with universal compaction, num_levels=1
|
||||
Options options = CurrentOptions();
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.num_levels = 1;
|
||||
options.write_buffer_size = 200 << 10; // 200KB
|
||||
options.write_buffer_size = 100 << 10; // 100KB
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
options.memtable_factory.reset(new SpecialSkipListFactory(KNumKeysPerFile));
|
||||
options = CurrentOptions(options);
|
||||
CreateAndReopenWithCF({"pikachu"}, options);
|
||||
|
||||
@@ -1091,14 +1047,11 @@ TEST_P(DBTestUniversalCompaction, UniversalCompactionSecondPathRatio) {
|
||||
options.db_paths.emplace_back(dbname_, 500 * 1024);
|
||||
options.db_paths.emplace_back(dbname_ + "_2", 1024 * 1024 * 1024);
|
||||
options.compaction_style = kCompactionStyleUniversal;
|
||||
options.compaction_options_universal.size_ratio = 5;
|
||||
options.write_buffer_size = 110 << 10; // 105KB
|
||||
options.arena_block_size = 4 * 1024;
|
||||
options.arena_block_size = 4 << 10;
|
||||
options.level0_file_num_compaction_trigger = 2;
|
||||
options.num_levels = 1;
|
||||
options.memtable_factory.reset(
|
||||
new SpecialSkipListFactory(KNumKeysByGenerateNewFile - 1));
|
||||
options = CurrentOptions(options);
|
||||
|
||||
std::vector<std::string> filenames;
|
||||
|
||||
+3
-37
@@ -21,7 +21,6 @@
|
||||
#include "util/file_reader_writer.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/sync_point.h"
|
||||
|
||||
namespace rocksdb {
|
||||
@@ -48,9 +47,8 @@ static size_t GetInfoLogPrefix(const std::string& path, char* dest, int len) {
|
||||
path[i] == '_'){
|
||||
dest[write_idx++] = path[i];
|
||||
} else {
|
||||
if (i > 0) {
|
||||
if (i > 0)
|
||||
dest[write_idx++] = '_';
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -148,7 +146,7 @@ std::string LockFileName(const std::string& dbname) {
|
||||
}
|
||||
|
||||
std::string TempFileName(const std::string& dbname, uint64_t number) {
|
||||
return MakeFileName(dbname, number, kTempFileNameSuffix.c_str());
|
||||
return MakeFileName(dbname, number, "dbtmp");
|
||||
}
|
||||
|
||||
InfoLogPrefix::InfoLogPrefix(bool has_log_dir,
|
||||
@@ -188,21 +186,6 @@ std::string OldInfoLogFileName(const std::string& dbname, uint64_t ts,
|
||||
return log_dir + "/" + info_log_prefix.buf + ".old." + buf;
|
||||
}
|
||||
|
||||
std::string OptionsFileName(const std::string& dbname, uint64_t file_num) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "%s%06" PRIu64,
|
||||
kOptionsFileNamePrefix.c_str(), file_num);
|
||||
return dbname + "/" + buffer;
|
||||
}
|
||||
|
||||
std::string TempOptionsFileName(const std::string& dbname, uint64_t file_num) {
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), "%s%06" PRIu64 ".%s",
|
||||
kOptionsFileNamePrefix.c_str(), file_num,
|
||||
kTempFileNameSuffix.c_str());
|
||||
return dbname + "/" + buffer;
|
||||
}
|
||||
|
||||
std::string MetaDatabaseName(const std::string& dbname, uint64_t number) {
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "/METADB-%llu",
|
||||
@@ -223,8 +206,6 @@ std::string IdentityFileName(const std::string& dbname) {
|
||||
// dbname/MANIFEST-[0-9]+
|
||||
// dbname/[0-9]+.(log|sst)
|
||||
// dbname/METADB-[0-9]+
|
||||
// dbname/OPTIONS-[0-9]+
|
||||
// dbname/OPTIONS-[0-9]+.dbtmp
|
||||
// Disregards / at the beginning
|
||||
bool ParseFileName(const std::string& fname,
|
||||
uint64_t* number,
|
||||
@@ -287,21 +268,6 @@ bool ParseFileName(const std::string& fname, uint64_t* number,
|
||||
}
|
||||
*type = kMetaDatabase;
|
||||
*number = num;
|
||||
} else if (rest.starts_with(kOptionsFileNamePrefix)) {
|
||||
uint64_t ts_suffix;
|
||||
bool is_temp_file = false;
|
||||
rest.remove_prefix(kOptionsFileNamePrefix.size());
|
||||
const std::string kTempFileNameSuffixWithDot =
|
||||
std::string(".") + kTempFileNameSuffix;
|
||||
if (rest.ends_with(kTempFileNameSuffixWithDot)) {
|
||||
rest.remove_suffix(kTempFileNameSuffixWithDot.size());
|
||||
is_temp_file = true;
|
||||
}
|
||||
if (!ConsumeDecimalNumber(&rest, &ts_suffix)) {
|
||||
return false;
|
||||
}
|
||||
*number = ts_suffix;
|
||||
*type = is_temp_file ? kTempFile : kOptionsFile;
|
||||
} else {
|
||||
// Avoid strtoull() to keep filename format independent of the
|
||||
// current locale
|
||||
@@ -336,7 +302,7 @@ bool ParseFileName(const std::string& fname, uint64_t* number,
|
||||
} else if (suffix == Slice(kRocksDbTFileExt) ||
|
||||
suffix == Slice(kLevelDbTFileExt)) {
|
||||
*type = kTableFile;
|
||||
} else if (suffix == Slice(kTempFileNameSuffix)) {
|
||||
} else if (suffix == Slice("dbtmp")) {
|
||||
*type = kTempFile;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
+1
-15
@@ -36,8 +36,7 @@ enum FileType {
|
||||
kTempFile,
|
||||
kInfoLogFile, // Either the current one, or an old one
|
||||
kMetaDatabase,
|
||||
kIdentityFile,
|
||||
kOptionsFile
|
||||
kIdentityFile
|
||||
};
|
||||
|
||||
// Return the name of the log file with the specified number
|
||||
@@ -115,19 +114,6 @@ extern std::string OldInfoLogFileName(const std::string& dbname, uint64_t ts,
|
||||
const std::string& db_path = "",
|
||||
const std::string& log_dir = "");
|
||||
|
||||
static const std::string kOptionsFileNamePrefix = "OPTIONS-";
|
||||
static const std::string kTempFileNameSuffix = "dbtmp";
|
||||
|
||||
// Return a options file name given the "dbname" and file number.
|
||||
// Format: OPTIONS-[number].dbtmp
|
||||
extern std::string OptionsFileName(const std::string& dbname,
|
||||
uint64_t file_num);
|
||||
|
||||
// Return a temp options file name given the "dbname" and file number.
|
||||
// Format: OPTIONS-[number]
|
||||
extern std::string TempOptionsFileName(const std::string& dbname,
|
||||
uint64_t file_num);
|
||||
|
||||
// Return the name to use for a metadatabase. The result will be prefixed with
|
||||
// "dbname".
|
||||
extern std::string MetaDatabaseName(const std::string& dbname,
|
||||
|
||||
+24
-104
@@ -144,23 +144,6 @@ ForwardIterator::~ForwardIterator() {
|
||||
Cleanup(true);
|
||||
}
|
||||
|
||||
void ForwardIterator::SVCleanup() {
|
||||
if (sv_ != nullptr && sv_->Unref()) {
|
||||
// Job id == 0 means that this is not our background process, but rather
|
||||
// user thread
|
||||
JobContext job_context(0);
|
||||
db_->mutex_.Lock();
|
||||
sv_->Cleanup();
|
||||
db_->FindObsoleteFiles(&job_context, false, true);
|
||||
db_->mutex_.Unlock();
|
||||
delete sv_;
|
||||
if (job_context.HaveSomethingToDelete()) {
|
||||
db_->PurgeObsoleteFiles(job_context);
|
||||
}
|
||||
job_context.Clean();
|
||||
}
|
||||
}
|
||||
|
||||
void ForwardIterator::Cleanup(bool release_sv) {
|
||||
if (mutable_iter_ != nullptr) {
|
||||
mutable_iter_->~InternalIterator();
|
||||
@@ -179,7 +162,20 @@ void ForwardIterator::Cleanup(bool release_sv) {
|
||||
level_iters_.clear();
|
||||
|
||||
if (release_sv) {
|
||||
SVCleanup();
|
||||
if (sv_ != nullptr && sv_->Unref()) {
|
||||
// Job id == 0 means that this is not our background process, but rather
|
||||
// user thread
|
||||
JobContext job_context(0);
|
||||
db_->mutex_.Lock();
|
||||
sv_->Cleanup();
|
||||
db_->FindObsoleteFiles(&job_context, false, true);
|
||||
db_->mutex_.Unlock();
|
||||
delete sv_;
|
||||
if (job_context.HaveSomethingToDelete()) {
|
||||
db_->PurgeObsoleteFiles(job_context);
|
||||
}
|
||||
job_context.Clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,10 +185,9 @@ bool ForwardIterator::Valid() const {
|
||||
}
|
||||
|
||||
void ForwardIterator::SeekToFirst() {
|
||||
if (sv_ == nullptr) {
|
||||
if (sv_ == nullptr ||
|
||||
sv_ ->version_number != cfd_->GetSuperVersionNumber()) {
|
||||
RebuildIterators(true);
|
||||
} else if (sv_->version_number != cfd_->GetSuperVersionNumber()) {
|
||||
RenewIterators();
|
||||
} else if (immutable_status_.IsIncomplete()) {
|
||||
ResetIncompleteIterators();
|
||||
}
|
||||
@@ -210,10 +205,9 @@ void ForwardIterator::Seek(const Slice& internal_key) {
|
||||
if (IsOverUpperBound(internal_key)) {
|
||||
valid_ = false;
|
||||
}
|
||||
if (sv_ == nullptr) {
|
||||
if (sv_ == nullptr ||
|
||||
sv_ ->version_number != cfd_->GetSuperVersionNumber()) {
|
||||
RebuildIterators(true);
|
||||
} else if (sv_->version_number != cfd_->GetSuperVersionNumber()) {
|
||||
RenewIterators();
|
||||
} else if (immutable_status_.IsIncomplete()) {
|
||||
ResetIncompleteIterators();
|
||||
}
|
||||
@@ -233,9 +227,7 @@ void ForwardIterator::SeekInternal(const Slice& internal_key,
|
||||
// an option to turn it off.
|
||||
if (seek_to_first || NeedToSeekImmutable(internal_key)) {
|
||||
immutable_status_ = Status::OK();
|
||||
if ((has_iter_trimmed_for_upper_bound_) &&
|
||||
(cfd_->internal_comparator().InternalKeyComparator::Compare(
|
||||
prev_key_.GetKey(), internal_key) > 0)) {
|
||||
if (has_iter_trimmed_for_upper_bound_) {
|
||||
// Some iterators are trimmed. Need to rebuild.
|
||||
RebuildIterators(true);
|
||||
// Already seeked mutable iter, so seek again
|
||||
@@ -401,11 +393,7 @@ void ForwardIterator::Next() {
|
||||
std::string current_key = key().ToString();
|
||||
Slice old_key(current_key.data(), current_key.size());
|
||||
|
||||
if (sv_ == nullptr) {
|
||||
RebuildIterators(true);
|
||||
} else {
|
||||
RenewIterators();
|
||||
}
|
||||
RebuildIterators(true);
|
||||
SeekInternal(old_key, false);
|
||||
if (!valid_ || key().compare(old_key) != 0) {
|
||||
return;
|
||||
@@ -496,81 +484,10 @@ void ForwardIterator::RebuildIterators(bool refresh_sv) {
|
||||
l0_iters_.push_back(cfd_->table_cache()->NewIterator(
|
||||
read_options_, *cfd_->soptions(), cfd_->internal_comparator(), l0->fd));
|
||||
}
|
||||
BuildLevelIterators(vstorage);
|
||||
current_ = nullptr;
|
||||
is_prev_set_ = false;
|
||||
}
|
||||
|
||||
void ForwardIterator::RenewIterators() {
|
||||
SuperVersion* svnew;
|
||||
assert(sv_);
|
||||
svnew = cfd_->GetReferencedSuperVersion(&(db_->mutex_));
|
||||
|
||||
if (mutable_iter_ != nullptr) {
|
||||
mutable_iter_->~InternalIterator();
|
||||
}
|
||||
for (auto* m : imm_iters_) {
|
||||
m->~InternalIterator();
|
||||
}
|
||||
imm_iters_.clear();
|
||||
|
||||
mutable_iter_ = svnew->mem->NewIterator(read_options_, &arena_);
|
||||
svnew->imm->AddIterators(read_options_, &imm_iters_, &arena_);
|
||||
|
||||
const auto* vstorage = sv_->current->storage_info();
|
||||
const auto& l0_files = vstorage->LevelFiles(0);
|
||||
const auto* vstorage_new = svnew->current->storage_info();
|
||||
const auto& l0_files_new = vstorage_new->LevelFiles(0);
|
||||
uint32_t iold, inew;
|
||||
bool found;
|
||||
std::vector<InternalIterator*> l0_iters_new;
|
||||
l0_iters_new.reserve(l0_files_new.size());
|
||||
|
||||
for (inew = 0; inew < l0_files_new.size(); inew++) {
|
||||
found = false;
|
||||
for (iold = 0; iold < l0_files.size(); iold++) {
|
||||
if (l0_files[iold] == l0_files_new[inew]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
if (l0_iters_[iold] == nullptr) {
|
||||
l0_iters_new.push_back(nullptr);
|
||||
TEST_SYNC_POINT_CALLBACK("ForwardIterator::RenewIterators:Null", this);
|
||||
} else {
|
||||
l0_iters_new.push_back(l0_iters_[iold]);
|
||||
l0_iters_[iold] = nullptr;
|
||||
TEST_SYNC_POINT_CALLBACK("ForwardIterator::RenewIterators:Copy", this);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
l0_iters_new.push_back(cfd_->table_cache()->NewIterator(
|
||||
read_options_, *cfd_->soptions(), cfd_->internal_comparator(),
|
||||
l0_files_new[inew]->fd));
|
||||
}
|
||||
|
||||
for (auto* f : l0_iters_) {
|
||||
delete f;
|
||||
}
|
||||
l0_iters_.clear();
|
||||
l0_iters_ = l0_iters_new;
|
||||
|
||||
for (auto* l : level_iters_) {
|
||||
delete l;
|
||||
}
|
||||
level_iters_.clear();
|
||||
BuildLevelIterators(vstorage_new);
|
||||
current_ = nullptr;
|
||||
is_prev_set_ = false;
|
||||
SVCleanup();
|
||||
sv_ = svnew;
|
||||
}
|
||||
|
||||
void ForwardIterator::BuildLevelIterators(const VersionStorageInfo* vstorage) {
|
||||
level_iters_.reserve(vstorage->num_levels() - 1);
|
||||
for (int32_t level = 1; level < vstorage->num_levels(); ++level) {
|
||||
const auto& level_files = vstorage->LevelFiles(level);
|
||||
|
||||
if ((level_files.empty()) ||
|
||||
((read_options_.iterate_upper_bound != nullptr) &&
|
||||
(user_comparator_->Compare(*read_options_.iterate_upper_bound,
|
||||
@@ -585,6 +502,9 @@ void ForwardIterator::BuildLevelIterators(const VersionStorageInfo* vstorage) {
|
||||
new LevelIterator(cfd_, read_options_, level_files));
|
||||
}
|
||||
}
|
||||
|
||||
current_ = nullptr;
|
||||
is_prev_set_ = false;
|
||||
}
|
||||
|
||||
void ForwardIterator::ResetIncompleteIterators() {
|
||||
|
||||
@@ -24,7 +24,6 @@ class Env;
|
||||
struct SuperVersion;
|
||||
class ColumnFamilyData;
|
||||
class LevelIterator;
|
||||
class VersionStorageInfo;
|
||||
struct FileMetaData;
|
||||
|
||||
class MinIterComparator {
|
||||
@@ -75,10 +74,7 @@ class ForwardIterator : public InternalIterator {
|
||||
|
||||
private:
|
||||
void Cleanup(bool release_sv);
|
||||
void SVCleanup();
|
||||
void RebuildIterators(bool refresh_sv);
|
||||
void RenewIterators();
|
||||
void BuildLevelIterators(const VersionStorageInfo* vstorage);
|
||||
void ResetIncompleteIterators();
|
||||
void SeekInternal(const Slice& internal_key, bool seek_to_first);
|
||||
void UpdateCurrent();
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#if !defined(GFLAGS) || defined(ROCKSDB_LITE)
|
||||
#include <cstdio>
|
||||
int main() {
|
||||
fprintf(stderr, "Please install gflags to run rocksdb tools\n");
|
||||
return 1;
|
||||
}
|
||||
#elif defined(OS_MACOSX) || defined(OS_WIN)
|
||||
// Block forward_iterator_bench under MAC and Windows
|
||||
int main() { return 0; }
|
||||
#else
|
||||
#include <gflags/gflags.h>
|
||||
#include <semaphore.h>
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <condition_variable>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
const int MAX_SHARDS = 100000;
|
||||
|
||||
DEFINE_int32(writers, 8, "");
|
||||
DEFINE_int32(readers, 8, "");
|
||||
DEFINE_int64(rate, 100000, "");
|
||||
DEFINE_int64(value_size, 300, "");
|
||||
DEFINE_int64(shards, 1000, "");
|
||||
DEFINE_int64(memtable_size, 500000000, "");
|
||||
DEFINE_int64(block_cache_size, 300000000, "");
|
||||
DEFINE_int64(block_size, 65536, "");
|
||||
DEFINE_double(runtime, 300.0, "");
|
||||
DEFINE_bool(cache_only_first, true, "");
|
||||
DEFINE_bool(iterate_upper_bound, true, "");
|
||||
|
||||
struct Stats {
|
||||
char pad1[128] __attribute__((__unused__));
|
||||
std::atomic<uint64_t> written{0};
|
||||
char pad2[128] __attribute__((__unused__));
|
||||
std::atomic<uint64_t> read{0};
|
||||
std::atomic<uint64_t> cache_misses{0};
|
||||
char pad3[128] __attribute__((__unused__));
|
||||
} stats;
|
||||
|
||||
struct Key {
|
||||
Key() {}
|
||||
Key(uint64_t shard_in, uint64_t seqno_in)
|
||||
: shard_be(htobe64(shard_in)), seqno_be(htobe64(seqno_in)) {}
|
||||
|
||||
uint64_t shard() const { return be64toh(shard_be); }
|
||||
uint64_t seqno() const { return be64toh(seqno_be); }
|
||||
|
||||
private:
|
||||
uint64_t shard_be;
|
||||
uint64_t seqno_be;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct Reader;
|
||||
struct Writer;
|
||||
|
||||
struct ShardState {
|
||||
char pad1[128] __attribute__((__unused__));
|
||||
std::atomic<uint64_t> last_written{0};
|
||||
Writer* writer;
|
||||
Reader* reader;
|
||||
char pad2[128] __attribute__((__unused__));
|
||||
std::atomic<uint64_t> last_read{0};
|
||||
std::unique_ptr<rocksdb::Iterator> it;
|
||||
std::unique_ptr<rocksdb::Iterator> it_cacheonly;
|
||||
Key upper_bound;
|
||||
rocksdb::Slice upper_bound_slice;
|
||||
char pad3[128] __attribute__((__unused__));
|
||||
};
|
||||
|
||||
struct Reader {
|
||||
public:
|
||||
explicit Reader(std::vector<ShardState>* shard_states, rocksdb::DB* db)
|
||||
: shard_states_(shard_states), db_(db) {
|
||||
sem_init(&sem_, 0, 0);
|
||||
thread_ = std::thread(&Reader::run, this);
|
||||
}
|
||||
|
||||
void run() {
|
||||
while (1) {
|
||||
sem_wait(&sem_);
|
||||
if (done_.load()) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t shard;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(queue_mutex_);
|
||||
assert(!shards_pending_queue_.empty());
|
||||
shard = shards_pending_queue_.front();
|
||||
shards_pending_queue_.pop();
|
||||
shards_pending_set_.reset(shard);
|
||||
}
|
||||
readOnceFromShard(shard);
|
||||
}
|
||||
}
|
||||
|
||||
void readOnceFromShard(uint64_t shard) {
|
||||
ShardState& state = (*shard_states_)[shard];
|
||||
if (!state.it) {
|
||||
// Initialize iterators
|
||||
rocksdb::ReadOptions options;
|
||||
options.tailing = true;
|
||||
if (FLAGS_iterate_upper_bound) {
|
||||
state.upper_bound = Key(shard, std::numeric_limits<uint64_t>::max());
|
||||
state.upper_bound_slice = rocksdb::Slice(
|
||||
(const char*)&state.upper_bound, sizeof(state.upper_bound));
|
||||
options.iterate_upper_bound = &state.upper_bound_slice;
|
||||
}
|
||||
|
||||
state.it.reset(db_->NewIterator(options));
|
||||
|
||||
if (FLAGS_cache_only_first) {
|
||||
options.read_tier = rocksdb::ReadTier::kBlockCacheTier;
|
||||
state.it_cacheonly.reset(db_->NewIterator(options));
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t upto = state.last_written.load();
|
||||
for (rocksdb::Iterator* it : {state.it_cacheonly.get(), state.it.get()}) {
|
||||
if (it == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (state.last_read.load() >= upto) {
|
||||
break;
|
||||
}
|
||||
bool need_seek = true;
|
||||
for (uint64_t seq = state.last_read.load() + 1; seq <= upto; ++seq) {
|
||||
if (need_seek) {
|
||||
Key from(shard, state.last_read.load() + 1);
|
||||
it->Seek(rocksdb::Slice((const char*)&from, sizeof(from)));
|
||||
need_seek = false;
|
||||
} else {
|
||||
it->Next();
|
||||
}
|
||||
if (it->status().IsIncomplete()) {
|
||||
++::stats.cache_misses;
|
||||
break;
|
||||
}
|
||||
assert(it->Valid());
|
||||
assert(it->key().size() == sizeof(Key));
|
||||
Key key;
|
||||
memcpy(&key, it->key().data(), it->key().size());
|
||||
// fprintf(stderr, "Expecting (%ld, %ld) read (%ld, %ld)\n",
|
||||
// shard, seq, key.shard(), key.seqno());
|
||||
assert(key.shard() == shard);
|
||||
assert(key.seqno() == seq);
|
||||
state.last_read.store(seq);
|
||||
++::stats.read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onWrite(uint64_t shard) {
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(queue_mutex_);
|
||||
if (!shards_pending_set_.test(shard)) {
|
||||
shards_pending_queue_.push(shard);
|
||||
shards_pending_set_.set(shard);
|
||||
sem_post(&sem_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Reader() {
|
||||
done_.store(true);
|
||||
sem_post(&sem_);
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
private:
|
||||
char pad1[128] __attribute__((__unused__));
|
||||
std::vector<ShardState>* shard_states_;
|
||||
rocksdb::DB* db_;
|
||||
std::thread thread_;
|
||||
sem_t sem_;
|
||||
std::mutex queue_mutex_;
|
||||
std::bitset<MAX_SHARDS + 1> shards_pending_set_;
|
||||
std::queue<uint64_t> shards_pending_queue_;
|
||||
std::atomic<bool> done_{false};
|
||||
char pad2[128] __attribute__((__unused__));
|
||||
};
|
||||
|
||||
struct Writer {
|
||||
explicit Writer(std::vector<ShardState>* shard_states, rocksdb::DB* db)
|
||||
: shard_states_(shard_states), db_(db) {}
|
||||
|
||||
void start() { thread_ = std::thread(&Writer::run, this); }
|
||||
|
||||
void run() {
|
||||
std::queue<std::chrono::steady_clock::time_point> workq;
|
||||
std::chrono::steady_clock::time_point deadline(
|
||||
std::chrono::steady_clock::now() +
|
||||
std::chrono::nanoseconds((uint64_t)(1000000000 * FLAGS_runtime)));
|
||||
std::vector<uint64_t> my_shards;
|
||||
for (int i = 1; i <= FLAGS_shards; ++i) {
|
||||
if ((*shard_states_)[i].writer == this) {
|
||||
my_shards.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
std::mt19937 rng{std::random_device()()};
|
||||
std::uniform_int_distribution<int> shard_dist(
|
||||
0, static_cast<int>(my_shards.size()) - 1);
|
||||
std::string value(FLAGS_value_size, '*');
|
||||
|
||||
while (1) {
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (FLAGS_runtime >= 0 && now >= deadline) {
|
||||
break;
|
||||
}
|
||||
if (workq.empty()) {
|
||||
for (int i = 0; i < FLAGS_rate; i += FLAGS_writers) {
|
||||
std::chrono::nanoseconds offset(1000000000LL * i / FLAGS_rate);
|
||||
workq.push(now + offset);
|
||||
}
|
||||
}
|
||||
while (!workq.empty() && workq.front() < now) {
|
||||
workq.pop();
|
||||
uint64_t shard = my_shards[shard_dist(rng)];
|
||||
ShardState& state = (*shard_states_)[shard];
|
||||
uint64_t seqno = state.last_written.load() + 1;
|
||||
Key key(shard, seqno);
|
||||
// fprintf(stderr, "Writing (%ld, %ld)\n", shard, seqno);
|
||||
rocksdb::Status status =
|
||||
db_->Put(rocksdb::WriteOptions(),
|
||||
rocksdb::Slice((const char*)&key, sizeof(key)),
|
||||
rocksdb::Slice(value));
|
||||
assert(status.ok());
|
||||
state.last_written.store(seqno);
|
||||
state.reader->onWrite(shard);
|
||||
++::stats.written;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
// fprintf(stderr, "Writer done\n");
|
||||
}
|
||||
|
||||
~Writer() { thread_.join(); }
|
||||
|
||||
private:
|
||||
char pad1[128] __attribute__((__unused__));
|
||||
std::vector<ShardState>* shard_states_;
|
||||
rocksdb::DB* db_;
|
||||
std::thread thread_;
|
||||
char pad2[128] __attribute__((__unused__));
|
||||
};
|
||||
|
||||
struct StatsThread {
|
||||
explicit StatsThread(rocksdb::DB* db)
|
||||
: db_(db), thread_(&StatsThread::run, this) {}
|
||||
|
||||
void run() {
|
||||
// using namespace std::chrono;
|
||||
auto tstart = std::chrono::steady_clock::now(), tlast = tstart;
|
||||
uint64_t wlast = 0, rlast = 0;
|
||||
while (!done_.load()) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(cvm_);
|
||||
cv_.wait_for(lock, std::chrono::seconds(1));
|
||||
}
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
double elapsed =
|
||||
std::chrono::duration_cast<std::chrono::duration<double> >(
|
||||
now - tlast).count();
|
||||
uint64_t w = ::stats.written.load();
|
||||
uint64_t r = ::stats.read.load();
|
||||
fprintf(stderr,
|
||||
"%s elapsed %4lds | written %10ld | w/s %10.0f | read %10ld | "
|
||||
"r/s %10.0f | cache misses %10ld\n",
|
||||
db_->GetEnv()->TimeToString(time(nullptr)).c_str(),
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - tstart)
|
||||
.count(),
|
||||
w, (w - wlast) / elapsed, r, (r - rlast) / elapsed,
|
||||
::stats.cache_misses.load());
|
||||
wlast = w;
|
||||
rlast = r;
|
||||
tlast = now;
|
||||
}
|
||||
}
|
||||
|
||||
~StatsThread() {
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(cvm_);
|
||||
done_.store(true);
|
||||
}
|
||||
cv_.notify_all();
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
private:
|
||||
rocksdb::DB* db_;
|
||||
std::mutex cvm_;
|
||||
std::condition_variable cv_;
|
||||
std::thread thread_;
|
||||
std::atomic<bool> done_{false};
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
GFLAGS::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
std::mt19937 rng{std::random_device()()};
|
||||
rocksdb::Status status;
|
||||
std::string path = rocksdb::test::TmpDir() + "/forward_iterator_test";
|
||||
fprintf(stderr, "db path is %s\n", path.c_str());
|
||||
rocksdb::Options options;
|
||||
options.create_if_missing = true;
|
||||
options.compression = rocksdb::CompressionType::kNoCompression;
|
||||
options.compaction_style = rocksdb::CompactionStyle::kCompactionStyleNone;
|
||||
options.level0_slowdown_writes_trigger = 99999;
|
||||
options.level0_stop_writes_trigger = 99999;
|
||||
options.allow_os_buffer = false;
|
||||
options.write_buffer_size = FLAGS_memtable_size;
|
||||
rocksdb::BlockBasedTableOptions table_options;
|
||||
table_options.block_cache = rocksdb::NewLRUCache(FLAGS_block_cache_size);
|
||||
table_options.block_size = FLAGS_block_size;
|
||||
options.table_factory.reset(
|
||||
rocksdb::NewBlockBasedTableFactory(table_options));
|
||||
|
||||
status = rocksdb::DestroyDB(path, options);
|
||||
assert(status.ok());
|
||||
rocksdb::DB* db_raw;
|
||||
status = rocksdb::DB::Open(options, path, &db_raw);
|
||||
assert(status.ok());
|
||||
std::unique_ptr<rocksdb::DB> db(db_raw);
|
||||
|
||||
std::vector<ShardState> shard_states(FLAGS_shards + 1);
|
||||
std::deque<Reader> readers;
|
||||
while (static_cast<int>(readers.size()) < FLAGS_readers) {
|
||||
readers.emplace_back(&shard_states, db_raw);
|
||||
}
|
||||
std::deque<Writer> writers;
|
||||
while (static_cast<int>(writers.size()) < FLAGS_writers) {
|
||||
writers.emplace_back(&shard_states, db_raw);
|
||||
}
|
||||
|
||||
// Each shard gets a random reader and random writer assigned to it
|
||||
for (int i = 1; i <= FLAGS_shards; ++i) {
|
||||
std::uniform_int_distribution<int> reader_dist(0, FLAGS_readers - 1);
|
||||
std::uniform_int_distribution<int> writer_dist(0, FLAGS_writers - 1);
|
||||
shard_states[i].reader = &readers[reader_dist(rng)];
|
||||
shard_states[i].writer = &writers[writer_dist(rng)];
|
||||
}
|
||||
|
||||
StatsThread stats_thread(db_raw);
|
||||
for (Writer& w : writers) {
|
||||
w.start();
|
||||
}
|
||||
|
||||
writers.clear();
|
||||
readers.clear();
|
||||
}
|
||||
#endif // !defined(GFLAGS) || defined(ROCKSDB_LITE)
|
||||
@@ -1,550 +0,0 @@
|
||||
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional
|
||||
// grant of patent rights can be found in the PATENTS file in the same
|
||||
// directory.
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved. Use of
|
||||
// this source code is governed by a BSD-style license that can be found
|
||||
// in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// InlineSkipList is derived from SkipList (skiplist.h), but it optimizes
|
||||
// the memory layout by requiring that the key storage be allocated through
|
||||
// the skip list instance. For the common case of SkipList<const char*,
|
||||
// Cmp> this saves 1 pointer per skip list node and gives better cache
|
||||
// locality, at the expense of wasted padding from using AllocateAligned
|
||||
// instead of Allocate for the keys. The unused padding will be from
|
||||
// 0 to sizeof(void*)-1 bytes, and the space savings are sizeof(void*)
|
||||
// bytes, so despite the padding the space used is always less than
|
||||
// SkipList<const char*, ..>.
|
||||
//
|
||||
// Thread safety -------------
|
||||
//
|
||||
// Writes require external synchronization, most likely a mutex. Reads
|
||||
// require a guarantee that the InlineSkipList will not be destroyed while
|
||||
// the read is in progress. Apart from that, reads progress without any
|
||||
// internal locking or synchronization.
|
||||
//
|
||||
// Invariants:
|
||||
//
|
||||
// (1) Allocated nodes are never deleted until the InlineSkipList is
|
||||
// destroyed. This is trivially guaranteed by the code since we never
|
||||
// delete any skip list nodes.
|
||||
//
|
||||
// (2) The contents of a Node except for the next/prev pointers are
|
||||
// immutable after the Node has been linked into the InlineSkipList.
|
||||
// Only Insert() modifies the list, and it is careful to initialize a
|
||||
// node and use release-stores to publish the nodes in one or more lists.
|
||||
//
|
||||
// ... prev vs. next pointer ordering ...
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <atomic>
|
||||
#include "port/port.h"
|
||||
#include "util/allocator.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
template <class Comparator>
|
||||
class InlineSkipList {
|
||||
private:
|
||||
struct Node;
|
||||
|
||||
public:
|
||||
// Create a new InlineSkipList object that will use "cmp" for comparing
|
||||
// keys, and will allocate memory using "*allocator". Objects allocated
|
||||
// in the allocator must remain allocated for the lifetime of the
|
||||
// skiplist object.
|
||||
explicit InlineSkipList(Comparator cmp, Allocator* allocator,
|
||||
int32_t max_height = 12,
|
||||
int32_t branching_factor = 4);
|
||||
|
||||
// Allocates a key and a skip-list node, returning a pointer to the
|
||||
// key portion of the node.
|
||||
char* AllocateKey(size_t key_size);
|
||||
|
||||
// Inserts a key allocated by AllocateKey, after the actual key value
|
||||
// has been filled in.
|
||||
//
|
||||
// REQUIRES: nothing that compares equal to key is currently in the list.
|
||||
void Insert(const char* key);
|
||||
|
||||
// Returns true iff an entry that compares equal to key is in the list.
|
||||
bool Contains(const char* key) const;
|
||||
|
||||
// Return estimated number of entries smaller than `key`.
|
||||
uint64_t EstimateCount(const char* key) const;
|
||||
|
||||
// Iteration over the contents of a skip list
|
||||
class Iterator {
|
||||
public:
|
||||
// Initialize an iterator over the specified list.
|
||||
// The returned iterator is not valid.
|
||||
explicit Iterator(const InlineSkipList* list);
|
||||
|
||||
// Change the underlying skiplist used for this iterator
|
||||
// This enables us not changing the iterator without deallocating
|
||||
// an old one and then allocating a new one
|
||||
void SetList(const InlineSkipList* list);
|
||||
|
||||
// Returns true iff the iterator is positioned at a valid node.
|
||||
bool Valid() const;
|
||||
|
||||
// Returns the key at the current position.
|
||||
// REQUIRES: Valid()
|
||||
const char* key() const;
|
||||
|
||||
// Advances to the next position.
|
||||
// REQUIRES: Valid()
|
||||
void Next();
|
||||
|
||||
// Advances to the previous position.
|
||||
// REQUIRES: Valid()
|
||||
void Prev();
|
||||
|
||||
// Advance to the first entry with a key >= target
|
||||
void Seek(const char* target);
|
||||
|
||||
// Position at the first entry in list.
|
||||
// Final state of iterator is Valid() iff list is not empty.
|
||||
void SeekToFirst();
|
||||
|
||||
// Position at the last entry in list.
|
||||
// Final state of iterator is Valid() iff list is not empty.
|
||||
void SeekToLast();
|
||||
|
||||
private:
|
||||
const InlineSkipList* list_;
|
||||
Node* node_;
|
||||
// Intentionally copyable
|
||||
};
|
||||
|
||||
private:
|
||||
const uint16_t kMaxHeight_;
|
||||
const uint16_t kBranching_;
|
||||
const uint32_t kScaledInverseBranching_;
|
||||
|
||||
// Immutable after construction
|
||||
Comparator const compare_;
|
||||
Allocator* const allocator_; // Allocator used for allocations of nodes
|
||||
|
||||
Node* const head_;
|
||||
|
||||
// Modified only by Insert(). Read racily by readers, but stale
|
||||
// values are ok.
|
||||
std::atomic<int> max_height_; // Height of the entire list
|
||||
|
||||
// Used for optimizing sequential insert patterns. Tricky. prev_[i] for
|
||||
// i up to max_height_ is the predecessor of prev_[0] and prev_height_
|
||||
// is the height of prev_[0]. prev_[0] can only be equal to head before
|
||||
// insertion, in which case max_height_ and prev_height_ are 1.
|
||||
Node** prev_;
|
||||
int32_t prev_height_;
|
||||
|
||||
inline int GetMaxHeight() const {
|
||||
return max_height_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
int RandomHeight();
|
||||
|
||||
Node* AllocateNode(size_t key_size, int height);
|
||||
|
||||
bool Equal(const char* a, const char* b) const {
|
||||
return (compare_(a, b) == 0);
|
||||
}
|
||||
|
||||
// Return true if key is greater than the data stored in "n". Null n
|
||||
// is considered infinite.
|
||||
bool KeyIsAfterNode(const char* key, Node* n) const;
|
||||
|
||||
// Returns the earliest node with a key >= key.
|
||||
// Return nullptr if there is no such node.
|
||||
Node* FindGreaterOrEqual(const char* key) const;
|
||||
|
||||
// Return the latest node with a key < key.
|
||||
// Return head_ if there is no such node.
|
||||
// Fills prev[level] with pointer to previous node at "level" for every
|
||||
// level in [0..max_height_-1], if prev is non-null.
|
||||
Node* FindLessThan(const char* key, Node** prev = nullptr) const;
|
||||
|
||||
// Return the last node in the list.
|
||||
// Return head_ if list is empty.
|
||||
Node* FindLast() const;
|
||||
|
||||
// No copying allowed
|
||||
InlineSkipList(const InlineSkipList&);
|
||||
InlineSkipList& operator=(const InlineSkipList&);
|
||||
};
|
||||
|
||||
// Implementation details follow
|
||||
|
||||
// The Node data type is more of a pointer into custom-managed memory than
|
||||
// a traditional C++ struct. The key is stored in the bytes immediately
|
||||
// after the struct, and the next_ pointers for nodes with height > 1 are
|
||||
// stored immediately _before_ the struct. This avoids the need to include
|
||||
// any pointer or sizing data, which reduces per-node memory overheads.
|
||||
template <class Comparator>
|
||||
struct InlineSkipList<Comparator>::Node {
|
||||
// Stores the height of the node in the memory location normally used for
|
||||
// next_[0]. This is used for passing data from AllocateKey to Insert.
|
||||
void StashHeight(const int height) {
|
||||
assert(sizeof(int) <= sizeof(next_[0]));
|
||||
memcpy(&next_[0], &height, sizeof(int));
|
||||
}
|
||||
|
||||
// Retrieves the value passed to StashHeight. Undefined after a call
|
||||
// to SetNext or NoBarrier_SetNext.
|
||||
int UnstashHeight() const {
|
||||
int rv;
|
||||
memcpy(&rv, &next_[0], sizeof(int));
|
||||
return rv;
|
||||
}
|
||||
|
||||
const char* Key() const { return reinterpret_cast<const char*>(&next_[1]); }
|
||||
|
||||
// Accessors/mutators for links. Wrapped in methods so we can add
|
||||
// the appropriate barriers as necessary, and perform the necessary
|
||||
// addressing trickery for storing links below the Node in memory.
|
||||
Node* Next(int n) {
|
||||
assert(n >= 0);
|
||||
// Use an 'acquire load' so that we observe a fully initialized
|
||||
// version of the returned Node.
|
||||
return (next_[-n].load(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
void SetNext(int n, Node* x) {
|
||||
assert(n >= 0);
|
||||
// Use a 'release store' so that anybody who reads through this
|
||||
// pointer observes a fully initialized version of the inserted node.
|
||||
next_[-n].store(x, std::memory_order_release);
|
||||
}
|
||||
|
||||
// No-barrier variants that can be safely used in a few locations.
|
||||
Node* NoBarrier_Next(int n) {
|
||||
assert(n >= 0);
|
||||
return next_[-n].load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void NoBarrier_SetNext(int n, Node* x) {
|
||||
assert(n >= 0);
|
||||
next_[-n].store(x, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
private:
|
||||
// next_[0] is the lowest level link (level 0). Higher levels are
|
||||
// stored _earlier_, so level 1 is at next_[-1].
|
||||
std::atomic<Node*> next_[1];
|
||||
};
|
||||
|
||||
template <class Comparator>
|
||||
inline InlineSkipList<Comparator>::Iterator::Iterator(
|
||||
const InlineSkipList* list) {
|
||||
SetList(list);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline void InlineSkipList<Comparator>::Iterator::SetList(
|
||||
const InlineSkipList* list) {
|
||||
list_ = list;
|
||||
node_ = nullptr;
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline bool InlineSkipList<Comparator>::Iterator::Valid() const {
|
||||
return node_ != nullptr;
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline const char* InlineSkipList<Comparator>::Iterator::key() const {
|
||||
assert(Valid());
|
||||
return node_->Key();
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline void InlineSkipList<Comparator>::Iterator::Next() {
|
||||
assert(Valid());
|
||||
node_ = node_->Next(0);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline void InlineSkipList<Comparator>::Iterator::Prev() {
|
||||
// Instead of using explicit "prev" links, we just search for the
|
||||
// last node that falls before key.
|
||||
assert(Valid());
|
||||
node_ = list_->FindLessThan(node_->Key());
|
||||
if (node_ == list_->head_) {
|
||||
node_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline void InlineSkipList<Comparator>::Iterator::Seek(const char* target) {
|
||||
node_ = list_->FindGreaterOrEqual(target);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline void InlineSkipList<Comparator>::Iterator::SeekToFirst() {
|
||||
node_ = list_->head_->Next(0);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
inline void InlineSkipList<Comparator>::Iterator::SeekToLast() {
|
||||
node_ = list_->FindLast();
|
||||
if (node_ == list_->head_) {
|
||||
node_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
int InlineSkipList<Comparator>::RandomHeight() {
|
||||
auto rnd = Random::GetTLSInstance();
|
||||
|
||||
// Increase height with probability 1 in kBranching
|
||||
int height = 1;
|
||||
while (height < kMaxHeight_ && rnd->Next() < kScaledInverseBranching_) {
|
||||
height++;
|
||||
}
|
||||
assert(height > 0);
|
||||
assert(height <= kMaxHeight_);
|
||||
return height;
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
bool InlineSkipList<Comparator>::KeyIsAfterNode(const char* key,
|
||||
Node* n) const {
|
||||
// nullptr n is considered infinite
|
||||
return (n != nullptr) && (compare_(n->Key(), key) < 0);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
typename InlineSkipList<Comparator>::Node*
|
||||
InlineSkipList<Comparator>::FindGreaterOrEqual(const char* key) const {
|
||||
// Note: It looks like we could reduce duplication by implementing
|
||||
// this function as FindLessThan(key)->Next(0), but we wouldn't be able
|
||||
// to exit early on equality and the result wouldn't even be correct.
|
||||
// A concurrent insert might occur after FindLessThan(key) but before
|
||||
// we get a chance to call Next(0).
|
||||
Node* x = head_;
|
||||
int level = GetMaxHeight() - 1;
|
||||
Node* last_bigger = nullptr;
|
||||
while (true) {
|
||||
Node* next = x->Next(level);
|
||||
// Make sure the lists are sorted
|
||||
assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x));
|
||||
// Make sure we haven't overshot during our search
|
||||
assert(x == head_ || KeyIsAfterNode(key, x));
|
||||
int cmp = (next == nullptr || next == last_bigger)
|
||||
? 1
|
||||
: compare_(next->Key(), key);
|
||||
if (cmp == 0 || (cmp > 0 && level == 0)) {
|
||||
return next;
|
||||
} else if (cmp < 0) {
|
||||
// Keep searching in this list
|
||||
x = next;
|
||||
} else {
|
||||
// Switch to next list, reuse compare_() result
|
||||
last_bigger = next;
|
||||
level--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
typename InlineSkipList<Comparator>::Node*
|
||||
InlineSkipList<Comparator>::FindLessThan(const char* key, Node** prev) const {
|
||||
Node* x = head_;
|
||||
int level = GetMaxHeight() - 1;
|
||||
// KeyIsAfter(key, last_not_after) is definitely false
|
||||
Node* last_not_after = nullptr;
|
||||
while (true) {
|
||||
Node* next = x->Next(level);
|
||||
assert(x == head_ || next == nullptr || KeyIsAfterNode(next->Key(), x));
|
||||
assert(x == head_ || KeyIsAfterNode(key, x));
|
||||
if (next != last_not_after && KeyIsAfterNode(key, next)) {
|
||||
// Keep searching in this list
|
||||
x = next;
|
||||
} else {
|
||||
if (prev != nullptr) {
|
||||
prev[level] = x;
|
||||
}
|
||||
if (level == 0) {
|
||||
return x;
|
||||
} else {
|
||||
// Switch to next list, reuse KeyIUsAfterNode() result
|
||||
last_not_after = next;
|
||||
level--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
typename InlineSkipList<Comparator>::Node*
|
||||
InlineSkipList<Comparator>::FindLast() const {
|
||||
Node* x = head_;
|
||||
int level = GetMaxHeight() - 1;
|
||||
while (true) {
|
||||
Node* next = x->Next(level);
|
||||
if (next == nullptr) {
|
||||
if (level == 0) {
|
||||
return x;
|
||||
} else {
|
||||
// Switch to next list
|
||||
level--;
|
||||
}
|
||||
} else {
|
||||
x = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
uint64_t InlineSkipList<Comparator>::EstimateCount(const char* key) const {
|
||||
uint64_t count = 0;
|
||||
|
||||
Node* x = head_;
|
||||
int level = GetMaxHeight() - 1;
|
||||
while (true) {
|
||||
assert(x == head_ || compare_(x->Key(), key) < 0);
|
||||
Node* next = x->Next(level);
|
||||
if (next == nullptr || compare_(next->Key(), key) >= 0) {
|
||||
if (level == 0) {
|
||||
return count;
|
||||
} else {
|
||||
// Switch to next list
|
||||
count *= kBranching_;
|
||||
level--;
|
||||
}
|
||||
} else {
|
||||
x = next;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
InlineSkipList<Comparator>::InlineSkipList(const Comparator cmp,
|
||||
Allocator* allocator,
|
||||
int32_t max_height,
|
||||
int32_t branching_factor)
|
||||
: kMaxHeight_(max_height),
|
||||
kBranching_(branching_factor),
|
||||
kScaledInverseBranching_((Random::kMaxNext + 1) / kBranching_),
|
||||
compare_(cmp),
|
||||
allocator_(allocator),
|
||||
head_(AllocateNode(0, max_height)),
|
||||
max_height_(1),
|
||||
prev_height_(1) {
|
||||
assert(max_height > 0 && kMaxHeight_ == static_cast<uint32_t>(max_height));
|
||||
assert(branching_factor > 0 &&
|
||||
kBranching_ == static_cast<uint32_t>(branching_factor));
|
||||
assert(kScaledInverseBranching_ > 0);
|
||||
// Allocate the prev_ Node* array, directly from the passed-in allocator.
|
||||
// prev_ does not need to be freed, as its life cycle is tied up with
|
||||
// the allocator as a whole.
|
||||
prev_ = reinterpret_cast<Node**>(
|
||||
allocator_->AllocateAligned(sizeof(Node*) * kMaxHeight_));
|
||||
for (int i = 0; i < kMaxHeight_; i++) {
|
||||
head_->SetNext(i, nullptr);
|
||||
prev_[i] = head_;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
char* InlineSkipList<Comparator>::AllocateKey(size_t key_size) {
|
||||
return const_cast<char*>(AllocateNode(key_size, RandomHeight())->Key());
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
typename InlineSkipList<Comparator>::Node*
|
||||
InlineSkipList<Comparator>::AllocateNode(size_t key_size, int height) {
|
||||
auto prefix = sizeof(std::atomic<Node*>) * (height - 1);
|
||||
|
||||
// prefix is space for the height - 1 pointers that we store before
|
||||
// the Node instance (next_[-(height - 1) .. -1]). Node starts at
|
||||
// raw + prefix, and holds the bottom-mode (level 0) skip list pointer
|
||||
// next_[0]. key_size is the bytes for the key, which comes just after
|
||||
// the Node.
|
||||
char* raw = allocator_->AllocateAligned(prefix + sizeof(Node) + key_size);
|
||||
Node* x = reinterpret_cast<Node*>(raw + prefix);
|
||||
|
||||
// Once we've linked the node into the skip list we don't actually need
|
||||
// to know its height, because we can implicitly use the fact that we
|
||||
// traversed into a node at level h to known that h is a valid level
|
||||
// for that node. We need to convey the height to the Insert step,
|
||||
// however, so that it can perform the proper links. Since we're not
|
||||
// using the pointers at the moment, StashHeight temporarily borrow
|
||||
// storage from next_[0] for that purpose.
|
||||
x->StashHeight(height);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void InlineSkipList<Comparator>::Insert(const char* key) {
|
||||
// fast path for sequential insertion
|
||||
if (!KeyIsAfterNode(key, prev_[0]->NoBarrier_Next(0)) &&
|
||||
(prev_[0] == head_ || KeyIsAfterNode(key, prev_[0]))) {
|
||||
assert(prev_[0] != head_ || (prev_height_ == 1 && GetMaxHeight() == 1));
|
||||
|
||||
// Outside of this method prev_[1..max_height_] is the predecessor
|
||||
// of prev_[0], and prev_height_ refers to prev_[0]. Inside Insert
|
||||
// prev_[0..max_height - 1] is the predecessor of key. Switch from
|
||||
// the external state to the internal
|
||||
for (int i = 1; i < prev_height_; i++) {
|
||||
prev_[i] = prev_[0];
|
||||
}
|
||||
} else {
|
||||
// TODO(opt): we could use a NoBarrier predecessor search as an
|
||||
// optimization for architectures where memory_order_acquire needs
|
||||
// a synchronization instruction. Doesn't matter on x86
|
||||
FindLessThan(key, prev_);
|
||||
}
|
||||
|
||||
// Our data structure does not allow duplicate insertion
|
||||
assert(prev_[0]->Next(0) == nullptr || !Equal(key, prev_[0]->Next(0)->Key()));
|
||||
|
||||
// Find the Node that we placed before the key in AllocateKey
|
||||
Node* x = reinterpret_cast<Node*>(const_cast<char*>(key)) - 1;
|
||||
int height = x->UnstashHeight();
|
||||
assert(height >= 1 && height <= kMaxHeight_);
|
||||
|
||||
if (height > GetMaxHeight()) {
|
||||
for (int i = GetMaxHeight(); i < height; i++) {
|
||||
prev_[i] = head_;
|
||||
}
|
||||
|
||||
// It is ok to mutate max_height_ without any synchronization
|
||||
// with concurrent readers. A concurrent reader that observes
|
||||
// the new value of max_height_ will see either the old value of
|
||||
// new level pointers from head_ (nullptr), or a new value set in
|
||||
// the loop below. In the former case the reader will
|
||||
// immediately drop to the next level since nullptr sorts after all
|
||||
// keys. In the latter case the reader will use the new node.
|
||||
max_height_.store(height, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
// NoBarrier_SetNext() suffices since we will add a barrier when
|
||||
// we publish a pointer to "x" in prev[i].
|
||||
x->NoBarrier_SetNext(i, prev_[i]->NoBarrier_Next(i));
|
||||
prev_[i]->SetNext(i, x);
|
||||
}
|
||||
prev_[0] = x;
|
||||
prev_height_ = height;
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
bool InlineSkipList<Comparator>::Contains(const char* key) const {
|
||||
Node* x = FindGreaterOrEqual(key);
|
||||
if (x != nullptr && Equal(key, x->Key())) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
@@ -1,391 +0,0 @@
|
||||
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "db/inlineskiplist.h"
|
||||
#include <set>
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/arena.h"
|
||||
#include "util/hash.h"
|
||||
#include "util/random.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
// Our test skip list stores 8-byte unsigned integers
|
||||
typedef uint64_t Key;
|
||||
|
||||
static const char* Encode(const uint64_t* key) {
|
||||
return reinterpret_cast<const char*>(key);
|
||||
}
|
||||
|
||||
static Key Decode(const char* key) {
|
||||
Key rv;
|
||||
memcpy(&rv, key, sizeof(Key));
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct TestComparator {
|
||||
int operator()(const char* a, const char* b) const {
|
||||
if (Decode(a) < Decode(b)) {
|
||||
return -1;
|
||||
} else if (Decode(a) > Decode(b)) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class InlineSkipTest : public testing::Test {};
|
||||
|
||||
TEST_F(InlineSkipTest, Empty) {
|
||||
Arena arena;
|
||||
TestComparator cmp;
|
||||
InlineSkipList<TestComparator> list(cmp, &arena);
|
||||
Key key = 10;
|
||||
ASSERT_TRUE(!list.Contains(Encode(&key)));
|
||||
|
||||
InlineSkipList<TestComparator>::Iterator iter(&list);
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
iter.SeekToFirst();
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
key = 100;
|
||||
iter.Seek(Encode(&key));
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
iter.SeekToLast();
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
}
|
||||
|
||||
TEST_F(InlineSkipTest, InsertAndLookup) {
|
||||
const int N = 2000;
|
||||
const int R = 5000;
|
||||
Random rnd(1000);
|
||||
std::set<Key> keys;
|
||||
Arena arena;
|
||||
TestComparator cmp;
|
||||
InlineSkipList<TestComparator> list(cmp, &arena);
|
||||
for (int i = 0; i < N; i++) {
|
||||
Key key = rnd.Next() % R;
|
||||
if (keys.insert(key).second) {
|
||||
char* buf = list.AllocateKey(sizeof(Key));
|
||||
memcpy(buf, &key, sizeof(Key));
|
||||
list.Insert(buf);
|
||||
}
|
||||
}
|
||||
|
||||
for (Key i = 0; i < R; i++) {
|
||||
if (list.Contains(Encode(&i))) {
|
||||
ASSERT_EQ(keys.count(i), 1U);
|
||||
} else {
|
||||
ASSERT_EQ(keys.count(i), 0U);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple iterator tests
|
||||
{
|
||||
InlineSkipList<TestComparator>::Iterator iter(&list);
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
|
||||
uint64_t zero = 0;
|
||||
iter.Seek(Encode(&zero));
|
||||
ASSERT_TRUE(iter.Valid());
|
||||
ASSERT_EQ(*(keys.begin()), Decode(iter.key()));
|
||||
|
||||
iter.SeekToFirst();
|
||||
ASSERT_TRUE(iter.Valid());
|
||||
ASSERT_EQ(*(keys.begin()), Decode(iter.key()));
|
||||
|
||||
iter.SeekToLast();
|
||||
ASSERT_TRUE(iter.Valid());
|
||||
ASSERT_EQ(*(keys.rbegin()), Decode(iter.key()));
|
||||
}
|
||||
|
||||
// Forward iteration test
|
||||
for (Key i = 0; i < R; i++) {
|
||||
InlineSkipList<TestComparator>::Iterator iter(&list);
|
||||
iter.Seek(Encode(&i));
|
||||
|
||||
// Compare against model iterator
|
||||
std::set<Key>::iterator model_iter = keys.lower_bound(i);
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (model_iter == keys.end()) {
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
break;
|
||||
} else {
|
||||
ASSERT_TRUE(iter.Valid());
|
||||
ASSERT_EQ(*model_iter, Decode(iter.key()));
|
||||
++model_iter;
|
||||
iter.Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Backward iteration test
|
||||
{
|
||||
InlineSkipList<TestComparator>::Iterator iter(&list);
|
||||
iter.SeekToLast();
|
||||
|
||||
// Compare against model iterator
|
||||
for (std::set<Key>::reverse_iterator model_iter = keys.rbegin();
|
||||
model_iter != keys.rend(); ++model_iter) {
|
||||
ASSERT_TRUE(iter.Valid());
|
||||
ASSERT_EQ(*model_iter, Decode(iter.key()));
|
||||
iter.Prev();
|
||||
}
|
||||
ASSERT_TRUE(!iter.Valid());
|
||||
}
|
||||
}
|
||||
|
||||
// We want to make sure that with a single writer and multiple
|
||||
// concurrent readers (with no synchronization other than when a
|
||||
// reader's iterator is created), the reader always observes all the
|
||||
// data that was present in the skip list when the iterator was
|
||||
// constructor. Because insertions are happening concurrently, we may
|
||||
// also observe new values that were inserted since the iterator was
|
||||
// constructed, but we should never miss any values that were present
|
||||
// at iterator construction time.
|
||||
//
|
||||
// We generate multi-part keys:
|
||||
// <key,gen,hash>
|
||||
// where:
|
||||
// key is in range [0..K-1]
|
||||
// gen is a generation number for key
|
||||
// hash is hash(key,gen)
|
||||
//
|
||||
// The insertion code picks a random key, sets gen to be 1 + the last
|
||||
// generation number inserted for that key, and sets hash to Hash(key,gen).
|
||||
//
|
||||
// At the beginning of a read, we snapshot the last inserted
|
||||
// generation number for each key. We then iterate, including random
|
||||
// calls to Next() and Seek(). For every key we encounter, we
|
||||
// check that it is either expected given the initial snapshot or has
|
||||
// been concurrently added since the iterator started.
|
||||
class ConcurrentTest {
|
||||
private:
|
||||
static const uint32_t K = 4;
|
||||
|
||||
static uint64_t key(Key key) { return (key >> 40); }
|
||||
static uint64_t gen(Key key) { return (key >> 8) & 0xffffffffu; }
|
||||
static uint64_t hash(Key key) { return key & 0xff; }
|
||||
|
||||
static uint64_t HashNumbers(uint64_t k, uint64_t g) {
|
||||
uint64_t data[2] = {k, g};
|
||||
return Hash(reinterpret_cast<char*>(data), sizeof(data), 0);
|
||||
}
|
||||
|
||||
static Key MakeKey(uint64_t k, uint64_t g) {
|
||||
assert(sizeof(Key) == sizeof(uint64_t));
|
||||
assert(k <= K); // We sometimes pass K to seek to the end of the skiplist
|
||||
assert(g <= 0xffffffffu);
|
||||
return ((k << 40) | (g << 8) | (HashNumbers(k, g) & 0xff));
|
||||
}
|
||||
|
||||
static bool IsValidKey(Key k) {
|
||||
return hash(k) == (HashNumbers(key(k), gen(k)) & 0xff);
|
||||
}
|
||||
|
||||
static Key RandomTarget(Random* rnd) {
|
||||
switch (rnd->Next() % 10) {
|
||||
case 0:
|
||||
// Seek to beginning
|
||||
return MakeKey(0, 0);
|
||||
case 1:
|
||||
// Seek to end
|
||||
return MakeKey(K, 0);
|
||||
default:
|
||||
// Seek to middle
|
||||
return MakeKey(rnd->Next() % K, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Per-key generation
|
||||
struct State {
|
||||
std::atomic<int> generation[K];
|
||||
void Set(int k, int v) {
|
||||
generation[k].store(v, std::memory_order_release);
|
||||
}
|
||||
int Get(int k) { return generation[k].load(std::memory_order_acquire); }
|
||||
|
||||
State() {
|
||||
for (unsigned int k = 0; k < K; k++) {
|
||||
Set(k, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Current state of the test
|
||||
State current_;
|
||||
|
||||
Arena arena_;
|
||||
|
||||
// InlineSkipList is not protected by mu_. We just use a single writer
|
||||
// thread to modify it.
|
||||
InlineSkipList<TestComparator> list_;
|
||||
|
||||
public:
|
||||
ConcurrentTest() : list_(TestComparator(), &arena_) {}
|
||||
|
||||
// REQUIRES: External synchronization
|
||||
void WriteStep(Random* rnd) {
|
||||
const uint32_t k = rnd->Next() % K;
|
||||
const int g = current_.Get(k) + 1;
|
||||
const Key new_key = MakeKey(k, g);
|
||||
char* buf = list_.AllocateKey(sizeof(Key));
|
||||
memcpy(buf, &new_key, sizeof(Key));
|
||||
list_.Insert(buf);
|
||||
current_.Set(k, g);
|
||||
}
|
||||
|
||||
void ReadStep(Random* rnd) {
|
||||
// Remember the initial committed state of the skiplist.
|
||||
State initial_state;
|
||||
for (unsigned int k = 0; k < K; k++) {
|
||||
initial_state.Set(k, current_.Get(k));
|
||||
}
|
||||
|
||||
Key pos = RandomTarget(rnd);
|
||||
InlineSkipList<TestComparator>::Iterator iter(&list_);
|
||||
iter.Seek(Encode(&pos));
|
||||
while (true) {
|
||||
Key current;
|
||||
if (!iter.Valid()) {
|
||||
current = MakeKey(K, 0);
|
||||
} else {
|
||||
current = Decode(iter.key());
|
||||
ASSERT_TRUE(IsValidKey(current)) << current;
|
||||
}
|
||||
ASSERT_LE(pos, current) << "should not go backwards";
|
||||
|
||||
// Verify that everything in [pos,current) was not present in
|
||||
// initial_state.
|
||||
while (pos < current) {
|
||||
ASSERT_LT(key(pos), K) << pos;
|
||||
|
||||
// Note that generation 0 is never inserted, so it is ok if
|
||||
// <*,0,*> is missing.
|
||||
ASSERT_TRUE((gen(pos) == 0U) ||
|
||||
(gen(pos) > static_cast<uint64_t>(initial_state.Get(
|
||||
static_cast<int>(key(pos))))))
|
||||
<< "key: " << key(pos) << "; gen: " << gen(pos)
|
||||
<< "; initgen: " << initial_state.Get(static_cast<int>(key(pos)));
|
||||
|
||||
// Advance to next key in the valid key space
|
||||
if (key(pos) < key(current)) {
|
||||
pos = MakeKey(key(pos) + 1, 0);
|
||||
} else {
|
||||
pos = MakeKey(key(pos), gen(pos) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!iter.Valid()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rnd->Next() % 2) {
|
||||
iter.Next();
|
||||
pos = MakeKey(key(pos), gen(pos) + 1);
|
||||
} else {
|
||||
Key new_target = RandomTarget(rnd);
|
||||
if (new_target > pos) {
|
||||
pos = new_target;
|
||||
iter.Seek(Encode(&new_target));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const uint32_t ConcurrentTest::K;
|
||||
|
||||
// Simple test that does single-threaded testing of the ConcurrentTest
|
||||
// scaffolding.
|
||||
TEST_F(InlineSkipTest, ConcurrentWithoutThreads) {
|
||||
ConcurrentTest test;
|
||||
Random rnd(test::RandomSeed());
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
test.ReadStep(&rnd);
|
||||
test.WriteStep(&rnd);
|
||||
}
|
||||
}
|
||||
|
||||
class TestState {
|
||||
public:
|
||||
ConcurrentTest t_;
|
||||
int seed_;
|
||||
std::atomic<bool> quit_flag_;
|
||||
|
||||
enum ReaderState { STARTING, RUNNING, DONE };
|
||||
|
||||
explicit TestState(int s)
|
||||
: seed_(s), quit_flag_(false), state_(STARTING), state_cv_(&mu_) {}
|
||||
|
||||
void Wait(ReaderState s) {
|
||||
mu_.Lock();
|
||||
while (state_ != s) {
|
||||
state_cv_.Wait();
|
||||
}
|
||||
mu_.Unlock();
|
||||
}
|
||||
|
||||
void Change(ReaderState s) {
|
||||
mu_.Lock();
|
||||
state_ = s;
|
||||
state_cv_.Signal();
|
||||
mu_.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
port::Mutex mu_;
|
||||
ReaderState state_;
|
||||
port::CondVar state_cv_;
|
||||
};
|
||||
|
||||
static void ConcurrentReader(void* arg) {
|
||||
TestState* state = reinterpret_cast<TestState*>(arg);
|
||||
Random rnd(state->seed_);
|
||||
int64_t reads = 0;
|
||||
state->Change(TestState::RUNNING);
|
||||
while (!state->quit_flag_.load(std::memory_order_acquire)) {
|
||||
state->t_.ReadStep(&rnd);
|
||||
++reads;
|
||||
}
|
||||
state->Change(TestState::DONE);
|
||||
}
|
||||
|
||||
static void RunConcurrent(int run) {
|
||||
const int seed = test::RandomSeed() + (run * 100);
|
||||
Random rnd(seed);
|
||||
const int N = 1000;
|
||||
const int kSize = 1000;
|
||||
for (int i = 0; i < N; i++) {
|
||||
if ((i % 100) == 0) {
|
||||
fprintf(stderr, "Run %d of %d\n", i, N);
|
||||
}
|
||||
TestState state(seed + 1);
|
||||
Env::Default()->Schedule(ConcurrentReader, &state);
|
||||
state.Wait(TestState::RUNNING);
|
||||
for (int k = 0; k < kSize; k++) {
|
||||
state.t_.WriteStep(&rnd);
|
||||
}
|
||||
state.quit_flag_.store(true, std::memory_order_release);
|
||||
state.Wait(TestState::DONE);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(InlineSkipTest, Concurrent1) { RunConcurrent(1); }
|
||||
TEST_F(InlineSkipTest, Concurrent2) { RunConcurrent(2); }
|
||||
TEST_F(InlineSkipTest, Concurrent3) { RunConcurrent(3); }
|
||||
TEST_F(InlineSkipTest, Concurrent4) { RunConcurrent(4); }
|
||||
TEST_F(InlineSkipTest, Concurrent5) { RunConcurrent(5); }
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -533,3 +533,4 @@ int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
#include <string>
|
||||
|
||||
#include "db/db_impl.h"
|
||||
#include "db/db_test_util.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace rocksdb {
|
||||
class OptionsFileTest : public testing::Test {
|
||||
public:
|
||||
OptionsFileTest() : dbname_(test::TmpDir() + "/options_file_test") {}
|
||||
|
||||
std::string dbname_;
|
||||
};
|
||||
|
||||
namespace {
|
||||
void UpdateOptionsFiles(DB* db,
|
||||
std::unordered_set<std::string>* filename_history,
|
||||
int* options_files_count) {
|
||||
std::vector<std::string> filenames;
|
||||
db->GetEnv()->GetChildren(db->GetName(), &filenames);
|
||||
uint64_t number;
|
||||
FileType type;
|
||||
*options_files_count = 0;
|
||||
for (auto filename : filenames) {
|
||||
if (ParseFileName(filename, &number, &type) && type == kOptionsFile) {
|
||||
filename_history->insert(filename);
|
||||
(*options_files_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify whether the current Options Files are the latest ones.
|
||||
void VerifyOptionsFileName(
|
||||
DB* db, const std::unordered_set<std::string>& past_filenames) {
|
||||
std::vector<std::string> filenames;
|
||||
std::unordered_set<std::string> current_filenames;
|
||||
db->GetEnv()->GetChildren(db->GetName(), &filenames);
|
||||
uint64_t number;
|
||||
FileType type;
|
||||
for (auto filename : filenames) {
|
||||
if (ParseFileName(filename, &number, &type) && type == kOptionsFile) {
|
||||
current_filenames.insert(filename);
|
||||
}
|
||||
}
|
||||
for (auto past_filename : past_filenames) {
|
||||
if (current_filenames.find(past_filename) != current_filenames.end()) {
|
||||
continue;
|
||||
}
|
||||
for (auto filename : current_filenames) {
|
||||
ASSERT_GT(filename, past_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_F(OptionsFileTest, NumberOfOptionsFiles) {
|
||||
const int kReopenCount = 20;
|
||||
Options opt;
|
||||
opt.create_if_missing = true;
|
||||
DestroyDB(dbname_, opt);
|
||||
std::unordered_set<std::string> filename_history;
|
||||
DB* db;
|
||||
for (int i = 0; i < kReopenCount; ++i) {
|
||||
ASSERT_OK(DB::Open(opt, dbname_, &db));
|
||||
int num_options_files = 0;
|
||||
UpdateOptionsFiles(db, &filename_history, &num_options_files);
|
||||
ASSERT_GT(num_options_files, 0);
|
||||
ASSERT_LE(num_options_files, 2);
|
||||
// Make sure we always keep the latest option files.
|
||||
VerifyOptionsFileName(db, filename_history);
|
||||
delete db;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OptionsFileTest, OptionsFileName) {
|
||||
const uint64_t kOptionsFileNum = 12345;
|
||||
uint64_t number;
|
||||
FileType type;
|
||||
|
||||
auto options_file_name = OptionsFileName("", kOptionsFileNum);
|
||||
ASSERT_TRUE(ParseFileName(options_file_name, &number, &type, nullptr));
|
||||
ASSERT_EQ(type, kOptionsFile);
|
||||
ASSERT_EQ(number, kOptionsFileNum);
|
||||
|
||||
const uint64_t kTempOptionsFileNum = 54352;
|
||||
auto temp_options_file_name = TempOptionsFileName("", kTempOptionsFileNum);
|
||||
ASSERT_TRUE(ParseFileName(temp_options_file_name, &number, &type, nullptr));
|
||||
ASSERT_NE(temp_options_file_name.find(kTempFileNameSuffix),
|
||||
std::string::npos);
|
||||
ASSERT_EQ(type, kTempFile);
|
||||
ASSERT_EQ(number, kTempOptionsFileNum);
|
||||
}
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#if !(defined NDEBUG) || !defined(OS_WIN)
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
#else
|
||||
return 0;
|
||||
#endif // !(defined NDEBUG) || !defined(OS_WIN)
|
||||
}
|
||||
#else
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
printf("Skipped as Options file is not supported in RocksDBLite.\n");
|
||||
return 0;
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
+10
-12
@@ -107,9 +107,8 @@ class SkipList {
|
||||
};
|
||||
|
||||
private:
|
||||
const uint16_t kMaxHeight_;
|
||||
const uint16_t kBranching_;
|
||||
const uint32_t kScaledInverseBranching_;
|
||||
const int32_t kMaxHeight_;
|
||||
const int32_t kBranching_;
|
||||
|
||||
// Immutable after construction
|
||||
Comparator const compare_;
|
||||
@@ -132,6 +131,9 @@ class SkipList {
|
||||
return max_height_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Read/written only by Insert().
|
||||
Random rnd_;
|
||||
|
||||
Node* NewNode(const Key& key, int height);
|
||||
int RandomHeight();
|
||||
bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); }
|
||||
@@ -262,11 +264,9 @@ inline void SkipList<Key, Comparator>::Iterator::SeekToLast() {
|
||||
|
||||
template<typename Key, class Comparator>
|
||||
int SkipList<Key, Comparator>::RandomHeight() {
|
||||
auto rnd = Random::GetTLSInstance();
|
||||
|
||||
// Increase height with probability 1 in kBranching
|
||||
int height = 1;
|
||||
while (height < kMaxHeight_ && rnd->Next() < kScaledInverseBranching_) {
|
||||
while (height < kMaxHeight_ && ((rnd_.Next() % kBranching_) == 0)) {
|
||||
height++;
|
||||
}
|
||||
assert(height > 0);
|
||||
@@ -391,16 +391,14 @@ SkipList<Key, Comparator>::SkipList(const Comparator cmp, Allocator* allocator,
|
||||
int32_t branching_factor)
|
||||
: kMaxHeight_(max_height),
|
||||
kBranching_(branching_factor),
|
||||
kScaledInverseBranching_((Random::kMaxNext + 1) / kBranching_),
|
||||
compare_(cmp),
|
||||
allocator_(allocator),
|
||||
head_(NewNode(0 /* any key will do */, max_height)),
|
||||
max_height_(1),
|
||||
prev_height_(1) {
|
||||
assert(max_height > 0 && kMaxHeight_ == static_cast<uint32_t>(max_height));
|
||||
assert(branching_factor > 0 &&
|
||||
kBranching_ == static_cast<uint32_t>(branching_factor));
|
||||
assert(kScaledInverseBranching_ > 0);
|
||||
prev_height_(1),
|
||||
rnd_(0xdeadbeef) {
|
||||
assert(kMaxHeight_ > 0);
|
||||
assert(kBranching_ > 0);
|
||||
// Allocate the prev_ Node* array, directly from the passed-in allocator.
|
||||
// prev_ does not need to be freed, as its life cycle is tied up with
|
||||
// the allocator as a whole.
|
||||
|
||||
+39
-186
@@ -42,91 +42,22 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
// anon namespace for file-local types
|
||||
namespace {
|
||||
|
||||
enum ContentFlags : uint32_t {
|
||||
DEFERRED = 1,
|
||||
HAS_PUT = 2,
|
||||
HAS_DELETE = 4,
|
||||
HAS_SINGLE_DELETE = 8,
|
||||
HAS_MERGE = 16,
|
||||
};
|
||||
|
||||
struct BatchContentClassifier : public WriteBatch::Handler {
|
||||
uint32_t content_flags = 0;
|
||||
|
||||
Status PutCF(uint32_t, const Slice&, const Slice&) override {
|
||||
content_flags |= ContentFlags::HAS_PUT;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status DeleteCF(uint32_t, const Slice&) override {
|
||||
content_flags |= ContentFlags::HAS_DELETE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status SingleDeleteCF(uint32_t, const Slice&) override {
|
||||
content_flags |= ContentFlags::HAS_SINGLE_DELETE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status MergeCF(uint32_t, const Slice&, const Slice&) override {
|
||||
content_flags |= ContentFlags::HAS_MERGE;
|
||||
return Status::OK();
|
||||
}
|
||||
};
|
||||
|
||||
} // anon namespace
|
||||
|
||||
// WriteBatch header has an 8-byte sequence number followed by a 4-byte count.
|
||||
static const size_t kHeader = 12;
|
||||
|
||||
struct SavePoint {
|
||||
size_t size; // size of rep_
|
||||
int count; // count of elements in rep_
|
||||
uint32_t content_flags;
|
||||
SavePoint(size_t s, int c) : size(s), count(c) {}
|
||||
};
|
||||
|
||||
struct SavePoints {
|
||||
std::stack<SavePoint> stack;
|
||||
};
|
||||
|
||||
WriteBatch::WriteBatch(size_t reserved_bytes)
|
||||
: save_points_(nullptr), content_flags_(0), rep_() {
|
||||
WriteBatch::WriteBatch(size_t reserved_bytes) : save_points_(nullptr) {
|
||||
rep_.reserve((reserved_bytes > kHeader) ? reserved_bytes : kHeader);
|
||||
rep_.resize(kHeader);
|
||||
}
|
||||
|
||||
WriteBatch::WriteBatch(const std::string& rep)
|
||||
: save_points_(nullptr),
|
||||
content_flags_(ContentFlags::DEFERRED),
|
||||
rep_(rep) {}
|
||||
|
||||
WriteBatch::WriteBatch(const WriteBatch& src)
|
||||
: save_points_(src.save_points_),
|
||||
content_flags_(src.content_flags_.load(std::memory_order_relaxed)),
|
||||
rep_(src.rep_) {}
|
||||
|
||||
WriteBatch::WriteBatch(WriteBatch&& src)
|
||||
: save_points_(std::move(src.save_points_)),
|
||||
content_flags_(src.content_flags_.load(std::memory_order_relaxed)),
|
||||
rep_(std::move(src.rep_)) {}
|
||||
|
||||
WriteBatch& WriteBatch::operator=(const WriteBatch& src) {
|
||||
if (&src != this) {
|
||||
this->~WriteBatch();
|
||||
new (this) WriteBatch(src);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
WriteBatch& WriteBatch::operator=(WriteBatch&& src) {
|
||||
if (&src != this) {
|
||||
this->~WriteBatch();
|
||||
new (this) WriteBatch(std::move(src));
|
||||
}
|
||||
return *this;
|
||||
Clear();
|
||||
}
|
||||
|
||||
WriteBatch::~WriteBatch() {
|
||||
@@ -150,8 +81,6 @@ void WriteBatch::Clear() {
|
||||
rep_.clear();
|
||||
rep_.resize(kHeader);
|
||||
|
||||
content_flags_.store(0, std::memory_order_relaxed);
|
||||
|
||||
if (save_points_ != nullptr) {
|
||||
while (!save_points_->stack.empty()) {
|
||||
save_points_->stack.pop();
|
||||
@@ -163,38 +92,6 @@ int WriteBatch::Count() const {
|
||||
return WriteBatchInternal::Count(this);
|
||||
}
|
||||
|
||||
uint32_t WriteBatch::ComputeContentFlags() const {
|
||||
auto rv = content_flags_.load(std::memory_order_relaxed);
|
||||
if ((rv & ContentFlags::DEFERRED) != 0) {
|
||||
BatchContentClassifier classifier;
|
||||
Iterate(&classifier);
|
||||
rv = classifier.content_flags;
|
||||
|
||||
// this method is conceptually const, because it is performing a lazy
|
||||
// computation that doesn't affect the abstract state of the batch.
|
||||
// content_flags_ is marked mutable so that we can perform the
|
||||
// following assignment
|
||||
content_flags_.store(rv, std::memory_order_relaxed);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool WriteBatch::HasPut() const {
|
||||
return (ComputeContentFlags() & ContentFlags::HAS_PUT) != 0;
|
||||
}
|
||||
|
||||
bool WriteBatch::HasDelete() const {
|
||||
return (ComputeContentFlags() & ContentFlags::HAS_DELETE) != 0;
|
||||
}
|
||||
|
||||
bool WriteBatch::HasSingleDelete() const {
|
||||
return (ComputeContentFlags() & ContentFlags::HAS_SINGLE_DELETE) != 0;
|
||||
}
|
||||
|
||||
bool WriteBatch::HasMerge() const {
|
||||
return (ComputeContentFlags() & ContentFlags::HAS_MERGE) != 0;
|
||||
}
|
||||
|
||||
Status ReadRecordFromWriteBatch(Slice* input, char* tag,
|
||||
uint32_t* column_family, Slice* key,
|
||||
Slice* value, Slice* blob) {
|
||||
@@ -272,29 +169,21 @@ Status WriteBatch::Iterate(Handler* handler) const {
|
||||
switch (tag) {
|
||||
case kTypeColumnFamilyValue:
|
||||
case kTypeValue:
|
||||
assert(content_flags_.load(std::memory_order_relaxed) &
|
||||
(ContentFlags::DEFERRED | ContentFlags::HAS_PUT));
|
||||
s = handler->PutCF(column_family, key, value);
|
||||
found++;
|
||||
break;
|
||||
case kTypeColumnFamilyDeletion:
|
||||
case kTypeDeletion:
|
||||
assert(content_flags_.load(std::memory_order_relaxed) &
|
||||
(ContentFlags::DEFERRED | ContentFlags::HAS_DELETE));
|
||||
s = handler->DeleteCF(column_family, key);
|
||||
found++;
|
||||
break;
|
||||
case kTypeColumnFamilySingleDeletion:
|
||||
case kTypeSingleDeletion:
|
||||
assert(content_flags_.load(std::memory_order_relaxed) &
|
||||
(ContentFlags::DEFERRED | ContentFlags::HAS_SINGLE_DELETE));
|
||||
s = handler->SingleDeleteCF(column_family, key);
|
||||
found++;
|
||||
break;
|
||||
case kTypeColumnFamilyMerge:
|
||||
case kTypeMerge:
|
||||
assert(content_flags_.load(std::memory_order_relaxed) &
|
||||
(ContentFlags::DEFERRED | ContentFlags::HAS_MERGE));
|
||||
s = handler->MergeCF(column_family, key, value);
|
||||
found++;
|
||||
break;
|
||||
@@ -344,9 +233,6 @@ void WriteBatchInternal::Put(WriteBatch* b, uint32_t column_family_id,
|
||||
}
|
||||
PutLengthPrefixedSlice(&b->rep_, key);
|
||||
PutLengthPrefixedSlice(&b->rep_, value);
|
||||
b->content_flags_.store(
|
||||
b->content_flags_.load(std::memory_order_relaxed) | ContentFlags::HAS_PUT,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::Put(ColumnFamilyHandle* column_family, const Slice& key,
|
||||
@@ -365,9 +251,6 @@ void WriteBatchInternal::Put(WriteBatch* b, uint32_t column_family_id,
|
||||
}
|
||||
PutLengthPrefixedSliceParts(&b->rep_, key);
|
||||
PutLengthPrefixedSliceParts(&b->rep_, value);
|
||||
b->content_flags_.store(
|
||||
b->content_flags_.load(std::memory_order_relaxed) | ContentFlags::HAS_PUT,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::Put(ColumnFamilyHandle* column_family, const SliceParts& key,
|
||||
@@ -385,9 +268,6 @@ void WriteBatchInternal::Delete(WriteBatch* b, uint32_t column_family_id,
|
||||
PutVarint32(&b->rep_, column_family_id);
|
||||
}
|
||||
PutLengthPrefixedSlice(&b->rep_, key);
|
||||
b->content_flags_.store(b->content_flags_.load(std::memory_order_relaxed) |
|
||||
ContentFlags::HAS_DELETE,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::Delete(ColumnFamilyHandle* column_family, const Slice& key) {
|
||||
@@ -404,9 +284,6 @@ void WriteBatchInternal::Delete(WriteBatch* b, uint32_t column_family_id,
|
||||
PutVarint32(&b->rep_, column_family_id);
|
||||
}
|
||||
PutLengthPrefixedSliceParts(&b->rep_, key);
|
||||
b->content_flags_.store(b->content_flags_.load(std::memory_order_relaxed) |
|
||||
ContentFlags::HAS_DELETE,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::Delete(ColumnFamilyHandle* column_family,
|
||||
@@ -424,9 +301,6 @@ void WriteBatchInternal::SingleDelete(WriteBatch* b, uint32_t column_family_id,
|
||||
PutVarint32(&b->rep_, column_family_id);
|
||||
}
|
||||
PutLengthPrefixedSlice(&b->rep_, key);
|
||||
b->content_flags_.store(b->content_flags_.load(std::memory_order_relaxed) |
|
||||
ContentFlags::HAS_SINGLE_DELETE,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::SingleDelete(ColumnFamilyHandle* column_family,
|
||||
@@ -444,9 +318,6 @@ void WriteBatchInternal::SingleDelete(WriteBatch* b, uint32_t column_family_id,
|
||||
PutVarint32(&b->rep_, column_family_id);
|
||||
}
|
||||
PutLengthPrefixedSliceParts(&b->rep_, key);
|
||||
b->content_flags_.store(b->content_flags_.load(std::memory_order_relaxed) |
|
||||
ContentFlags::HAS_SINGLE_DELETE,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::SingleDelete(ColumnFamilyHandle* column_family,
|
||||
@@ -465,9 +336,6 @@ void WriteBatchInternal::Merge(WriteBatch* b, uint32_t column_family_id,
|
||||
}
|
||||
PutLengthPrefixedSlice(&b->rep_, key);
|
||||
PutLengthPrefixedSlice(&b->rep_, value);
|
||||
b->content_flags_.store(b->content_flags_.load(std::memory_order_relaxed) |
|
||||
ContentFlags::HAS_MERGE,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::Merge(ColumnFamilyHandle* column_family, const Slice& key,
|
||||
@@ -487,9 +355,6 @@ void WriteBatchInternal::Merge(WriteBatch* b, uint32_t column_family_id,
|
||||
}
|
||||
PutLengthPrefixedSliceParts(&b->rep_, key);
|
||||
PutLengthPrefixedSliceParts(&b->rep_, value);
|
||||
b->content_flags_.store(b->content_flags_.load(std::memory_order_relaxed) |
|
||||
ContentFlags::HAS_MERGE,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatch::Merge(ColumnFamilyHandle* column_family,
|
||||
@@ -509,8 +374,7 @@ void WriteBatch::SetSavePoint() {
|
||||
save_points_ = new SavePoints();
|
||||
}
|
||||
// Record length and count of current batch of writes.
|
||||
save_points_->stack.push(SavePoint{
|
||||
GetDataSize(), Count(), content_flags_.load(std::memory_order_relaxed)});
|
||||
save_points_->stack.push(SavePoint(GetDataSize(), Count()));
|
||||
}
|
||||
|
||||
Status WriteBatch::RollbackToSavePoint() {
|
||||
@@ -523,7 +387,6 @@ Status WriteBatch::RollbackToSavePoint() {
|
||||
save_points_->stack.pop();
|
||||
|
||||
assert(savepoint.size <= rep_.size());
|
||||
assert(savepoint.count <= Count());
|
||||
|
||||
if (savepoint.size == rep_.size()) {
|
||||
// No changes to rollback
|
||||
@@ -533,7 +396,6 @@ Status WriteBatch::RollbackToSavePoint() {
|
||||
} else {
|
||||
rep_.resize(savepoint.size);
|
||||
WriteBatchInternal::SetCount(this, savepoint.count);
|
||||
content_flags_.store(savepoint.content_flags, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
@@ -591,7 +453,6 @@ class MemTableInserter : public WriteBatch::Handler {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Status PutCF(uint32_t column_family_id, const Slice& key,
|
||||
const Slice& value) override {
|
||||
Status seek_status;
|
||||
@@ -648,8 +509,8 @@ class MemTableInserter : public WriteBatch::Handler {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status DeleteImpl(uint32_t column_family_id, const Slice& key,
|
||||
ValueType delete_type) {
|
||||
virtual Status DeleteCF(uint32_t column_family_id,
|
||||
const Slice& key) override {
|
||||
Status seek_status;
|
||||
if (!SeekToColumnFamily(column_family_id, &seek_status)) {
|
||||
++sequence_;
|
||||
@@ -672,20 +533,40 @@ class MemTableInserter : public WriteBatch::Handler {
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
mem->Add(sequence_, delete_type, key, Slice());
|
||||
mem->Add(sequence_, kTypeDeletion, key, Slice());
|
||||
sequence_++;
|
||||
cf_mems_->CheckMemtableFull();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status DeleteCF(uint32_t column_family_id,
|
||||
const Slice& key) override {
|
||||
return DeleteImpl(column_family_id, key, kTypeDeletion);
|
||||
}
|
||||
|
||||
virtual Status SingleDeleteCF(uint32_t column_family_id,
|
||||
const Slice& key) override {
|
||||
return DeleteImpl(column_family_id, key, kTypeSingleDeletion);
|
||||
Status seek_status;
|
||||
if (!SeekToColumnFamily(column_family_id, &seek_status)) {
|
||||
++sequence_;
|
||||
return seek_status;
|
||||
}
|
||||
MemTable* mem = cf_mems_->GetMemTable();
|
||||
auto* moptions = mem->GetMemTableOptions();
|
||||
if (!dont_filter_deletes_ && moptions->filter_deletes) {
|
||||
SnapshotImpl read_from_snapshot;
|
||||
read_from_snapshot.number_ = sequence_;
|
||||
ReadOptions ropts;
|
||||
ropts.snapshot = &read_from_snapshot;
|
||||
std::string value;
|
||||
auto cf_handle = cf_mems_->GetColumnFamilyHandle();
|
||||
if (cf_handle == nullptr) {
|
||||
cf_handle = db_->DefaultColumnFamily();
|
||||
}
|
||||
if (!db_->KeyMayExist(ropts, cf_handle, key, &value)) {
|
||||
RecordTick(moptions->statistics, NUMBER_FILTERED_DELETES);
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
mem->Add(sequence_, kTypeSingleDeletion, key, Slice());
|
||||
sequence_++;
|
||||
cf_mems_->CheckMemtableFull();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
|
||||
@@ -772,57 +653,29 @@ class MemTableInserter : public WriteBatch::Handler {
|
||||
|
||||
// This function can only be called in these conditions:
|
||||
// 1) During Recovery()
|
||||
// 2) During Write(), in a single-threaded write thread
|
||||
// The reason is that it calls memtables->Seek(), which has a stateful cache
|
||||
Status WriteBatchInternal::InsertInto(const autovector<WriteBatch*>& batches,
|
||||
SequenceNumber sequence,
|
||||
// 2) during Write(), in a single-threaded write thread
|
||||
// The reason is that it calles ColumnFamilyMemTablesImpl::Seek(), which needs
|
||||
// to be called from a single-threaded write thread (or while holding DB mutex)
|
||||
Status WriteBatchInternal::InsertInto(const WriteBatch* b,
|
||||
ColumnFamilyMemTables* memtables,
|
||||
bool ignore_missing_column_families,
|
||||
uint64_t log_number, DB* db,
|
||||
const bool dont_filter_deletes) {
|
||||
MemTableInserter inserter(sequence, memtables, ignore_missing_column_families,
|
||||
log_number, db, dont_filter_deletes);
|
||||
Status rv = Status::OK();
|
||||
for (size_t i = 0; i < batches.size() && rv.ok(); ++i) {
|
||||
rv = batches[i]->Iterate(&inserter);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
Status WriteBatchInternal::InsertInto(const WriteBatch* batch,
|
||||
ColumnFamilyMemTables* memtables,
|
||||
bool ignore_missing_column_families,
|
||||
uint64_t log_number, DB* db,
|
||||
const bool dont_filter_deletes) {
|
||||
MemTableInserter inserter(WriteBatchInternal::Sequence(batch), memtables,
|
||||
MemTableInserter inserter(WriteBatchInternal::Sequence(b), memtables,
|
||||
ignore_missing_column_families, log_number, db,
|
||||
dont_filter_deletes);
|
||||
return batch->Iterate(&inserter);
|
||||
return b->Iterate(&inserter);
|
||||
}
|
||||
|
||||
void WriteBatchInternal::SetContents(WriteBatch* b, const Slice& contents) {
|
||||
assert(contents.size() >= kHeader);
|
||||
b->rep_.assign(contents.data(), contents.size());
|
||||
b->content_flags_.store(ContentFlags::DEFERRED, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {
|
||||
SetCount(dst, Count(dst) + Count(src));
|
||||
assert(src->rep_.size() >= kHeader);
|
||||
dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);
|
||||
dst->content_flags_.store(
|
||||
dst->content_flags_.load(std::memory_order_relaxed) |
|
||||
src->content_flags_.load(std::memory_order_relaxed),
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
size_t WriteBatchInternal::AppendedByteSize(size_t leftByteSize,
|
||||
size_t rightByteSize) {
|
||||
if (leftByteSize == 0 || rightByteSize == 0) {
|
||||
return leftByteSize + rightByteSize;
|
||||
} else {
|
||||
return leftByteSize + rightByteSize - kHeader;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "util/autovector.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@@ -113,28 +112,17 @@ class WriteBatchInternal {
|
||||
|
||||
static void SetContents(WriteBatch* batch, const Slice& contents);
|
||||
|
||||
// Inserts batches[i] into memtable, for i in 0..num_batches-1 inclusive.
|
||||
//
|
||||
// If dont_filter_deletes is false AND options.filter_deletes is true
|
||||
// AND db->KeyMayExist is false, then a Delete won't modify the memtable.
|
||||
//
|
||||
// If ignore_missing_column_families == true. WriteBatch
|
||||
// referencing non-existing column family will be ignored.
|
||||
// If ignore_missing_column_families == false, processing of the
|
||||
// batches will be stopped if a reference is found to a non-existing
|
||||
// column family and InvalidArgument() will be returned. The writes
|
||||
// in batches may be only partially applied at that point.
|
||||
// Inserts batch entries into memtable
|
||||
// If dont_filter_deletes is false AND options.filter_deletes is true,
|
||||
// then --> Drops deletes in batch if db->KeyMayExist returns false
|
||||
// If ignore_missing_column_families == true. WriteBatch referencing
|
||||
// non-existing column family should be ignored.
|
||||
// However, if ignore_missing_column_families == false, any WriteBatch
|
||||
// referencing non-existing column family will return a InvalidArgument()
|
||||
// failure.
|
||||
//
|
||||
// If log_number is non-zero, the memtable will be updated only if
|
||||
// memtables->GetLogNumber() >= log_number.
|
||||
static Status InsertInto(const autovector<WriteBatch*>& batches,
|
||||
SequenceNumber sequence,
|
||||
ColumnFamilyMemTables* memtables,
|
||||
bool ignore_missing_column_families = false,
|
||||
uint64_t log_number = 0, DB* db = nullptr,
|
||||
const bool dont_filter_deletes = true);
|
||||
|
||||
// Convenience form of InsertInto when you have only one batch
|
||||
// memtables->GetLogNumber() >= log_number
|
||||
static Status InsertInto(const WriteBatch* batch,
|
||||
ColumnFamilyMemTables* memtables,
|
||||
bool ignore_missing_column_families = false,
|
||||
@@ -142,10 +130,6 @@ class WriteBatchInternal {
|
||||
const bool dont_filter_deletes = true);
|
||||
|
||||
static void Append(WriteBatch* dst, const WriteBatch* src);
|
||||
|
||||
// Returns the byte size of appending a WriteBatch with ByteSize
|
||||
// leftByteSize and a WriteBatch with ByteSize rightByteSize
|
||||
static size_t AppendedByteSize(size_t leftByteSize, size_t rightByteSize);
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -39,10 +39,6 @@ static std::string PrintContents(WriteBatch* b) {
|
||||
ColumnFamilyMemTablesDefault cf_mems_default(mem);
|
||||
Status s = WriteBatchInternal::InsertInto(b, &cf_mems_default);
|
||||
int count = 0;
|
||||
int put_count = 0;
|
||||
int delete_count = 0;
|
||||
int single_delete_count = 0;
|
||||
int merge_count = 0;
|
||||
Arena arena;
|
||||
ScopedArenaIterator iter(mem->NewIterator(ReadOptions(), &arena));
|
||||
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
|
||||
@@ -57,21 +53,18 @@ static std::string PrintContents(WriteBatch* b) {
|
||||
state.append(iter->value().ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
put_count++;
|
||||
break;
|
||||
case kTypeDeletion:
|
||||
state.append("Delete(");
|
||||
state.append(ikey.user_key.ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
delete_count++;
|
||||
break;
|
||||
case kTypeSingleDeletion:
|
||||
state.append("SingleDelete(");
|
||||
state.append(ikey.user_key.ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
single_delete_count++;
|
||||
break;
|
||||
case kTypeMerge:
|
||||
state.append("Merge(");
|
||||
@@ -80,7 +73,6 @@ static std::string PrintContents(WriteBatch* b) {
|
||||
state.append(iter->value().ToString());
|
||||
state.append(")");
|
||||
count++;
|
||||
merge_count++;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
@@ -89,10 +81,6 @@ static std::string PrintContents(WriteBatch* b) {
|
||||
state.append("@");
|
||||
state.append(NumberToString(ikey.sequence));
|
||||
}
|
||||
EXPECT_EQ(b->HasPut(), put_count > 0);
|
||||
EXPECT_EQ(b->HasDelete(), delete_count > 0);
|
||||
EXPECT_EQ(b->HasSingleDelete(), single_delete_count > 0);
|
||||
EXPECT_EQ(b->HasMerge(), merge_count > 0);
|
||||
if (!s.ok()) {
|
||||
state.append(s.ToString());
|
||||
} else if (count != WriteBatchInternal::Count(b)) {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
#include "db/write_thread.h"
|
||||
#include "util/sync_point.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
@@ -189,7 +188,6 @@ void WriteThread::EnterUnbatched(Writer* w, InstrumentedMutex* mu) {
|
||||
LinkOne(w, &wait_needed);
|
||||
if (wait_needed) {
|
||||
mu->Unlock();
|
||||
TEST_SYNC_POINT("WriteThread::EnterUnbatched:Wait");
|
||||
Await(w);
|
||||
mu->Lock();
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ Each block consists of a sequence of records:
|
||||
|
||||
A record never starts within the last six bytes of a block (since it
|
||||
won't fit). Any leftover bytes here form the trailer, which must
|
||||
consist entirely of zero bytes and must be skipped by readers.
|
||||
consist entirely of zero bytes and must be skipped by readers.
|
||||
|
||||
Aside: if exactly seven bytes are left in the current block, and a new
|
||||
non-zero length record is added, the writer must emit a FIRST record
|
||||
|
||||
@@ -28,9 +28,6 @@ optimistic_transaction_example: librocksdb optimistic_transaction_example.cc
|
||||
transaction_example: librocksdb transaction_example.cc
|
||||
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++11 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
|
||||
|
||||
options_file_example: librocksdb options_file_example.cc
|
||||
$(CXX) $(CXXFLAGS) $@.cc -o$@ ../librocksdb.a -I../include -O2 -std=c++11 $(PLATFORM_LDFLAGS) $(PLATFORM_CXXFLAGS) $(EXEC_LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -rf ./simple_example ./column_families_example ./compact_files_example ./compaction_filter_example ./c_simple_example c_simple_example.o ./optimistic_transaction_example ./transaction_example
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
// This file demonstrates how to use the utility functions defined in
|
||||
// rocksdb/utilities/options_util.h to open a rocksdb database without
|
||||
// remembering all the rocksdb options.
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "rocksdb/utilities/options_util.h"
|
||||
|
||||
using namespace rocksdb;
|
||||
|
||||
std::string kDBPath = "/tmp/rocksdb_options_file_example";
|
||||
|
||||
namespace {
|
||||
// A dummy compaction filter
|
||||
class DummyCompactionFilter : public CompactionFilter {
|
||||
public:
|
||||
virtual ~DummyCompactionFilter() {}
|
||||
virtual bool Filter(int level, const Slice& key, const Slice& existing_value,
|
||||
std::string* new_value, bool* value_changed) const {
|
||||
return false;
|
||||
}
|
||||
virtual const char* Name() const { return "DummyCompactionFilter"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
DBOptions db_opt;
|
||||
db_opt.create_if_missing = true;
|
||||
|
||||
std::vector<ColumnFamilyDescriptor> cf_descs;
|
||||
cf_descs.push_back({kDefaultColumnFamilyName, ColumnFamilyOptions()});
|
||||
cf_descs.push_back({"new_cf", ColumnFamilyOptions()});
|
||||
|
||||
// initialize BlockBasedTableOptions
|
||||
auto cache = NewLRUCache(1 * 1024 * 1024 * 1024);
|
||||
BlockBasedTableOptions bbt_opts;
|
||||
bbt_opts.block_size = 32 * 1024;
|
||||
bbt_opts.block_cache = cache;
|
||||
|
||||
// initialize column families options
|
||||
std::unique_ptr<CompactionFilter> compaction_filter;
|
||||
compaction_filter.reset(new DummyCompactionFilter());
|
||||
cf_descs[0].options.table_factory.reset(NewBlockBasedTableFactory(bbt_opts));
|
||||
cf_descs[0].options.compaction_filter = compaction_filter.get();
|
||||
cf_descs[1].options.table_factory.reset(NewBlockBasedTableFactory(bbt_opts));
|
||||
|
||||
// destroy and open DB
|
||||
DB* db;
|
||||
Status s = DestroyDB(kDBPath, Options(db_opt, cf_descs[0].options));
|
||||
assert(s.ok());
|
||||
s = DB::Open(Options(db_opt, cf_descs[0].options), kDBPath, &db);
|
||||
assert(s.ok());
|
||||
|
||||
// Create column family, and rocksdb will persist the options.
|
||||
ColumnFamilyHandle* cf;
|
||||
s = db->CreateColumnFamily(ColumnFamilyOptions(), "new_cf", &cf);
|
||||
assert(s.ok());
|
||||
|
||||
// close DB
|
||||
delete cf;
|
||||
delete db;
|
||||
|
||||
// In the following code, we will reopen the rocksdb instance using
|
||||
// the options file stored in the db directory.
|
||||
|
||||
// Load the options file.
|
||||
DBOptions loaded_db_opt;
|
||||
std::vector<ColumnFamilyDescriptor> loaded_cf_descs;
|
||||
s = LoadLatestOptions(kDBPath, Env::Default(), &loaded_db_opt,
|
||||
&loaded_cf_descs);
|
||||
assert(s.ok());
|
||||
assert(loaded_db_opt.create_if_missing == db_opt.create_if_missing);
|
||||
|
||||
// Initialize pointer options for each column family
|
||||
for (size_t i = 0; i < loaded_cf_descs.size(); ++i) {
|
||||
auto* loaded_bbt_opt = reinterpret_cast<BlockBasedTableOptions*>(
|
||||
loaded_cf_descs[0].options.table_factory->GetOptions());
|
||||
// Expect the same as BlockBasedTableOptions will be loaded form file.
|
||||
assert(loaded_bbt_opt->block_size == bbt_opts.block_size);
|
||||
// However, block_cache needs to be manually initialized as documented
|
||||
// in rocksdb/utilities/options_util.h.
|
||||
loaded_bbt_opt->block_cache = cache;
|
||||
}
|
||||
// In addition, as pointer options are initialized with default value,
|
||||
// we need to properly initialized all the pointer options if non-defalut
|
||||
// values are used before calling DB::Open().
|
||||
assert(loaded_cf_descs[0].options.compaction_filter == nullptr);
|
||||
loaded_cf_descs[0].options.compaction_filter = compaction_filter.get();
|
||||
|
||||
// reopen the db using the loaded options.
|
||||
std::vector<ColumnFamilyHandle*> handles;
|
||||
s = DB::Open(loaded_db_opt, kDBPath, loaded_cf_descs, &handles, &db);
|
||||
assert(s.ok());
|
||||
|
||||
// close DB
|
||||
for (auto* handle : handles) {
|
||||
delete handle;
|
||||
}
|
||||
delete db;
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
# This is a RocksDB option file.
|
||||
#
|
||||
# A typical RocksDB options file has four sections, which are
|
||||
# Version section, DBOptions section, at least one CFOptions
|
||||
# section, and one TableOptions section for each column family.
|
||||
# The RocksDB options file in general follows the basic INI
|
||||
# file format with the following extensions / modifications:
|
||||
# A typical RocksDB options file has three sections, which are
|
||||
# Version, DBOptions, and more than one CFOptions. The RocksDB
|
||||
# options file in general follows the basic INI file format
|
||||
# with the following extensions / modifications:
|
||||
#
|
||||
# * Escaped characters
|
||||
# We escaped the following characters:
|
||||
@@ -21,7 +20,7 @@
|
||||
# Each statement contains a '=', where extra white-spaces
|
||||
# are supported. However, we don't support multi-lined statement.
|
||||
# Furthermore, each line can only contain at most one statement.
|
||||
# * Sections
|
||||
# * Section
|
||||
# Sections are of the form [SecitonTitle "SectionArgument"],
|
||||
# where section argument is optional.
|
||||
# * List
|
||||
@@ -30,113 +29,166 @@
|
||||
#
|
||||
# Below is an example of a RocksDB options file:
|
||||
[Version]
|
||||
rocksdb_version=4.3.0
|
||||
rocksdb_version=4.0.0
|
||||
options_file_version=1.1
|
||||
|
||||
[DBOptions]
|
||||
stats_dump_period_sec=600
|
||||
max_manifest_file_size=18446744073709551615
|
||||
bytes_per_sync=8388608
|
||||
delayed_write_rate=2097152
|
||||
bytes_per_sync=0
|
||||
delayed_write_rate=1048576
|
||||
WAL_ttl_seconds=0
|
||||
WAL_size_limit_MB=0
|
||||
max_subcompactions=1
|
||||
wal_dir=
|
||||
wal_bytes_per_sync=0
|
||||
db_write_buffer_size=0
|
||||
keep_log_file_num=1000
|
||||
table_cache_numshardbits=4
|
||||
max_file_opening_threads=1
|
||||
writable_file_max_buffer_size=1048576
|
||||
random_access_max_buffer_size=1048576
|
||||
use_fsync=false
|
||||
max_total_wal_size=0
|
||||
max_open_files=-1
|
||||
skip_stats_update_on_db_open=false
|
||||
max_background_compactions=16
|
||||
max_open_files=5000
|
||||
max_file_opening_threads=1
|
||||
use_fsync=false
|
||||
max_background_compactions=1
|
||||
manifest_preallocation_size=4194304
|
||||
max_background_flushes=7
|
||||
max_background_flushes=1
|
||||
is_fd_close_on_exec=true
|
||||
create_if_missing=false
|
||||
use_adaptive_mutex=false
|
||||
enable_thread_tracking=false
|
||||
disableDataSync=false
|
||||
max_log_file_size=0
|
||||
advise_random_on_open=true
|
||||
create_missing_column_families=false
|
||||
keep_log_file_num=1000
|
||||
table_cache_numshardbits=4
|
||||
error_if_exists=false
|
||||
skip_log_error_on_recovery=false
|
||||
allow_os_buffer=true
|
||||
allow_mmap_reads=false
|
||||
paranoid_checks=true
|
||||
delete_obsolete_files_period_micros=21600000000
|
||||
disable_data_sync=false
|
||||
log_file_time_to_roll=0
|
||||
compaction_readahead_size=0
|
||||
create_if_missing=false
|
||||
use_adaptive_mutex=false
|
||||
enable_thread_tracking=false
|
||||
disableDataSync=false
|
||||
allow_fallocate=true
|
||||
error_if_exists=false
|
||||
recycle_log_file_num=0
|
||||
skip_log_error_on_recovery=false
|
||||
allow_mmap_reads=false
|
||||
allow_os_buffer=true
|
||||
db_log_dir=
|
||||
new_table_reader_for_compaction_inputs=true
|
||||
new_table_reader_for_compaction_inputs=false
|
||||
allow_mmap_writes=false
|
||||
|
||||
|
||||
[CFOptions "default"]
|
||||
compaction_style=kCompactionStyleLevel
|
||||
compaction_filter=nullptr
|
||||
num_levels=6
|
||||
num_levels=7
|
||||
table_factory=BlockBasedTable
|
||||
comparator=leveldb.BytewiseComparator
|
||||
max_sequential_skip_in_iterations=8
|
||||
soft_rate_limit=0.000000
|
||||
max_bytes_for_level_base=1073741824
|
||||
max_bytes_for_level_base=536870912
|
||||
memtable_prefix_bloom_probes=6
|
||||
memtable_prefix_bloom_bits=0
|
||||
memtable_prefix_bloom_huge_page_tlb_size=0
|
||||
max_successive_merges=0
|
||||
arena_block_size=16777216
|
||||
min_write_buffer_number_to_merge=1
|
||||
arena_block_size=0
|
||||
min_write_buffer_number_to_merge=2
|
||||
target_file_size_multiplier=1
|
||||
source_compaction_factor=1
|
||||
max_bytes_for_level_multiplier=8
|
||||
max_bytes_for_level_multiplier=10
|
||||
compaction_filter_factory=nullptr
|
||||
max_write_buffer_number=8
|
||||
level0_stop_writes_trigger=20
|
||||
max_write_buffer_number=6
|
||||
level0_stop_writes_trigger=24
|
||||
compression=kSnappyCompression
|
||||
level0_file_num_compaction_trigger=4
|
||||
level0_file_num_compaction_trigger=2
|
||||
purge_redundant_kvs_while_flush=true
|
||||
max_write_buffer_number_to_maintain=0
|
||||
memtable_factory=SkipListFactory
|
||||
max_grandparent_overlap_factor=8
|
||||
max_grandparent_overlap_factor=10
|
||||
expanded_compaction_factor=25
|
||||
hard_pending_compaction_bytes_limit=137438953472
|
||||
hard_pending_compaction_bytes_limit=0
|
||||
inplace_update_num_locks=10000
|
||||
level_compaction_dynamic_level_bytes=true
|
||||
level0_slowdown_writes_trigger=12
|
||||
level_compaction_dynamic_level_bytes=false
|
||||
level0_slowdown_writes_trigger=20
|
||||
filter_deletes=false
|
||||
verify_checksums_in_compaction=true
|
||||
min_partial_merge_operands=2
|
||||
paranoid_file_checks=false
|
||||
target_file_size_base=134217728
|
||||
target_file_size_base=67108864
|
||||
optimize_filters_for_hits=false
|
||||
merge_operator=PutOperator
|
||||
compression_per_level=kNoCompression:kNoCompression:kNoCompression:kSnappyCompression:kSnappyCompression:kSnappyCompression
|
||||
merge_operator=nullptr
|
||||
compression_per_level=kNoCompression:kNoCompression:kSnappyCompression:kSnappyCompression:kSnappyCompression:kSnappyCompression:kSnappyCompression
|
||||
compaction_measure_io_stats=false
|
||||
prefix_extractor=nullptr
|
||||
bloom_locality=0
|
||||
write_buffer_size=134217728
|
||||
disable_auto_compactions=false
|
||||
inplace_update_support=false
|
||||
|
||||
[TableOptions/BlockBasedTable "default"]
|
||||
format_version=2
|
||||
format_version=0
|
||||
whole_key_filtering=true
|
||||
skip_table_builder_flush=false
|
||||
block_size_deviation=10
|
||||
block_size=4096
|
||||
block_restart_interval=16
|
||||
filter_policy=nullptr
|
||||
no_block_cache=false
|
||||
checksum=kCRC32c
|
||||
cache_index_and_filter_blocks=false
|
||||
index_type=kBinarySearch
|
||||
hash_index_allow_collision=true
|
||||
flush_block_policy_factory=FlushBlockBySizePolicyFactory
|
||||
|
||||
[CFOptions "universal"]
|
||||
compaction_style=kCompactionStyleUniversal
|
||||
compaction_filter=nullptr
|
||||
num_levels=7
|
||||
table_factory=BlockBasedTable
|
||||
comparator=leveldb.BytewiseComparator
|
||||
max_sequential_skip_in_iterations=8
|
||||
soft_rate_limit=0.000000
|
||||
max_bytes_for_level_base=10485760
|
||||
memtable_prefix_bloom_probes=6
|
||||
memtable_prefix_bloom_bits=0
|
||||
memtable_prefix_bloom_huge_page_tlb_size=0
|
||||
max_successive_merges=0
|
||||
arena_block_size=0
|
||||
min_write_buffer_number_to_merge=2
|
||||
target_file_size_multiplier=1
|
||||
source_compaction_factor=1
|
||||
max_bytes_for_level_multiplier=10
|
||||
compaction_filter_factory=nullptr
|
||||
max_write_buffer_number=6
|
||||
level0_stop_writes_trigger=24
|
||||
compression=kSnappyCompression
|
||||
level0_file_num_compaction_trigger=4
|
||||
purge_redundant_kvs_while_flush=true
|
||||
max_write_buffer_number_to_maintain=0
|
||||
memtable_factory=SkipListFactory
|
||||
max_grandparent_overlap_factor=10
|
||||
expanded_compaction_factor=25
|
||||
hard_pending_compaction_bytes_limit=0
|
||||
inplace_update_num_locks=10000
|
||||
level_compaction_dynamic_level_bytes=false
|
||||
level0_slowdown_writes_trigger=20
|
||||
filter_deletes=false
|
||||
verify_checksums_in_compaction=true
|
||||
min_partial_merge_operands=2
|
||||
paranoid_file_checks=false
|
||||
target_file_size_base=2097152
|
||||
optimize_filters_for_hits=false
|
||||
merge_operator=nullptr
|
||||
compression_per_level=
|
||||
compaction_measure_io_stats=false
|
||||
prefix_extractor=nullptr
|
||||
bloom_locality=0
|
||||
write_buffer_size=134217728
|
||||
disable_auto_compactions=false
|
||||
inplace_update_support=false
|
||||
[TableOptions/BlockBasedTable "universal"]
|
||||
format_version=0
|
||||
whole_key_filtering=true
|
||||
block_size_deviation=10
|
||||
block_size=4096
|
||||
block_restart_interval=16
|
||||
filter_policy=nullptr
|
||||
no_block_cache=false
|
||||
checksum=kCRC32c
|
||||
filter_policy=rocksdb.BuiltinBloomFilter
|
||||
block_size_deviation=10
|
||||
block_size=8192
|
||||
block_restart_interval=16
|
||||
cache_index_and_filter_blocks=false
|
||||
index_type=kBinarySearch
|
||||
hash_index_allow_collision=true
|
||||
|
||||
@@ -98,16 +98,6 @@ class CompactionFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
// By default, compaction will only call Filter() on keys written after the
|
||||
// most recent call to GetSnapshot(). However, if the compaction filter
|
||||
// overrides IgnoreSnapshots to make it return false, the compaction filter
|
||||
// will be called even if the keys were written before the last snapshot.
|
||||
// This behavior is to be used only when we want to delete a set of keys
|
||||
// irrespective of snapshots. In particular, care should be taken
|
||||
// to understand that the values of thesekeys will change even if we are
|
||||
// using a snapshot.
|
||||
virtual bool IgnoreSnapshots() const { return false; }
|
||||
|
||||
// Returns a name that identifies this compaction filter.
|
||||
// The name will be printed to LOG file on start up for diagnosis.
|
||||
virtual const char* Name() const = 0;
|
||||
|
||||
@@ -85,10 +85,6 @@ Status GetPlainTableOptionsFromString(
|
||||
const std::string& opts_str,
|
||||
PlainTableOptions* new_table_options);
|
||||
|
||||
Status GetMemTableRepFactoryFromString(
|
||||
const std::string& opts_str,
|
||||
std::unique_ptr<MemTableRepFactory>* new_mem_factory);
|
||||
|
||||
Status GetOptionsFromString(const Options& base_options,
|
||||
const std::string& opts_str, Options* new_options);
|
||||
|
||||
|
||||
@@ -558,12 +558,6 @@ class DB {
|
||||
virtual Status PauseBackgroundWork() = 0;
|
||||
virtual Status ContinueBackgroundWork() = 0;
|
||||
|
||||
// This function will enable automatic compactions for the given column
|
||||
// families if they were previously disabled via the disable_auto_compactions
|
||||
// option.
|
||||
virtual Status EnableAutoCompaction(
|
||||
const std::vector<ColumnFamilyHandle*>& column_family_handles) = 0;
|
||||
|
||||
// Number of levels used for this DB.
|
||||
virtual int NumberLevels(ColumnFamilyHandle* column_family) = 0;
|
||||
virtual int NumberLevels() { return NumberLevels(DefaultColumnFamily()); }
|
||||
|
||||
+6
-12
@@ -570,7 +570,7 @@ class WritableFile {
|
||||
// This asks the OS to initiate flushing the cached data to disk,
|
||||
// without waiting for completion.
|
||||
// Default implementation does nothing.
|
||||
virtual Status RangeSync(uint64_t offset, uint64_t nbytes) { return Status::OK(); }
|
||||
virtual Status RangeSync(off_t offset, off_t nbytes) { return Status::OK(); }
|
||||
|
||||
// PrepareWrite performs any necessary preparation for a write
|
||||
// before the write actually occurs. This allows for pre-allocation
|
||||
@@ -590,8 +590,8 @@ class WritableFile {
|
||||
if (new_last_preallocated_block > last_preallocated_block_) {
|
||||
size_t num_spanned_blocks =
|
||||
new_last_preallocated_block - last_preallocated_block_;
|
||||
Allocate(block_size * last_preallocated_block_,
|
||||
block_size * num_spanned_blocks);
|
||||
Allocate(static_cast<off_t>(block_size * last_preallocated_block_),
|
||||
static_cast<off_t>(block_size * num_spanned_blocks));
|
||||
last_preallocated_block_ = new_last_preallocated_block;
|
||||
}
|
||||
}
|
||||
@@ -600,7 +600,7 @@ class WritableFile {
|
||||
/*
|
||||
* Pre-allocate space for a file.
|
||||
*/
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) {
|
||||
virtual Status Allocate(off_t offset, off_t len) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -768,12 +768,6 @@ class EnvWrapper : public Env {
|
||||
const EnvOptions& options) override {
|
||||
return target_->NewWritableFile(f, r, options);
|
||||
}
|
||||
Status ReuseWritableFile(const std::string& fname,
|
||||
const std::string& old_fname,
|
||||
unique_ptr<WritableFile>* r,
|
||||
const EnvOptions& options) override {
|
||||
return target_->ReuseWritableFile(fname, old_fname, r, options);
|
||||
}
|
||||
virtual Status NewDirectory(const std::string& name,
|
||||
unique_ptr<Directory>* result) override {
|
||||
return target_->NewDirectory(name, result);
|
||||
@@ -926,10 +920,10 @@ class WritableFileWrapper : public WritableFile {
|
||||
}
|
||||
|
||||
protected:
|
||||
Status Allocate(uint64_t offset, uint64_t len) override {
|
||||
Status Allocate(off_t offset, off_t len) override {
|
||||
return target_->Allocate(offset, len);
|
||||
}
|
||||
Status RangeSync(uint64_t offset, uint64_t nbytes) override {
|
||||
Status RangeSync(off_t offset, off_t nbytes) override {
|
||||
return target_->RangeSync(offset, nbytes);
|
||||
}
|
||||
|
||||
|
||||
@@ -1090,8 +1090,8 @@ struct DBOptions {
|
||||
size_t random_access_max_buffer_size;
|
||||
|
||||
// This is the maximum buffer size that is used by WritableFileWriter.
|
||||
// On Windows, we need to maintain an aligned buffer for writes.
|
||||
// We allow the buffer to grow until it's size hits the limit.
|
||||
// On Windows, we need to maintain an aligned buffer for writes.
|
||||
// We allow the buffer to grow until it's size hits the limit.
|
||||
//
|
||||
// Default: 1024 * 1024 (1 MB)
|
||||
size_t writable_file_max_buffer_size;
|
||||
@@ -1172,13 +1172,6 @@ struct DBOptions {
|
||||
// currently.
|
||||
const WalFilter* wal_filter;
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// If true, then DB::Open / CreateColumnFamily / DropColumnFamily
|
||||
// / SetOptions will fail if options file is not detected or properly
|
||||
// persisted.
|
||||
//
|
||||
// DEFAULT: false
|
||||
bool fail_if_options_file_error;
|
||||
};
|
||||
|
||||
// Options to control the behavior of a database (passed to DB::Open)
|
||||
|
||||
@@ -73,11 +73,6 @@ class Slice {
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
void remove_suffix(size_t n) {
|
||||
assert(n <= size());
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
// Return a string that contains the copy of the referenced data.
|
||||
std::string ToString(bool hex = false) const;
|
||||
|
||||
@@ -93,11 +88,6 @@ class Slice {
|
||||
(memcmp(data_, x.data_, x.size_) == 0));
|
||||
}
|
||||
|
||||
bool ends_with(const Slice& x) const {
|
||||
return ((size_ >= x.size_) &&
|
||||
(memcmp(data_ + size_ - x.size_, x.data_, x.size_) == 0));
|
||||
}
|
||||
|
||||
// Compare two slices and returns the first byte where they differ
|
||||
size_t difference_offset(const Slice& b) const;
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class Status {
|
||||
kAborted = 10,
|
||||
kBusy = 11,
|
||||
kExpired = 12,
|
||||
kTryAgain = 13,
|
||||
kTryAgain = 13
|
||||
};
|
||||
|
||||
Code code() const { return code_; }
|
||||
|
||||
+8
-24
@@ -129,19 +129,19 @@ struct BlockBasedTableOptions {
|
||||
bool whole_key_filtering = true;
|
||||
|
||||
// If true, block will not be explictly flushed to disk during building
|
||||
// a SstTable. Instead, buffer in WritableFileWriter will take
|
||||
// care of the flushing when it is full.
|
||||
// a SstTable. Instead, buffer in WritableFileWriter will take
|
||||
// care of the flushing when it is full.
|
||||
//
|
||||
// On Windows, this option helps a lot when unbuffered I/O
|
||||
// (allow_os_buffer = false) is used, since it avoids small
|
||||
// unbuffered disk write.
|
||||
// On Windows, this option helps a lot when unbuffered I/O
|
||||
// (allow_os_buffer = false) is used, since it avoids small
|
||||
// unbuffered disk write.
|
||||
//
|
||||
// User may also adjust writable_file_max_buffer_size to optimize disk I/O
|
||||
// size.
|
||||
// User may also adjust writable_file_max_buffer_size to optimize disk I/O
|
||||
// size.
|
||||
//
|
||||
// Default: false
|
||||
bool skip_table_builder_flush = false;
|
||||
|
||||
|
||||
// We currently have three versions:
|
||||
// 0 -- This version is currently written out by all RocksDB's versions by
|
||||
// default. Can be read by really old RocksDB's. Doesn't support changing
|
||||
@@ -402,22 +402,6 @@ class TableFactory {
|
||||
// Return a string that contains printable format of table configurations.
|
||||
// RocksDB prints configurations at DB Open().
|
||||
virtual std::string GetPrintableTableOptions() const = 0;
|
||||
|
||||
// Returns the raw pointer of the table options that is used by this
|
||||
// TableFactory, or nullptr if this function is not supported.
|
||||
// Since the return value is a raw pointer, the TableFactory owns the
|
||||
// pointer and the caller should not delete the pointer.
|
||||
//
|
||||
// In certan case, it is desirable to alter the underlying options when the
|
||||
// TableFactory is not used by any open DB by casting the returned pointer
|
||||
// to the right class. For instance, if BlockBasedTableFactory is used,
|
||||
// then the pointer can be casted to BlockBasedTableOptions.
|
||||
//
|
||||
// Note that changing the underlying TableFactory options while the
|
||||
// TableFactory is currently used by any open DB is undefined behavior.
|
||||
// Developers should use DB::SetOption() instead to dynamically change
|
||||
// options while the DB is open.
|
||||
virtual void* GetOptions() { return nullptr; }
|
||||
};
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
@@ -88,14 +88,6 @@ struct BackupableDBOptions {
|
||||
// *turn it on only if you know what you're doing*
|
||||
bool share_files_with_checksum;
|
||||
|
||||
// Try to use the file size in file name instead of getting size from HDFS,
|
||||
// if the file is generated with options.share_files_with_checksum = true.
|
||||
// This is a temporary solution to reduce the backupable Db open latency when
|
||||
// There are too many sst files. Will remove the option after we have a
|
||||
// permanent solution.
|
||||
// Default: false
|
||||
bool use_file_size_in_file_name;
|
||||
|
||||
// Up to this many background threads will copy files for CreateNewBackup()
|
||||
// and RestoreDBFromBackup()
|
||||
// Default: 1
|
||||
@@ -125,7 +117,6 @@ struct BackupableDBOptions {
|
||||
backup_rate_limit(_backup_rate_limit),
|
||||
restore_rate_limit(_restore_rate_limit),
|
||||
share_files_with_checksum(false),
|
||||
use_file_size_in_file_name(false),
|
||||
max_background_operations(_max_background_operations),
|
||||
callback_trigger_interval_size(_callback_trigger_interval_size) {
|
||||
assert(share_table_files || !share_files_with_checksum);
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
// This file contains utility functions for RocksDB Options.
|
||||
#pragma once
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace rocksdb {
|
||||
// Constructs the DBOptions and ColumnFamilyDescriptors by loading the
|
||||
// latest RocksDB options file stored in the specified rocksdb database.
|
||||
//
|
||||
// Note that the all the pointer options (except table_factory, which will
|
||||
// be described in more details below) will be initialized with the default
|
||||
// values. Developers can further initialize them after this function call.
|
||||
// Below is an example list of pointer options which will be initialized
|
||||
//
|
||||
// * env
|
||||
// * memtable_factory
|
||||
// * compaction_filter_factory
|
||||
// * prefix_extractor
|
||||
// * comparator
|
||||
// * merge_operator
|
||||
// * compaction_filter
|
||||
//
|
||||
// For table_factory, this function further supports deserializing
|
||||
// BlockBasedTableFactory and its BlockBasedTableOptions except the
|
||||
// pointer options of BlockBasedTableOptions (flush_block_policy_factory,
|
||||
// block_cache, and block_cache_compressed), which will be initialized with
|
||||
// default values. Developers can further specify these three options by
|
||||
// casting the return value of TableFactoroy::GetOptions() to
|
||||
// BlockBasedTableOptions and making necessary changes.
|
||||
//
|
||||
// examples/options_file_example.cc demonstrates how to use this function
|
||||
// to open a RocksDB instance.
|
||||
//
|
||||
// @see LoadOptionsFromFile
|
||||
Status LoadLatestOptions(const std::string& dbpath, Env* env,
|
||||
DBOptions* db_options,
|
||||
std::vector<ColumnFamilyDescriptor>* cf_descs);
|
||||
|
||||
// Similar to LoadLatestOptions, this function constructs the DBOptions
|
||||
// and ColumnFamilyDescriptors based on the specified RocksDB Options file.
|
||||
//
|
||||
// @see LoadLatestOptions
|
||||
Status LoadOptionsFromFile(const std::string& options_file_name, Env* env,
|
||||
DBOptions* db_options,
|
||||
std::vector<ColumnFamilyDescriptor>* cf_descs);
|
||||
|
||||
// Returns the latest options file name under the specified db path.
|
||||
Status GetLatestOptionsFileName(const std::string& dbpath, Env* env,
|
||||
std::string* options_file_name);
|
||||
|
||||
// Returns Status::OK if the input DBOptions and ColumnFamilyDescriptors
|
||||
// are compatible with the latest options stored in the specified DB path.
|
||||
//
|
||||
// If the return status is non-ok, it means the specified RocksDB instance
|
||||
// might not be correctly opened with the input set of options. Currently,
|
||||
// changing one of the following options will fail the compatibility check:
|
||||
//
|
||||
// * comparator
|
||||
// * prefix_extractor
|
||||
// * table_factory
|
||||
// * merge_operator
|
||||
Status CheckOptionsCompatibility(
|
||||
const std::string& dbpath, Env* env, const DBOptions& db_options,
|
||||
const std::vector<ColumnFamilyDescriptor>& cf_descs);
|
||||
|
||||
} // namespace rocksdb
|
||||
#endif // !ROCKSDB_LITE
|
||||
@@ -183,11 +183,6 @@ class StackableDB : public DB {
|
||||
return db_->ContinueBackgroundWork();
|
||||
}
|
||||
|
||||
virtual Status EnableAutoCompaction(
|
||||
const std::vector<ColumnFamilyHandle*>& column_family_handles) override {
|
||||
return db_->EnableAutoCompaction(column_family_handles);
|
||||
}
|
||||
|
||||
using DB::NumberLevels;
|
||||
virtual int NumberLevels(ColumnFamilyHandle* column_family) override {
|
||||
return db_->NumberLevels(column_family);
|
||||
@@ -279,10 +274,9 @@ class StackableDB : public DB {
|
||||
}
|
||||
|
||||
using DB::SetOptions;
|
||||
virtual Status SetOptions(ColumnFamilyHandle* column_family_handle,
|
||||
const std::unordered_map<std::string, std::string>&
|
||||
new_options) override {
|
||||
return db_->SetOptions(column_family_handle, new_options);
|
||||
virtual Status SetOptions(
|
||||
const std::unordered_map<std::string, std::string>& new_options) override {
|
||||
return db_->SetOptions(new_options);
|
||||
}
|
||||
|
||||
using DB::GetPropertiesOfAllTables;
|
||||
|
||||
@@ -20,17 +20,6 @@ class Iterator;
|
||||
class TransactionDB;
|
||||
class WriteBatchWithIndex;
|
||||
|
||||
// Provides notification to the caller of SetSnapshotOnNextOperation when
|
||||
// the actual snapshot gets created
|
||||
class TransactionNotifier {
|
||||
public:
|
||||
virtual ~TransactionNotifier() {}
|
||||
|
||||
// Implement this method to receive notification when a snapshot is
|
||||
// requested via SetSnapshotOnNextOperation.
|
||||
virtual void SnapshotCreated(const Snapshot* newSnapshot) = 0;
|
||||
};
|
||||
|
||||
// Provides BEGIN/COMMIT/ROLLBACK transactions.
|
||||
//
|
||||
// To use transactions, you must first create either an OptimisticTransactionDB
|
||||
@@ -80,9 +69,6 @@ class Transaction {
|
||||
// Calling SetSnapshotOnNextOperation() will not affect what snapshot is
|
||||
// returned by GetSnapshot() until the next write/GetForUpdate is executed.
|
||||
//
|
||||
// When the snapshot is created the notifier's SnapshotCreated method will
|
||||
// be called so that the caller can get access to the snapshot.
|
||||
//
|
||||
// This is an optimization to reduce the likelyhood of conflicts that
|
||||
// could occur in between the time SetSnapshot() is called and the first
|
||||
// write/GetForUpdate operation. Eg, this prevents the following
|
||||
@@ -92,8 +78,7 @@ class Transaction {
|
||||
// txn2->Put("A", ...);
|
||||
// txn2->Commit();
|
||||
// txn1->GetForUpdate(opts, "A", ...); // FAIL!
|
||||
virtual void SetSnapshotOnNextOperation(
|
||||
std::shared_ptr<TransactionNotifier> notifier = nullptr) = 0;
|
||||
virtual void SetSnapshotOnNextOperation() = 0;
|
||||
|
||||
// Returns the Snapshot created by the last call to SetSnapshot().
|
||||
//
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#pragma once
|
||||
|
||||
#define ROCKSDB_MAJOR 4
|
||||
#define ROCKSDB_MINOR 3
|
||||
#define ROCKSDB_PATCH 1
|
||||
#define ROCKSDB_MINOR 2
|
||||
#define ROCKSDB_PATCH 0
|
||||
|
||||
// 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
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_WRITE_BATCH_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_WRITE_BATCH_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
@@ -202,39 +201,17 @@ class WriteBatch : public WriteBatchBase {
|
||||
// Returns the number of updates in the batch
|
||||
int Count() const;
|
||||
|
||||
// Returns true if PutCF will be called during Iterate
|
||||
bool HasPut() const;
|
||||
|
||||
// Returns true if DeleteCF will be called during Iterate
|
||||
bool HasDelete() const;
|
||||
|
||||
// Returns true if SingleDeleteCF will be called during Iterate
|
||||
bool HasSingleDelete() const;
|
||||
|
||||
// Returns trie if MergeCF will be called during Iterate
|
||||
bool HasMerge() const;
|
||||
|
||||
using WriteBatchBase::GetWriteBatch;
|
||||
WriteBatch* GetWriteBatch() override { return this; }
|
||||
|
||||
// Constructor with a serialized string object
|
||||
explicit WriteBatch(const std::string& rep);
|
||||
|
||||
WriteBatch(const WriteBatch& src);
|
||||
WriteBatch(WriteBatch&& src);
|
||||
WriteBatch& operator=(const WriteBatch& src);
|
||||
WriteBatch& operator=(WriteBatch&& src);
|
||||
explicit WriteBatch(const std::string& rep)
|
||||
: save_points_(nullptr), rep_(rep) {}
|
||||
|
||||
private:
|
||||
friend class WriteBatchInternal;
|
||||
SavePoints* save_points_;
|
||||
|
||||
// For HasXYZ. Mutable to allow lazy computation of results
|
||||
mutable std::atomic<uint32_t> content_flags_;
|
||||
|
||||
// Performs deferred computation of content_flags if necessary
|
||||
uint32_t ComputeContentFlags() const;
|
||||
|
||||
protected:
|
||||
std::string rep_; // See comment in write_batch.cc for the format of rep_
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ public interface ColumnFamilyOptionsInterface {
|
||||
|
||||
|
||||
/**
|
||||
* Same as fixed length prefix extractor, except that when slice is
|
||||
* Same as fixed length prefix extractor, except that when slice is
|
||||
* shorter than the fixed length, it will use the full key.
|
||||
*
|
||||
* @param n use the first n bytes of a key as its prefix.
|
||||
|
||||
@@ -565,7 +565,7 @@ public interface DBOptionsInterface {
|
||||
* are older than WAL_ttl_seconds will be deleted.</li>
|
||||
* <li>If both are not 0, WAL files will be checked every 10 min and both
|
||||
* checks will be performed with ttl being first.</li>
|
||||
* </ol>
|
||||
* </ol>
|
||||
*
|
||||
* @param sizeLimitMB size limit in mega-bytes.
|
||||
* @return the instance of the current Object.
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
#elif defined(OS_WIN)
|
||||
#include "port/win/port_win.h"
|
||||
#endif
|
||||
|
||||
|
||||
+6
-2
@@ -32,11 +32,14 @@
|
||||
#else
|
||||
#define PLATFORM_IS_LITTLE_ENDIAN false
|
||||
#endif
|
||||
#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) || \
|
||||
defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
|
||||
#elif defined(OS_FREEBSD)
|
||||
#include <sys/endian.h>
|
||||
#include <sys/types.h>
|
||||
#define PLATFORM_IS_LITTLE_ENDIAN (_BYTE_ORDER == _LITTLE_ENDIAN)
|
||||
#elif defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
|
||||
defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
#else
|
||||
#include <endian.h>
|
||||
#endif
|
||||
@@ -156,3 +159,4 @@ extern int GetMaxOpenFiles();
|
||||
|
||||
} // namespace port
|
||||
} // namespace rocksdb
|
||||
|
||||
|
||||
+11
-4
@@ -61,6 +61,12 @@ ThreadStatusUpdater* CreateThreadStatusUpdater() {
|
||||
return new ThreadStatusUpdater();
|
||||
}
|
||||
|
||||
// A wrapper for fadvise, if the platform doesn't support fadvise,
|
||||
// it will simply return Status::NotSupport.
|
||||
int Fadvise(int fd, off_t offset, size_t len, int advice) {
|
||||
return 0; // simply do nothing.
|
||||
}
|
||||
|
||||
inline Status IOErrorFromWindowsError(const std::string& context, DWORD err) {
|
||||
return Status::IOError(context, GetWindowsErrSz(err));
|
||||
}
|
||||
@@ -599,7 +605,7 @@ class WinMmapFile : public WritableFile {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) override {
|
||||
virtual Status Allocate(off_t offset, off_t len) override {
|
||||
return Status::OK();
|
||||
}
|
||||
};
|
||||
@@ -610,7 +616,7 @@ class WinSequentialFile : public SequentialFile {
|
||||
HANDLE file_;
|
||||
|
||||
// There is no equivalent of advising away buffered pages as in posix.
|
||||
// To implement this flag we would need to do unbuffered reads which
|
||||
// To implement this flag we would need to do unbuffered reads which
|
||||
// will need to be aligned (not sure there is a guarantee that the buffer
|
||||
// passed in is aligned).
|
||||
// Hence we currently ignore this flag. It is used only in a few cases
|
||||
@@ -970,7 +976,8 @@ class WinWritableFile : public WritableFile {
|
||||
virtual Status PositionedAppend(const Slice& data, uint64_t offset) override {
|
||||
Status s;
|
||||
|
||||
SSIZE_T ret = pwrite(hFile_, data.data(), data.size(), offset);
|
||||
SSIZE_T ret = pwrite(hFile_, data.data(),
|
||||
data.size(), offset);
|
||||
|
||||
// Error break
|
||||
if (ret < 0) {
|
||||
@@ -1046,7 +1053,7 @@ class WinWritableFile : public WritableFile {
|
||||
return filesize_;
|
||||
}
|
||||
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) override {
|
||||
virtual Status Allocate(off_t offset, off_t len) override {
|
||||
Status status;
|
||||
TEST_KILL_RANDOM("WinWritableFile::Allocate", rocksdb_kill_odds);
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ bool CondVar::TimedWait(uint64_t abs_time_us) {
|
||||
using namespace std::chrono;
|
||||
|
||||
// MSVC++ library implements wait_until in terms of wait_for so
|
||||
// we need to convert absolute wait into relative wait.
|
||||
// we need to convert absoulte wait into relative wait.
|
||||
microseconds usAbsTime(abs_time_us);
|
||||
|
||||
microseconds usNow(
|
||||
@@ -100,7 +100,7 @@ void CondVar::Signal() { cv_.notify_one(); }
|
||||
void CondVar::SignalAll() { cv_.notify_all(); }
|
||||
|
||||
void InitOnce(OnceType* once, void (*initializer)()) {
|
||||
std::call_once(once->flag_, initializer);
|
||||
std::call_once(*once, initializer);
|
||||
}
|
||||
|
||||
// Private structure, exposed only by pointer
|
||||
|
||||
+19
-42
@@ -25,7 +25,6 @@
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <mutex>
|
||||
#include <limits>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -42,6 +41,11 @@
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
// defined in stdio.h
|
||||
#ifndef snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#undef GetCurrentTime
|
||||
#undef DeleteFile
|
||||
|
||||
@@ -54,6 +58,8 @@ typedef SSIZE_T ssize_t;
|
||||
#define ROCKSDB_PRIszt "Iu"
|
||||
#endif
|
||||
|
||||
#define ROCKSDB_NOEXCEPT
|
||||
|
||||
#define __attribute__(A)
|
||||
|
||||
#ifdef ZLIB
|
||||
@@ -90,38 +96,17 @@ std::string GetWindowsErrSz(DWORD err);
|
||||
|
||||
namespace port {
|
||||
|
||||
// VS 15
|
||||
#if (defined _MSC_VER) && (_MSC_VER >= 1900)
|
||||
|
||||
#define ROCKSDB_NOEXCEPT noexcept
|
||||
|
||||
// For use at db/file_indexer.h kLevelMaxIndex
|
||||
const int kMaxInt32 = std::numeric_limits<int>::max();
|
||||
const uint64_t kMaxUint64 = std::numeric_limits<uint64_t>::max();
|
||||
|
||||
const size_t kMaxSizet = std::numeric_limits<size_t>::max();
|
||||
|
||||
#else //_MSC_VER
|
||||
|
||||
// VS 15 has snprintf
|
||||
#define snprintf _snprintf
|
||||
|
||||
#define ROCKSDB_NOEXCEPT
|
||||
// std::numeric_limits<size_t>::max() is not constexpr just yet
|
||||
// therefore, use the same limits
|
||||
|
||||
// For use at db/file_indexer.h kLevelMaxIndex
|
||||
const int kMaxInt32 = INT32_MAX;
|
||||
const uint64_t kMaxUint64 = UINT64_MAX;
|
||||
|
||||
// std::numeric_limits<size_t>::max() is not constexpr just yet
|
||||
// therefore, use the same limits
|
||||
#ifdef _WIN64
|
||||
const size_t kMaxSizet = UINT64_MAX;
|
||||
#else
|
||||
const size_t kMaxSizet = UINT_MAX;
|
||||
#endif
|
||||
|
||||
#endif //_MSC_VER
|
||||
|
||||
const bool kLittleEndian = true;
|
||||
|
||||
class CondVar;
|
||||
@@ -222,27 +207,19 @@ class CondVar {
|
||||
Mutex* mu_;
|
||||
};
|
||||
|
||||
|
||||
// OnceInit type helps emulate
|
||||
// Posix semantics with initialization
|
||||
// adopted in the project
|
||||
struct OnceType {
|
||||
|
||||
struct Init {};
|
||||
|
||||
OnceType() {}
|
||||
OnceType(const Init&) {}
|
||||
OnceType(const OnceType&) = delete;
|
||||
OnceType& operator=(const OnceType&) = delete;
|
||||
|
||||
std::once_flag flag_;
|
||||
};
|
||||
|
||||
#define LEVELDB_ONCE_INIT port::OnceType::Init()
|
||||
typedef std::once_flag OnceType;
|
||||
#define LEVELDB_ONCE_INIT std::once_flag::once_flag();
|
||||
extern void InitOnce(OnceType* once, void (*initializer)());
|
||||
|
||||
#define CACHE_LINE_SIZE 64U
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
// For Thread Local Storage abstraction
|
||||
typedef DWORD pthread_key_t;
|
||||
|
||||
@@ -303,4 +280,4 @@ using port::truncate;
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_
|
||||
#endif // STORAGE_LEVELDB_PORT_PORT_POSIX_H_
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
// Logger implementation that can be shared by all environments
|
||||
// where enough posix functionality is available.
|
||||
|
||||
#include "port/win/win_logger.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
@@ -20,6 +19,9 @@
|
||||
|
||||
#include "rocksdb/env.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "port/win/win_logger.h"
|
||||
#include "port/sys_time.h"
|
||||
#include "util/iostats_context_imp.h"
|
||||
|
||||
@@ -51,9 +53,8 @@ void WinLogger::close() { CloseHandle(file_); }
|
||||
void WinLogger::Flush() {
|
||||
if (flush_pending_) {
|
||||
flush_pending_ = false;
|
||||
// With Windows API writes go to OS buffers directly so no fflush needed
|
||||
// unlike with C runtime API. We don't flush all the way to disk
|
||||
// for perf reasons.
|
||||
// With Windows API writes go to OS buffers directly so no fflush needed unlike
|
||||
// with C runtime API. We don't flush all the way to disk for perf reasons.
|
||||
}
|
||||
|
||||
last_flush_micros_ = env_->NowMicros();
|
||||
@@ -123,7 +124,7 @@ void WinLogger::Logv(const char* format, va_list ap) {
|
||||
assert(p <= limit);
|
||||
const size_t write_size = p - base;
|
||||
|
||||
DWORD bytesWritten = 0;
|
||||
DWORD bytesWritten = 0;
|
||||
BOOL ret = WriteFile(file_, base, write_size, &bytesWritten, NULL);
|
||||
if (ret == FALSE) {
|
||||
std::string errSz = GetWindowsErrSz(GetLastError());
|
||||
@@ -140,9 +141,8 @@ void WinLogger::Logv(const char* format, va_list ap) {
|
||||
static_cast<uint64_t>(now_tv.tv_sec) * 1000000 + now_tv.tv_usec;
|
||||
if (now_micros - last_flush_micros_ >= flush_every_seconds_ * 1000000) {
|
||||
flush_pending_ = false;
|
||||
// With Windows API writes go to OS buffers directly so no fflush needed
|
||||
// unlike with C runtime API. We don't flush all the way to disk
|
||||
// for perf reasons.
|
||||
// With Windows API writes go to OS buffers directly so no fflush needed unlike
|
||||
// with C runtime API. We don't flush all the way to disk for perf reasons.
|
||||
last_flush_micros_ = now_micros;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
#include "rocksdb/env.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class Env;
|
||||
|
||||
@@ -118,7 +118,6 @@ LIB_SOURCES = \
|
||||
utilities/merge_operators/string_append/stringappend2.cc \
|
||||
utilities/merge_operators/string_append/stringappend.cc \
|
||||
utilities/merge_operators/uint64add.cc \
|
||||
utilities/options/options_util.cc \
|
||||
utilities/redis/redis_lists.cc \
|
||||
utilities/spatialdb/spatial_db.cc \
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector.cc \
|
||||
@@ -146,7 +145,6 @@ LIB_SOURCES = \
|
||||
util/options_sanity_check.cc \
|
||||
util/perf_context.cc \
|
||||
util/perf_level.cc \
|
||||
util/random.cc \
|
||||
util/rate_limiter.cc \
|
||||
util/skiplistrep.cc \
|
||||
util/slice.cc \
|
||||
@@ -201,14 +199,12 @@ TEST_BENCH_SOURCES = \
|
||||
db/file_indexer_test.cc \
|
||||
db/filename_test.cc \
|
||||
db/flush_job_test.cc \
|
||||
db/inlineskiplist_test.cc \
|
||||
db/listener_test.cc \
|
||||
db/log_and_apply_bench.cc \
|
||||
db/log_test.cc \
|
||||
db/manual_compaction_test.cc \
|
||||
db/memtablerep_bench.cc \
|
||||
db/merge_test.cc \
|
||||
db/options_file_test.cc \
|
||||
db/perf_context_test.cc \
|
||||
db/plain_table_db_test.cc \
|
||||
db/prefix_test.cc \
|
||||
@@ -256,7 +252,6 @@ TEST_BENCH_SOURCES = \
|
||||
utilities/geodb/geodb_test.cc \
|
||||
utilities/memory/memory_test.cc \
|
||||
utilities/merge_operators/string_append/stringappend_test.cc \
|
||||
utilities/options_util_test.cc \
|
||||
utilities/redis/redis_lists_test.cc \
|
||||
utilities/spatialdb/spatial_db_test.cc \
|
||||
utilities/table_properties_collectors/compact_on_deletion_collector_test.cc \
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
namespace rocksdb {
|
||||
|
||||
BlockBasedTableFactory::BlockBasedTableFactory(
|
||||
const BlockBasedTableOptions& _table_options)
|
||||
: table_options_(_table_options) {
|
||||
const BlockBasedTableOptions& table_options)
|
||||
: table_options_(table_options) {
|
||||
if (table_options_.flush_block_policy_factory == nullptr) {
|
||||
table_options_.flush_block_policy_factory.reset(
|
||||
new FlushBlockBySizePolicyFactory());
|
||||
@@ -162,13 +162,13 @@ std::string BlockBasedTableFactory::GetPrintableTableOptions() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const BlockBasedTableOptions& BlockBasedTableFactory::table_options() const {
|
||||
const BlockBasedTableOptions& BlockBasedTableFactory::GetTableOptions() const {
|
||||
return table_options_;
|
||||
}
|
||||
|
||||
TableFactory* NewBlockBasedTableFactory(
|
||||
const BlockBasedTableOptions& _table_options) {
|
||||
return new BlockBasedTableFactory(_table_options);
|
||||
const BlockBasedTableOptions& table_options) {
|
||||
return new BlockBasedTableFactory(table_options);
|
||||
}
|
||||
|
||||
const std::string BlockBasedTablePropertyNames::kIndexType =
|
||||
|
||||
@@ -56,9 +56,7 @@ class BlockBasedTableFactory : public TableFactory {
|
||||
|
||||
std::string GetPrintableTableOptions() const override;
|
||||
|
||||
const BlockBasedTableOptions& table_options() const;
|
||||
|
||||
void* GetOptions() override { return &table_options_; }
|
||||
const BlockBasedTableOptions& GetTableOptions() const;
|
||||
|
||||
private:
|
||||
BlockBasedTableOptions table_options_;
|
||||
|
||||
@@ -1117,12 +1117,9 @@ bool BlockBasedTable::PrefixMayMatch(const Slice& internal_key) {
|
||||
}
|
||||
|
||||
assert(rep_->ioptions.prefix_extractor != nullptr);
|
||||
auto user_key = ExtractUserKey(internal_key);
|
||||
if (!rep_->ioptions.prefix_extractor->InDomain(user_key)) {
|
||||
return true;
|
||||
}
|
||||
auto prefix = rep_->ioptions.prefix_extractor->Transform(user_key);
|
||||
InternalKey internal_key_prefix(prefix, kMaxSequenceNumber, kTypeValue);
|
||||
auto prefix = rep_->ioptions.prefix_extractor->Transform(
|
||||
ExtractUserKey(internal_key));
|
||||
InternalKey internal_key_prefix(prefix, 0, kTypeValue);
|
||||
auto internal_prefix = internal_key_prefix.Encode();
|
||||
|
||||
bool may_match = true;
|
||||
@@ -1205,7 +1202,6 @@ bool BlockBasedTable::FullFilterKeyMayMatch(FilterBlockReader* filter,
|
||||
return false;
|
||||
}
|
||||
if (rep_->ioptions.prefix_extractor &&
|
||||
rep_->ioptions.prefix_extractor->InDomain(user_key) &&
|
||||
!filter->PrefixMayMatch(
|
||||
rep_->ioptions.prefix_extractor->Transform(user_key))) {
|
||||
return false;
|
||||
|
||||
@@ -72,10 +72,8 @@ class CuckooTableFactory : public TableFactory {
|
||||
|
||||
std::string GetPrintableTableOptions() const override;
|
||||
|
||||
void* GetOptions() override { return &table_options_; }
|
||||
|
||||
private:
|
||||
CuckooTableOptions table_options_;
|
||||
const CuckooTableOptions table_options_;
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -21,8 +21,8 @@ Status PlainTableFactory::NewTableReader(
|
||||
return PlainTableReader::Open(
|
||||
table_reader_options.ioptions, table_reader_options.env_options,
|
||||
table_reader_options.internal_comparator, std::move(file), file_size,
|
||||
table, table_options_.bloom_bits_per_key, table_options_.hash_table_ratio,
|
||||
table_options_.index_sparseness, table_options_.huge_page_tlb_size,
|
||||
table, table_options_.bloom_bits_per_key, table_options_.hash_table_ratio,
|
||||
table_options_.index_sparseness, table_options_.huge_page_tlb_size,
|
||||
table_options_.full_scan_mode);
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ TableBuilder* PlainTableFactory::NewTableBuilder(
|
||||
return new PlainTableBuilder(
|
||||
table_builder_options.ioptions,
|
||||
table_builder_options.int_tbl_prop_collector_factories, column_family_id,
|
||||
file, table_options_.user_key_len, table_options_.encoding_type,
|
||||
table_options_.index_sparseness, table_options_.bloom_bits_per_key, 6,
|
||||
file, table_options_.user_key_len, table_options_.encoding_type,
|
||||
table_options_.index_sparseness, table_options_.bloom_bits_per_key, 6,
|
||||
table_options_.huge_page_tlb_size, table_options_.hash_table_ratio,
|
||||
table_options_.store_index_in_file);
|
||||
}
|
||||
@@ -75,7 +75,7 @@ std::string PlainTableFactory::GetPrintableTableOptions() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const PlainTableOptions& PlainTableFactory::table_options() const {
|
||||
const PlainTableOptions& PlainTableFactory::GetTableOptions() const {
|
||||
return table_options_;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,23 +142,23 @@ class PlainTableFactory : public TableFactory {
|
||||
// huge_page_tlb_size determines whether to allocate hash indexes from huge
|
||||
// page TLB and the page size if allocating from there. See comments of
|
||||
// Arena::AllocateAligned() for details.
|
||||
explicit PlainTableFactory(
|
||||
const PlainTableOptions& _table_options = PlainTableOptions())
|
||||
: table_options_(_table_options) {}
|
||||
explicit PlainTableFactory(const PlainTableOptions& table_options =
|
||||
PlainTableOptions())
|
||||
: table_options_(table_options) {};
|
||||
|
||||
const char* Name() const override { return "PlainTable"; }
|
||||
Status NewTableReader(const TableReaderOptions& table_reader_options,
|
||||
unique_ptr<RandomAccessFileReader>&& file,
|
||||
uint64_t file_size,
|
||||
unique_ptr<TableReader>* table) const override;
|
||||
|
||||
|
||||
TableBuilder* NewTableBuilder(
|
||||
const TableBuilderOptions& table_builder_options,
|
||||
uint32_t column_family_id, WritableFileWriter* file) const override;
|
||||
|
||||
std::string GetPrintableTableOptions() const override;
|
||||
|
||||
const PlainTableOptions& table_options() const;
|
||||
const PlainTableOptions& GetTableOptions() const;
|
||||
|
||||
static const char kValueTypeSeqId0 = char(0xFF);
|
||||
|
||||
@@ -168,8 +168,6 @@ class PlainTableFactory : public TableFactory {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void* GetOptions() override { return &table_options_; }
|
||||
|
||||
private:
|
||||
PlainTableOptions table_options_;
|
||||
};
|
||||
|
||||
+12
-10
@@ -409,8 +409,7 @@ Status PlainTableReader::PopulateIndex(TableProperties* props,
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status PlainTableReader::GetOffset(PlainTableKeyDecoder* decoder,
|
||||
const Slice& target, const Slice& prefix,
|
||||
Status PlainTableReader::GetOffset(const Slice& target, const Slice& prefix,
|
||||
uint32_t prefix_hash, bool& prefix_matched,
|
||||
uint32_t* offset) const {
|
||||
prefix_matched = false;
|
||||
@@ -436,12 +435,15 @@ Status PlainTableReader::GetOffset(PlainTableKeyDecoder* decoder,
|
||||
return Status::Corruption(Slice());
|
||||
}
|
||||
|
||||
PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_,
|
||||
ioptions_.prefix_extractor);
|
||||
|
||||
// The key is between [low, high). Do a binary search between it.
|
||||
while (high - low > 1) {
|
||||
uint32_t mid = (high + low) / 2;
|
||||
uint32_t file_offset = GetFixed32Element(base_ptr, mid);
|
||||
uint32_t tmp;
|
||||
Status s = decoder->NextKeyNoValue(file_offset, &mid_key, nullptr, &tmp);
|
||||
Status s = decoder.NextKeyNoValue(file_offset, &mid_key, nullptr, &tmp);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -466,7 +468,7 @@ Status PlainTableReader::GetOffset(PlainTableKeyDecoder* decoder,
|
||||
ParsedInternalKey low_key;
|
||||
uint32_t tmp;
|
||||
uint32_t low_key_offset = GetFixed32Element(base_ptr, low);
|
||||
Status s = decoder->NextKeyNoValue(low_key_offset, &low_key, nullptr, &tmp);
|
||||
Status s = decoder.NextKeyNoValue(low_key_offset, &low_key, nullptr, &tmp);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -557,10 +559,8 @@ Status PlainTableReader::Get(const ReadOptions& ro, const Slice& target,
|
||||
}
|
||||
uint32_t offset;
|
||||
bool prefix_match;
|
||||
PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_,
|
||||
ioptions_.prefix_extractor);
|
||||
Status s = GetOffset(&decoder, target, prefix_slice, prefix_hash,
|
||||
prefix_match, &offset);
|
||||
Status s =
|
||||
GetOffset(target, prefix_slice, prefix_hash, prefix_match, &offset);
|
||||
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
@@ -571,6 +571,8 @@ Status PlainTableReader::Get(const ReadOptions& ro, const Slice& target,
|
||||
return Status::Corruption(Slice());
|
||||
}
|
||||
Slice found_value;
|
||||
PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_,
|
||||
ioptions_.prefix_extractor);
|
||||
while (offset < file_info_.data_end_offset) {
|
||||
s = Next(&decoder, &offset, &found_key, nullptr, &found_value);
|
||||
if (!s.ok()) {
|
||||
@@ -660,8 +662,8 @@ void PlainTableIterator::Seek(const Slice& target) {
|
||||
}
|
||||
}
|
||||
bool prefix_match;
|
||||
status_ = table_->GetOffset(&decoder_, target, prefix_slice, prefix_hash,
|
||||
prefix_match, &next_offset_);
|
||||
status_ = table_->GetOffset(target, prefix_slice, prefix_hash, prefix_match,
|
||||
&next_offset_);
|
||||
if (!status_.ok()) {
|
||||
offset_ = next_offset_ = table_->file_info_.data_end_offset;
|
||||
return;
|
||||
|
||||
@@ -219,9 +219,9 @@ class PlainTableReader: public TableReader {
|
||||
// Get file offset for key target.
|
||||
// return value prefix_matched is set to true if the offset is confirmed
|
||||
// for a key with the same prefix as target.
|
||||
Status GetOffset(PlainTableKeyDecoder* decoder, const Slice& target,
|
||||
const Slice& prefix, uint32_t prefix_hash,
|
||||
bool& prefix_matched, uint32_t* offset) const;
|
||||
Status GetOffset(const Slice& target, const Slice& prefix,
|
||||
uint32_t prefix_hash, bool& prefix_matched,
|
||||
uint32_t* offset) const;
|
||||
|
||||
bool IsTotalOrderMode() const { return (prefix_extractor_ == nullptr); }
|
||||
|
||||
|
||||
@@ -258,7 +258,6 @@ DEFINE_bool(iterator, false, "For test iterator");
|
||||
DEFINE_bool(through_db, false, "If enable, a DB instance will be created and "
|
||||
"the query will be against DB. Otherwise, will be directly against "
|
||||
"a table reader.");
|
||||
DEFINE_bool(mmap_read, true, "Whether use mmap read");
|
||||
DEFINE_string(table_factory, "block_based",
|
||||
"Table factory to use: `block_based` (default), `plain_table` or "
|
||||
"`cuckoo_hash`.");
|
||||
@@ -284,8 +283,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
if (FLAGS_table_factory == "cuckoo_hash") {
|
||||
#ifndef ROCKSDB_LITE
|
||||
options.allow_mmap_reads = FLAGS_mmap_read;
|
||||
env_options.use_mmap_reads = FLAGS_mmap_read;
|
||||
options.allow_mmap_reads = true;
|
||||
env_options.use_mmap_reads = true;
|
||||
rocksdb::CuckooTableOptions table_options;
|
||||
table_options.hash_table_ratio = 0.75;
|
||||
tf.reset(rocksdb::NewCuckooTableFactory(table_options));
|
||||
@@ -295,8 +294,8 @@ int main(int argc, char** argv) {
|
||||
#endif // ROCKSDB_LITE
|
||||
} else if (FLAGS_table_factory == "plain_table") {
|
||||
#ifndef ROCKSDB_LITE
|
||||
options.allow_mmap_reads = FLAGS_mmap_read;
|
||||
env_options.use_mmap_reads = FLAGS_mmap_read;
|
||||
options.allow_mmap_reads = true;
|
||||
env_options.use_mmap_reads = true;
|
||||
|
||||
rocksdb::PlainTableOptions plain_table_options;
|
||||
plain_table_options.user_key_len = 16;
|
||||
|
||||
@@ -1242,41 +1242,6 @@ TEST_F(BlockBasedTableTest, TotalOrderSeekOnHashIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BlockBasedTableTest, NoopTransformSeek) {
|
||||
BlockBasedTableOptions table_options;
|
||||
table_options.filter_policy.reset(NewBloomFilterPolicy(10));
|
||||
|
||||
Options options;
|
||||
options.comparator = BytewiseComparator();
|
||||
options.table_factory.reset(new BlockBasedTableFactory(table_options));
|
||||
options.prefix_extractor.reset(NewNoopTransform());
|
||||
|
||||
TableConstructor c(options.comparator);
|
||||
// To tickle the PrefixMayMatch bug it is important that the
|
||||
// user-key is a single byte so that the index key exactly matches
|
||||
// the user-key.
|
||||
InternalKey key("a", 1, kTypeValue);
|
||||
c.Add(key.Encode().ToString(), "b");
|
||||
std::vector<std::string> keys;
|
||||
stl_wrappers::KVMap kvmap;
|
||||
const ImmutableCFOptions ioptions(options);
|
||||
const InternalKeyComparator internal_comparator(options.comparator);
|
||||
c.Finish(options, ioptions, table_options, internal_comparator, &keys,
|
||||
&kvmap);
|
||||
|
||||
auto* reader = c.GetTableReader();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ReadOptions ro;
|
||||
ro.total_order_seek = (i == 0);
|
||||
std::unique_ptr<InternalIterator> iter(reader->NewIterator(ro));
|
||||
|
||||
iter->Seek(key.Encode());
|
||||
ASSERT_OK(iter->status());
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
ASSERT_EQ("a", ExtractUserKey(iter->key()).ToString());
|
||||
}
|
||||
}
|
||||
|
||||
static std::string RandomString(Random* rnd, int len) {
|
||||
std::string r;
|
||||
test::RandomString(rnd, len, &r);
|
||||
|
||||
+1
-1
@@ -2592,7 +2592,7 @@ class Hunk {
|
||||
// Print a unified diff header for one hunk.
|
||||
// The format is
|
||||
// "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
|
||||
// where the left/right parts are omitted if unnecessary.
|
||||
// where the left/right parts are ommitted if unnecessary.
|
||||
void PrintHeader(std::ostream* ss) const {
|
||||
*ss << "@@ ";
|
||||
if (removes_) {
|
||||
|
||||
@@ -36,19 +36,6 @@ endif ()
|
||||
|
||||
if (${USE_GFLAGS} EQUAL 1)
|
||||
message(STATUS "GFLAGS library is enabled")
|
||||
|
||||
if(DEFINED ENV{GFLAGS_INCLUDE})
|
||||
set(GFLAGS_INCLUDE $ENV{GFLAGS_INCLUDE})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{GFLAGS_LIB_DEBUG})
|
||||
set(GFLAGS_LIB_DEBUG $ENV{GFLAGS_LIB_DEBUG})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{GFLAGS_LIB_RELEASE})
|
||||
set(GFLAGS_LIB_RELEASE $ENV{GFLAGS_LIB_RELEASE})
|
||||
endif()
|
||||
|
||||
set(GFLAGS_CXX_FLAGS -DGFLAGS=gflags)
|
||||
set(GFLAGS_LIBS debug ${GFLAGS_LIB_DEBUG} optimized ${GFLAGS_LIB_RELEASE})
|
||||
|
||||
@@ -79,19 +66,6 @@ endif ()
|
||||
|
||||
if (${USE_SNAPPY} EQUAL 1)
|
||||
message(STATUS "SNAPPY library is enabled")
|
||||
|
||||
if(DEFINED ENV{SNAPPY_INCLUDE})
|
||||
set(SNAPPY_INCLUDE $ENV{SNAPPY_INCLUDE})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{SNAPPY_LIB_DEBUG})
|
||||
set(SNAPPY_LIB_DEBUG $ENV{SNAPPY_LIB_DEBUG})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{SNAPPY_LIB_RELEASE})
|
||||
set(SNAPPY_LIB_RELEASE $ENV{SNAPPY_LIB_RELEASE})
|
||||
endif()
|
||||
|
||||
set(SNAPPY_CXX_FLAGS -DSNAPPY)
|
||||
set(SNAPPY_LIBS debug ${SNAPPY_LIB_DEBUG} optimized ${SNAPPY_LIB_RELEASE})
|
||||
|
||||
@@ -122,19 +96,6 @@ endif ()
|
||||
|
||||
if (${USE_LZ4} EQUAL 1)
|
||||
message(STATUS "LZ4 library is enabled")
|
||||
|
||||
if(DEFINED ENV{LZ4_INCLUDE})
|
||||
set(LZ4_INCLUDE $ENV{LZ4_INCLUDE})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{LZ4_LIB_DEBUG})
|
||||
set(LZ4_LIB_DEBUG $ENV{LZ4_LIB_DEBUG})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{LZ4_LIB_RELEASE})
|
||||
set(LZ4_LIB_RELEASE $ENV{LZ4_LIB_RELEASE})
|
||||
endif()
|
||||
|
||||
set(LZ4_CXX_FLAGS -DLZ4)
|
||||
set(LZ4_LIBS debug ${LZ4_LIB_DEBUG} optimized ${LZ4_LIB_RELEASE})
|
||||
|
||||
@@ -165,19 +126,6 @@ endif ()
|
||||
|
||||
if (${USE_ZLIB} EQUAL 1)
|
||||
message(STATUS "ZLIB library is enabled")
|
||||
|
||||
if(DEFINED ENV{ZLIB_INCLUDE})
|
||||
set(ZLIB_INCLUDE $ENV{ZLIB_INCLUDE})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{ZLIB_LIB_DEBUG})
|
||||
set(ZLIB_LIB_DEBUG $ENV{ZLIB_LIB_DEBUG})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{ZLIB_LIB_RELEASE})
|
||||
set(ZLIB_LIB_RELEASE $ENV{ZLIB_LIB_RELEASE})
|
||||
endif()
|
||||
|
||||
set(ZLIB_CXX_FLAGS -DZLIB)
|
||||
set(ZLIB_LIBS debug ${ZLIB_LIB_DEBUG} optimized ${ZLIB_LIB_RELEASE})
|
||||
|
||||
@@ -209,19 +157,6 @@ endif ()
|
||||
if (${USE_JEMALLOC} EQUAL 1)
|
||||
message(STATUS "JEMALLOC library is enabled")
|
||||
set(JEMALLOC_CXX_FLAGS -DJEMALLOC)
|
||||
|
||||
if(DEFINED ENV{JEMALLOC_INCLUDE})
|
||||
set(JEMALLOC_INCLUDE $ENV{JEMALLOC_INCLUDE})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{JEMALLOC_LIB_DEBUG})
|
||||
set(JEMALLOC_LIB_DEBUG $ENV{JEMALLOC_LIB_DEBUG})
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{JEMALLOC_LIB_RELEASE})
|
||||
set(JEMALLOC_LIB_RELEASE $ENV{JEMALLOC_LIB_RELEASE})
|
||||
endif()
|
||||
|
||||
set(JEMALLOC_LIBS debug ${JEMALLOC_LIB_DEBUG} optimized ${JEMALLOC_LIB_RELEASE})
|
||||
|
||||
add_definitions(${JEMALLOC_CXX_FLAGS})
|
||||
|
||||
+1
-2
@@ -610,8 +610,7 @@ class Stats {
|
||||
"", bytes_mb, rate, (100*writes_)/done_, done_);
|
||||
fprintf(stdout, "%-12s: Wrote %ld times\n", "", writes_);
|
||||
fprintf(stdout, "%-12s: Deleted %ld times\n", "", deletes_);
|
||||
fprintf(stdout, "%-12s: Single deleted %" ROCKSDB_PRIszt " times\n", "",
|
||||
single_deletes_);
|
||||
fprintf(stdout, "%-12s: Single deleted %ld times\n", "", single_deletes_);
|
||||
fprintf(stdout, "%-12s: %ld read and %ld found the key\n", "",
|
||||
gets_, founds_);
|
||||
fprintf(stdout, "%-12s: Prefix scanned %ld times\n", "", prefixes_);
|
||||
|
||||
+7
-27
@@ -449,10 +449,7 @@ void CompactorCommand::DoCommand() {
|
||||
end = new Slice(to_);
|
||||
}
|
||||
|
||||
CompactRangeOptions cro;
|
||||
cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
|
||||
|
||||
db_->CompactRange(cro, begin, end);
|
||||
db_->CompactRange(CompactRangeOptions(), begin, end);
|
||||
exec_state_ = LDBCommandExecuteResult::Succeed("");
|
||||
|
||||
delete begin;
|
||||
@@ -1762,6 +1759,7 @@ void ScanCommand::DoCommand() {
|
||||
for ( ;
|
||||
it->Valid() && (!end_key_specified_ || it->key().ToString() < end_key_);
|
||||
it->Next()) {
|
||||
string key = ldb_options_.key_formatter->Format(it->key());
|
||||
if (is_db_ttl_) {
|
||||
TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(it);
|
||||
assert(it_ttl);
|
||||
@@ -1773,29 +1771,11 @@ void ScanCommand::DoCommand() {
|
||||
fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Slice key_slice = it->key();
|
||||
Slice val_slice = it->value();
|
||||
|
||||
std::string formatted_key;
|
||||
if (is_key_hex_) {
|
||||
formatted_key = "0x" + key_slice.ToString(true /* hex */);
|
||||
key_slice = formatted_key;
|
||||
} else if (ldb_options_.key_formatter) {
|
||||
formatted_key = ldb_options_.key_formatter->Format(key_slice);
|
||||
key_slice = formatted_key;
|
||||
}
|
||||
|
||||
std::string formatted_value;
|
||||
if (is_value_hex_) {
|
||||
formatted_value = "0x" + val_slice.ToString(true /* hex */);
|
||||
val_slice = formatted_value;
|
||||
}
|
||||
|
||||
fprintf(stdout, "%.*s : %.*s\n",
|
||||
static_cast<int>(key_slice.size()), key_slice.data(),
|
||||
static_cast<int>(val_slice.size()), val_slice.data());
|
||||
|
||||
string value = it->value().ToString();
|
||||
fprintf(stdout, "%s : %s\n",
|
||||
(is_key_hex_ ? "0x" + it->key().ToString(true) : key).c_str(),
|
||||
(is_value_hex_ ? StringToHex(value) : value).c_str()
|
||||
);
|
||||
num_keys_scanned++;
|
||||
if (max_keys_scanned_ >= 0 && num_keys_scanned >= max_keys_scanned_) {
|
||||
break;
|
||||
|
||||
+10
-1
@@ -9,7 +9,16 @@
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
LDBOptions::LDBOptions() {}
|
||||
class DefaultSliceFormatter : public SliceFormatter {
|
||||
public:
|
||||
virtual std::string Format(const Slice& s) const override {
|
||||
return s.ToString();
|
||||
}
|
||||
};
|
||||
|
||||
LDBOptions::LDBOptions()
|
||||
: key_formatter(new DefaultSliceFormatter()) {
|
||||
}
|
||||
|
||||
class LDBCommandRunner {
|
||||
public:
|
||||
|
||||
+2
-2
@@ -296,8 +296,8 @@ void AssignEnvOptions(EnvOptions* env_options, const DBOptions& options) {
|
||||
env_options->random_access_max_buffer_size =
|
||||
options.random_access_max_buffer_size;
|
||||
env_options->rate_limiter = options.rate_limiter.get();
|
||||
env_options->writable_file_max_buffer_size =
|
||||
options.writable_file_max_buffer_size;
|
||||
env_options->writable_file_max_buffer_size =
|
||||
options.writable_file_max_buffer_size;
|
||||
env_options->allow_fallocate = options.allow_fallocate;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -971,11 +971,11 @@ TEST_F(EnvPosixTest, WritableFileWrapper) {
|
||||
}
|
||||
|
||||
protected:
|
||||
Status Allocate(uint64_t offset, uint64_t len) override {
|
||||
Status Allocate(off_t offset, off_t len) override {
|
||||
inc(11);
|
||||
return Status::OK();
|
||||
}
|
||||
Status RangeSync(uint64_t offset, uint64_t nbytes) override {
|
||||
Status RangeSync(off_t offset, off_t nbytes) override {
|
||||
inc(12);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ Status WritableFileWriter::SyncInternal(bool use_fsync) {
|
||||
return s;
|
||||
}
|
||||
|
||||
Status WritableFileWriter::RangeSync(uint64_t offset, uint64_t nbytes) {
|
||||
Status WritableFileWriter::RangeSync(off_t offset, off_t nbytes) {
|
||||
IOSTATS_TIMER_GUARD(range_sync_nanos);
|
||||
TEST_SYNC_POINT("WritableFileWriter::RangeSync:0");
|
||||
return writable_file_->RangeSync(offset, nbytes);
|
||||
|
||||
@@ -162,7 +162,7 @@ class WritableFileWriter {
|
||||
Status WriteUnbuffered();
|
||||
// Normal write
|
||||
Status WriteBuffered(const char* data, size_t size);
|
||||
Status RangeSync(uint64_t offset, uint64_t nbytes);
|
||||
Status RangeSync(off_t offset, off_t nbytes);
|
||||
size_t RequestToken(size_t bytes, bool align);
|
||||
Status SyncInternal(bool use_fsync);
|
||||
};
|
||||
|
||||
@@ -47,8 +47,8 @@ TEST_F(WritableFileWriterTest, RangeSync) {
|
||||
}
|
||||
|
||||
protected:
|
||||
Status Allocate(uint64_t offset, uint64_t len) override { return Status::OK(); }
|
||||
Status RangeSync(uint64_t offset, uint64_t nbytes) override {
|
||||
Status Allocate(off_t offset, off_t len) override { return Status::OK(); }
|
||||
Status RangeSync(off_t offset, off_t nbytes) override {
|
||||
EXPECT_EQ(offset % 4096, 0u);
|
||||
EXPECT_EQ(nbytes % 4096, 0u);
|
||||
|
||||
|
||||
+6
-15
@@ -478,15 +478,12 @@ Status PosixMmapFile::InvalidateCache(size_t offset, size_t length) {
|
||||
}
|
||||
|
||||
#ifdef ROCKSDB_FALLOCATE_PRESENT
|
||||
Status PosixMmapFile::Allocate(uint64_t offset, uint64_t len) {
|
||||
assert(offset <= std::numeric_limits<off_t>::max());
|
||||
assert(len <= std::numeric_limits<off_t>::max());
|
||||
Status PosixMmapFile::Allocate(off_t offset, off_t len) {
|
||||
TEST_KILL_RANDOM("PosixMmapFile::Allocate:0", rocksdb_kill_odds);
|
||||
int alloc_status = 0;
|
||||
if (allow_fallocate_) {
|
||||
alloc_status = fallocate(
|
||||
fd_, fallocate_with_keep_size_ ? FALLOC_FL_KEEP_SIZE : 0,
|
||||
static_cast<off_t>(offset), static_cast<off_t>(len));
|
||||
fd_, fallocate_with_keep_size_ ? FALLOC_FL_KEEP_SIZE : 0, offset, len);
|
||||
}
|
||||
if (alloc_status == 0) {
|
||||
return Status::OK();
|
||||
@@ -609,16 +606,13 @@ Status PosixWritableFile::InvalidateCache(size_t offset, size_t length) {
|
||||
}
|
||||
|
||||
#ifdef ROCKSDB_FALLOCATE_PRESENT
|
||||
Status PosixWritableFile::Allocate(uint64_t offset, uint64_t len) {
|
||||
assert(offset <= std::numeric_limits<off_t>::max());
|
||||
assert(len <= std::numeric_limits<off_t>::max());
|
||||
Status PosixWritableFile::Allocate(off_t offset, off_t len) {
|
||||
TEST_KILL_RANDOM("PosixWritableFile::Allocate:0", rocksdb_kill_odds);
|
||||
IOSTATS_TIMER_GUARD(allocate_nanos);
|
||||
int alloc_status = 0;
|
||||
if (allow_fallocate_) {
|
||||
alloc_status = fallocate(
|
||||
fd_, fallocate_with_keep_size_ ? FALLOC_FL_KEEP_SIZE : 0,
|
||||
static_cast<off_t>(offset), static_cast<off_t>(len));
|
||||
fd_, fallocate_with_keep_size_ ? FALLOC_FL_KEEP_SIZE : 0, offset, len);
|
||||
}
|
||||
if (alloc_status == 0) {
|
||||
return Status::OK();
|
||||
@@ -627,11 +621,8 @@ Status PosixWritableFile::Allocate(uint64_t offset, uint64_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
Status PosixWritableFile::RangeSync(uint64_t offset, uint64_t nbytes) {
|
||||
assert(offset <= std::numeric_limits<off_t>::max());
|
||||
assert(nbytes <= std::numeric_limits<off_t>::max());
|
||||
if (sync_file_range(fd_, static_cast<off_t>(offset),
|
||||
static_cast<off_t>(nbytes), SYNC_FILE_RANGE_WRITE) == 0) {
|
||||
Status PosixWritableFile::RangeSync(off_t offset, off_t nbytes) {
|
||||
if (sync_file_range(fd_, offset, nbytes, SYNC_FILE_RANGE_WRITE) == 0) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
return IOError(filename_, errno);
|
||||
|
||||
+3
-3
@@ -90,8 +90,8 @@ class PosixWritableFile : public WritableFile {
|
||||
virtual uint64_t GetFileSize() override;
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) override;
|
||||
#ifdef ROCKSDB_FALLOCATE_PRESENT
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) override;
|
||||
virtual Status RangeSync(uint64_t offset, uint64_t nbytes) override;
|
||||
virtual Status Allocate(off_t offset, off_t len) override;
|
||||
virtual Status RangeSync(off_t offset, off_t nbytes) override;
|
||||
virtual size_t GetUniqueId(char* id, size_t max_size) const override;
|
||||
#endif
|
||||
};
|
||||
@@ -157,7 +157,7 @@ class PosixMmapFile : public WritableFile {
|
||||
virtual uint64_t GetFileSize() override;
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) override;
|
||||
#ifdef ROCKSDB_FALLOCATE_PRESENT
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) override;
|
||||
virtual Status Allocate(off_t offset, off_t len) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
+8
-7
@@ -259,12 +259,12 @@ DBOptions::DBOptions()
|
||||
enable_thread_tracking(false),
|
||||
delayed_write_rate(1024U * 1024U),
|
||||
skip_stats_update_on_db_open(false),
|
||||
wal_recovery_mode(WALRecoveryMode::kTolerateCorruptedTailRecords),
|
||||
row_cache(nullptr),
|
||||
wal_recovery_mode(WALRecoveryMode::kTolerateCorruptedTailRecords)
|
||||
#ifndef ROCKSDB_LITE
|
||||
wal_filter(nullptr),
|
||||
,
|
||||
wal_filter(nullptr)
|
||||
#endif // ROCKSDB_LITE
|
||||
fail_if_options_file_error(false) {
|
||||
{
|
||||
}
|
||||
|
||||
DBOptions::DBOptions(const Options& options)
|
||||
@@ -323,11 +323,12 @@ DBOptions::DBOptions(const Options& options)
|
||||
delayed_write_rate(options.delayed_write_rate),
|
||||
skip_stats_update_on_db_open(options.skip_stats_update_on_db_open),
|
||||
wal_recovery_mode(options.wal_recovery_mode),
|
||||
row_cache(options.row_cache),
|
||||
row_cache(options.row_cache)
|
||||
#ifndef ROCKSDB_LITE
|
||||
wal_filter(options.wal_filter),
|
||||
,
|
||||
wal_filter(options.wal_filter)
|
||||
#endif // ROCKSDB_LITE
|
||||
fail_if_options_file_error(options.fail_if_options_file_error) {
|
||||
{
|
||||
}
|
||||
|
||||
static const char* const access_hints[] = {
|
||||
|
||||
+212
-327
@@ -106,27 +106,32 @@ std::string trim(const std::string& str) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ParseEnum(const std::unordered_map<std::string, T>& type_map,
|
||||
const std::string& type, T* value) {
|
||||
auto iter = type_map.find(type);
|
||||
if (iter != type_map.end()) {
|
||||
*value = iter->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool SerializeEnum(const std::unordered_map<std::string, T>& type_map,
|
||||
const T& type, std::string* value) {
|
||||
for (const auto& pair : type_map) {
|
||||
if (pair.second == type) {
|
||||
*value = pair.first;
|
||||
bool SerializeCompressionType(const CompressionType& type, std::string* value) {
|
||||
switch (type) {
|
||||
case kNoCompression:
|
||||
*value = "kNoCompression";
|
||||
return true;
|
||||
}
|
||||
case kSnappyCompression:
|
||||
*value = "kSnappyCompression";
|
||||
return true;
|
||||
case kZlibCompression:
|
||||
*value = "kZlibCompression";
|
||||
return true;
|
||||
case kBZip2Compression:
|
||||
*value = "kBZip2Compression";
|
||||
return true;
|
||||
case kLZ4Compression:
|
||||
*value = "kLZ4Compression";
|
||||
return true;
|
||||
case kLZ4HCCompression:
|
||||
*value = "kLZ4HCCompression";
|
||||
return true;
|
||||
case kZSTDNotFinalCompression:
|
||||
*value = "kZSTDNotFinalCompression";
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
|
||||
@@ -138,8 +143,7 @@ bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
|
||||
ss << ':';
|
||||
}
|
||||
std::string string_type;
|
||||
result = SerializeEnum<CompressionType>(compression_type_string_map,
|
||||
types[i], &string_type);
|
||||
result = SerializeCompressionType(types[i], &string_type);
|
||||
if (result == false) {
|
||||
return result;
|
||||
}
|
||||
@@ -149,6 +153,101 @@ bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseCompressionType(const std::string& string_value,
|
||||
CompressionType* type) {
|
||||
if (string_value == "kNoCompression") {
|
||||
*type = kNoCompression;
|
||||
} else if (string_value == "kSnappyCompression") {
|
||||
*type = kSnappyCompression;
|
||||
} else if (string_value == "kZlibCompression") {
|
||||
*type = kZlibCompression;
|
||||
} else if (string_value == "kBZip2Compression") {
|
||||
*type = kBZip2Compression;
|
||||
} else if (string_value == "kLZ4Compression") {
|
||||
*type = kLZ4Compression;
|
||||
} else if (string_value == "kLZ4HCCompression") {
|
||||
*type = kLZ4HCCompression;
|
||||
} else if (string_value == "kZSTDNotFinalCompression") {
|
||||
*type = kZSTDNotFinalCompression;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerializeBlockBasedTableIndexType(
|
||||
const BlockBasedTableOptions::IndexType& type, std::string* value) {
|
||||
switch (type) {
|
||||
case BlockBasedTableOptions::kBinarySearch:
|
||||
*value = "kBinarySearch";
|
||||
return true;
|
||||
case BlockBasedTableOptions::kHashSearch:
|
||||
*value = "kHashSearch";
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ParseBlockBasedTableIndexType(const std::string& type,
|
||||
BlockBasedTableOptions::IndexType* value) {
|
||||
if (type == "kBinarySearch") {
|
||||
*value = BlockBasedTableOptions::kBinarySearch;
|
||||
} else if (type == "kHashSearch") {
|
||||
*value = BlockBasedTableOptions::kHashSearch;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerializeEncodingType(
|
||||
const EncodingType& type, std::string* value) {
|
||||
switch (type) {
|
||||
case EncodingType::kPlain:
|
||||
*value = "kPlain";
|
||||
return true;
|
||||
case EncodingType::kPrefix:
|
||||
*value = "kPrefix";
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PraseEncodingType(const std::string& type, EncodingType* value) {
|
||||
if (type == "kPlain") {
|
||||
*value = EncodingType::kPlain;
|
||||
} else if (type == "kPrefix") {
|
||||
*value = EncodingType::kPrefix;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, ChecksumType> checksum_type_map = {
|
||||
{"kNoChecksum", kNoChecksum}, {"kCRC32c", kCRC32c}, {"kxxHash", kxxHash}};
|
||||
|
||||
bool ParseChecksumType(const std::string& type, ChecksumType* value) {
|
||||
auto iter = checksum_type_map.find(type);
|
||||
if (iter != checksum_type_map.end()) {
|
||||
*value = iter->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SerializeChecksumType(const ChecksumType& type, std::string* value) {
|
||||
for (const auto& pair : checksum_type_map) {
|
||||
if (pair.second == type) {
|
||||
*value = pair.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParseBoolean(const std::string& type, const std::string& value) {
|
||||
if (value == "true" || value == "1") {
|
||||
return true;
|
||||
@@ -226,6 +325,28 @@ double ParseDouble(const std::string& value) {
|
||||
return std::strtod(value.c_str(), 0);
|
||||
#endif
|
||||
}
|
||||
static const std::unordered_map<char, std::string>
|
||||
compaction_style_to_string_map = {
|
||||
{kCompactionStyleLevel, "kCompactionStyleLevel"},
|
||||
{kCompactionStyleUniversal, "kCompactionStyleUniversal"},
|
||||
{kCompactionStyleFIFO, "kCompactionStyleFIFO"},
|
||||
{kCompactionStyleNone, "kCompactionStyleNone"}};
|
||||
|
||||
CompactionStyle ParseCompactionStyle(const std::string& type) {
|
||||
for (auto const& entry : compaction_style_to_string_map) {
|
||||
if (entry.second == type) {
|
||||
return static_cast<CompactionStyle>(entry.first);
|
||||
}
|
||||
}
|
||||
throw std::invalid_argument("unknown compaction style: " + type);
|
||||
return kCompactionStyleLevel;
|
||||
}
|
||||
|
||||
std::string CompactionStyleToString(const CompactionStyle style) {
|
||||
auto iter = compaction_style_to_string_map.find(style);
|
||||
assert(iter != compaction_style_to_string_map.end());
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool ParseVectorCompressionType(
|
||||
const std::string& value,
|
||||
@@ -237,16 +358,14 @@ bool ParseVectorCompressionType(
|
||||
bool is_ok;
|
||||
CompressionType type;
|
||||
if (end == std::string::npos) {
|
||||
is_ok = ParseEnum<CompressionType>(compression_type_string_map,
|
||||
value.substr(start), &type);
|
||||
is_ok = ParseCompressionType(value.substr(start), &type);
|
||||
if (!is_ok) {
|
||||
return false;
|
||||
}
|
||||
compression_per_level->emplace_back(type);
|
||||
break;
|
||||
} else {
|
||||
is_ok = ParseEnum<CompressionType>(
|
||||
compression_type_string_map, value.substr(start, end - start), &type);
|
||||
is_ok = ParseCompressionType(value.substr(start, end - start), &type);
|
||||
if (!is_ok) {
|
||||
return false;
|
||||
}
|
||||
@@ -335,13 +454,12 @@ bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
|
||||
*reinterpret_cast<double*>(opt_address) = ParseDouble(value);
|
||||
break;
|
||||
case OptionType::kCompactionStyle:
|
||||
return ParseEnum<CompactionStyle>(
|
||||
compaction_style_string_map, value,
|
||||
reinterpret_cast<CompactionStyle*>(opt_address));
|
||||
*reinterpret_cast<CompactionStyle*>(opt_address) =
|
||||
ParseCompactionStyle(value);
|
||||
break;
|
||||
case OptionType::kCompressionType:
|
||||
return ParseEnum<CompressionType>(
|
||||
compression_type_string_map, value,
|
||||
reinterpret_cast<CompressionType*>(opt_address));
|
||||
return ParseCompressionType(
|
||||
value, reinterpret_cast<CompressionType*>(opt_address));
|
||||
case OptionType::kVectorCompressionType:
|
||||
return ParseVectorCompressionType(
|
||||
value, reinterpret_cast<std::vector<CompressionType>*>(opt_address));
|
||||
@@ -350,16 +468,15 @@ bool ParseOptionHelper(char* opt_address, const OptionType& opt_type,
|
||||
value, reinterpret_cast<std::shared_ptr<const SliceTransform>*>(
|
||||
opt_address));
|
||||
case OptionType::kChecksumType:
|
||||
return ParseEnum<ChecksumType>(
|
||||
checksum_type_string_map, value,
|
||||
reinterpret_cast<ChecksumType*>(opt_address));
|
||||
return ParseChecksumType(value,
|
||||
reinterpret_cast<ChecksumType*>(opt_address));
|
||||
case OptionType::kBlockBasedTableIndexType:
|
||||
return ParseEnum<BlockBasedTableOptions::IndexType>(
|
||||
block_base_table_index_type_string_map, value,
|
||||
return ParseBlockBasedTableIndexType(
|
||||
value,
|
||||
reinterpret_cast<BlockBasedTableOptions::IndexType*>(opt_address));
|
||||
case OptionType::kEncodingType:
|
||||
return ParseEnum<EncodingType>(
|
||||
encoding_type_string_map, value,
|
||||
return PraseEncodingType(
|
||||
value,
|
||||
reinterpret_cast<EncodingType*>(opt_address));
|
||||
default:
|
||||
return false;
|
||||
@@ -401,12 +518,11 @@ bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
*(reinterpret_cast<const std::string*>(opt_address)));
|
||||
break;
|
||||
case OptionType::kCompactionStyle:
|
||||
return SerializeEnum<CompactionStyle>(
|
||||
compaction_style_string_map,
|
||||
*(reinterpret_cast<const CompactionStyle*>(opt_address)), value);
|
||||
*value = CompactionStyleToString(
|
||||
*(reinterpret_cast<const CompactionStyle*>(opt_address)));
|
||||
break;
|
||||
case OptionType::kCompressionType:
|
||||
return SerializeEnum<CompressionType>(
|
||||
compression_type_string_map,
|
||||
return SerializeCompressionType(
|
||||
*(reinterpret_cast<const CompressionType*>(opt_address)), value);
|
||||
case OptionType::kVectorCompressionType:
|
||||
return SerializeVectorCompressionType(
|
||||
@@ -432,16 +548,7 @@ bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
case OptionType::kComparator: {
|
||||
// it's a const pointer of const Comparator*
|
||||
const auto* ptr = reinterpret_cast<const Comparator* const*>(opt_address);
|
||||
// Since the user-specified comparator will be wrapped by
|
||||
// InternalKeyComparator, we should persist the user-specified one
|
||||
// instead of InternalKeyComparator.
|
||||
const auto* internal_comparator =
|
||||
dynamic_cast<const InternalKeyComparator*>(*ptr);
|
||||
if (internal_comparator != nullptr) {
|
||||
*value = internal_comparator->user_comparator()->Name();
|
||||
} else {
|
||||
*value = *ptr ? (*ptr)->Name() : kNullptrString;
|
||||
}
|
||||
*value = *ptr ? (*ptr)->Name() : kNullptrString;
|
||||
break;
|
||||
}
|
||||
case OptionType::kCompactionFilter: {
|
||||
@@ -478,12 +585,10 @@ bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
break;
|
||||
}
|
||||
case OptionType::kChecksumType:
|
||||
return SerializeEnum<ChecksumType>(
|
||||
checksum_type_string_map,
|
||||
return SerializeChecksumType(
|
||||
*reinterpret_cast<const ChecksumType*>(opt_address), value);
|
||||
case OptionType::kBlockBasedTableIndexType:
|
||||
return SerializeEnum<BlockBasedTableOptions::IndexType>(
|
||||
block_base_table_index_type_string_map,
|
||||
return SerializeBlockBasedTableIndexType(
|
||||
*reinterpret_cast<const BlockBasedTableOptions::IndexType*>(
|
||||
opt_address),
|
||||
value);
|
||||
@@ -495,8 +600,7 @@ bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
break;
|
||||
}
|
||||
case OptionType::kEncodingType:
|
||||
return SerializeEnum<EncodingType>(
|
||||
encoding_type_string_map,
|
||||
return SerializeEncodingType(
|
||||
*reinterpret_cast<const EncodingType*>(opt_address), value);
|
||||
default:
|
||||
return false;
|
||||
@@ -700,10 +804,10 @@ Status StringToMap(const std::string& opts_str,
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status ParseColumnFamilyOption(const std::string& name,
|
||||
const std::string& org_value,
|
||||
ColumnFamilyOptions* new_options,
|
||||
bool input_strings_escaped = false) {
|
||||
bool ParseColumnFamilyOption(const std::string& name,
|
||||
const std::string& org_value,
|
||||
ColumnFamilyOptions* new_options,
|
||||
bool input_strings_escaped = false) {
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
try {
|
||||
@@ -728,13 +832,12 @@ Status ParseColumnFamilyOption(const std::string& name,
|
||||
auto block_based_table_factory = dynamic_cast<BlockBasedTableFactory*>(
|
||||
new_options->table_factory.get());
|
||||
if (block_based_table_factory != nullptr) {
|
||||
base_table_options = block_based_table_factory->table_options();
|
||||
base_table_options = block_based_table_factory->GetTableOptions();
|
||||
}
|
||||
Status table_opt_s = GetBlockBasedTableOptionsFromString(
|
||||
base_table_options, value, &table_opt);
|
||||
if (!table_opt_s.ok()) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
return false;
|
||||
}
|
||||
new_options->table_factory.reset(NewBlockBasedTableFactory(table_opt));
|
||||
} else if (name == "plain_table_factory") {
|
||||
@@ -743,80 +846,55 @@ Status ParseColumnFamilyOption(const std::string& name,
|
||||
auto plain_table_factory = dynamic_cast<PlainTableFactory*>(
|
||||
new_options->table_factory.get());
|
||||
if (plain_table_factory != nullptr) {
|
||||
base_table_options = plain_table_factory->table_options();
|
||||
base_table_options = plain_table_factory->GetTableOptions();
|
||||
}
|
||||
Status table_opt_s = GetPlainTableOptionsFromString(
|
||||
base_table_options, value, &table_opt);
|
||||
if (!table_opt_s.ok()) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
return false;
|
||||
}
|
||||
new_options->table_factory.reset(NewPlainTableFactory(table_opt));
|
||||
} else if (name == "memtable") {
|
||||
std::unique_ptr<MemTableRepFactory> new_mem_factory;
|
||||
Status mem_factory_s =
|
||||
GetMemTableRepFactoryFromString(value, &new_mem_factory);
|
||||
if (!mem_factory_s.ok()) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
}
|
||||
new_options->memtable_factory.reset(new_mem_factory.release());
|
||||
} else if (name == "compression_opts") {
|
||||
size_t start = 0;
|
||||
size_t end = value.find(':');
|
||||
if (end == std::string::npos) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
return false;
|
||||
}
|
||||
new_options->compression_opts.window_bits =
|
||||
ParseInt(value.substr(start, end - start));
|
||||
start = end + 1;
|
||||
end = value.find(':', start);
|
||||
if (end == std::string::npos) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
return false;
|
||||
}
|
||||
new_options->compression_opts.level =
|
||||
ParseInt(value.substr(start, end - start));
|
||||
start = end + 1;
|
||||
if (start >= value.size()) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified CF option " + name);
|
||||
return false;
|
||||
}
|
||||
new_options->compression_opts.strategy =
|
||||
ParseInt(value.substr(start, value.size() - start));
|
||||
} else if (name == "compaction_options_universal") {
|
||||
// TODO(ljin): add support
|
||||
return false;
|
||||
} else if (name == "compaction_options_fifo") {
|
||||
new_options->compaction_options_fifo.max_table_files_size =
|
||||
ParseUint64(value);
|
||||
} else {
|
||||
auto iter = cf_options_type_info.find(name);
|
||||
if (iter == cf_options_type_info.end()) {
|
||||
return Status::InvalidArgument(
|
||||
"Unable to parse the specified CF option " + name);
|
||||
return false;
|
||||
}
|
||||
const auto& opt_info = iter->second;
|
||||
if (ParseOptionHelper(
|
||||
reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value)) {
|
||||
return Status::OK();
|
||||
}
|
||||
switch (opt_info.verification) {
|
||||
case OptionVerificationType::kByName:
|
||||
return Status::NotSupported(
|
||||
"Deserializing the specified CF option " + name +
|
||||
" is not supported");
|
||||
case OptionVerificationType::kDeprecated:
|
||||
return Status::OK();
|
||||
default:
|
||||
return Status::InvalidArgument(
|
||||
"Unable to parse the specified CF option " + name);
|
||||
}
|
||||
return ParseOptionHelper(
|
||||
reinterpret_cast<char*>(new_options) + opt_info.offset, opt_info.type,
|
||||
value);
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return Status::InvalidArgument(
|
||||
"unable to parse the specified option " + name);
|
||||
return false;
|
||||
}
|
||||
return Status::OK();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerializeSingleDBOption(std::string* opt_string,
|
||||
@@ -952,17 +1030,15 @@ Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf,
|
||||
const auto* bbtf = dynamic_cast<const BlockBasedTableFactory*>(tf);
|
||||
opts_str->clear();
|
||||
if (bbtf != nullptr) {
|
||||
return GetStringFromBlockBasedTableOptions(opts_str, bbtf->table_options(),
|
||||
delimiter);
|
||||
return GetStringFromBlockBasedTableOptions(
|
||||
opts_str, bbtf->GetTableOptions(), delimiter);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status ParseDBOption(const std::string& name,
|
||||
const std::string& org_value,
|
||||
DBOptions* new_options,
|
||||
bool input_strings_escaped = false) {
|
||||
bool ParseDBOption(const std::string& name, const std::string& org_value,
|
||||
DBOptions* new_options, bool input_strings_escaped = false) {
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
try {
|
||||
@@ -972,30 +1048,20 @@ Status ParseDBOption(const std::string& name,
|
||||
} else {
|
||||
auto iter = db_options_type_info.find(name);
|
||||
if (iter == db_options_type_info.end()) {
|
||||
return Status::InvalidArgument("Unrecognized option DBOptions:", name);
|
||||
return false;
|
||||
}
|
||||
const auto& opt_info = iter->second;
|
||||
if (ParseOptionHelper(
|
||||
reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value)) {
|
||||
return Status::OK();
|
||||
}
|
||||
switch (opt_info.verification) {
|
||||
case OptionVerificationType::kByName:
|
||||
return Status::NotSupported(
|
||||
"Deserializing the specified DB option " + name +
|
||||
" is not supported");
|
||||
case OptionVerificationType::kDeprecated:
|
||||
return Status::OK();
|
||||
default:
|
||||
return Status::InvalidArgument(
|
||||
"Unable to parse the specified DB option " + name);
|
||||
if (opt_info.verification != OptionVerificationType::kByName &&
|
||||
opt_info.verification != OptionVerificationType::kDeprecated) {
|
||||
return ParseOptionHelper(
|
||||
reinterpret_cast<char*>(new_options) + opt_info.offset,
|
||||
opt_info.type, value);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return Status::InvalidArgument("Unable to parse DBOptions:", name);
|
||||
return false;
|
||||
}
|
||||
return Status::OK();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ParseBlockBasedTableOption(const std::string& name,
|
||||
@@ -1049,7 +1115,7 @@ std::string ParsePlainTableOptions(const std::string& name,
|
||||
const std::string& org_value,
|
||||
PlainTableOptions* new_option,
|
||||
bool input_strings_escaped = false) {
|
||||
const std::string& value =
|
||||
const std::string& value =
|
||||
input_strings_escaped ? UnescapeOptionString(org_value) : org_value;
|
||||
const auto iter = plain_table_type_info.find(name);
|
||||
if (iter == plain_table_type_info.end()) {
|
||||
@@ -1135,114 +1201,24 @@ Status GetPlainTableOptionsFromString(
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
return GetPlainTableOptionsFromMap(table_options, opts_map,
|
||||
return GetPlainTableOptionsFromMap(table_options, opts_map,
|
||||
new_table_options);
|
||||
}
|
||||
|
||||
Status GetMemTableRepFactoryFromString(const std::string& opts_str,
|
||||
std::unique_ptr<MemTableRepFactory>* new_mem_factory) {
|
||||
std::vector<std::string> opts_list = StringSplit(opts_str, ':');
|
||||
size_t len = opts_list.size();
|
||||
|
||||
if (opts_list.size() <= 0 || opts_list.size() > 2) {
|
||||
return Status::InvalidArgument("Can't parse memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
|
||||
MemTableRepFactory* mem_factory = nullptr;
|
||||
|
||||
if (opts_list[0] == "skip_list") {
|
||||
// Expecting format
|
||||
// skip_list:<lookahead>
|
||||
if (2 == len) {
|
||||
size_t lookahead = ParseSizeT(opts_list[1]);
|
||||
mem_factory = new SkipListFactory(lookahead);
|
||||
} else if (1 == len) {
|
||||
mem_factory = new SkipListFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "prefix_hash") {
|
||||
// Expecting format
|
||||
// prfix_hash:<hash_bucket_count>
|
||||
if (2 == len) {
|
||||
size_t hash_bucket_count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashSkipListRepFactory(hash_bucket_count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = NewHashSkipListRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "hash_linkedlist") {
|
||||
// Expecting format
|
||||
// hash_linkedlist:<hash_bucket_count>
|
||||
if (2 == len) {
|
||||
size_t hash_bucket_count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = NewHashLinkListRepFactory(hash_bucket_count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = NewHashLinkListRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "vector") {
|
||||
// Expecting format
|
||||
// vector:<count>
|
||||
if (2 == len) {
|
||||
size_t count = ParseSizeT(opts_list[1]);
|
||||
mem_factory = new VectorRepFactory(count);
|
||||
} else if (1 == len) {
|
||||
mem_factory = new VectorRepFactory();
|
||||
}
|
||||
} else if (opts_list[0] == "cuckoo") {
|
||||
// Expecting format
|
||||
// cuckoo:<write_buffer_size>
|
||||
if (2 == len) {
|
||||
size_t write_buffer_size = ParseSizeT(opts_list[1]);
|
||||
mem_factory= NewHashCuckooRepFactory(write_buffer_size);
|
||||
} else if (1 == len) {
|
||||
return Status::InvalidArgument("Can't parse memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
} else {
|
||||
return Status::InvalidArgument("Unrecognized memtable_factory option ",
|
||||
opts_str);
|
||||
}
|
||||
|
||||
if (mem_factory != nullptr){
|
||||
new_mem_factory->reset(mem_factory);
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetColumnFamilyOptionsFromMap(
|
||||
const ColumnFamilyOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
ColumnFamilyOptions* new_options, bool input_strings_escaped) {
|
||||
return GetColumnFamilyOptionsFromMapInternal(
|
||||
base_options, opts_map, new_options, input_strings_escaped);
|
||||
}
|
||||
|
||||
Status GetColumnFamilyOptionsFromMapInternal(
|
||||
const ColumnFamilyOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
ColumnFamilyOptions* new_options, bool input_strings_escaped,
|
||||
std::vector<std::string>* unsupported_options_names) {
|
||||
assert(new_options);
|
||||
*new_options = base_options;
|
||||
if (unsupported_options_names) {
|
||||
unsupported_options_names->clear();
|
||||
}
|
||||
for (const auto& o : opts_map) {
|
||||
auto s = ParseColumnFamilyOption(o.first, o.second, new_options,
|
||||
input_strings_escaped);
|
||||
if (!s.ok()) {
|
||||
if (s.IsNotSupported()) {
|
||||
// If the deserialization of the specified option is not supported
|
||||
// and an output vector of unsupported_options is provided, then
|
||||
// we log the name of the unsupported option and proceed.
|
||||
if (unsupported_options_names != nullptr) {
|
||||
unsupported_options_names->push_back(o.first);
|
||||
}
|
||||
// Note that we still return Status::OK in such case to maintain
|
||||
// the backward compatibility in the old public API defined in
|
||||
// rocksdb/convenience.h
|
||||
} else {
|
||||
return s;
|
||||
if (!ParseColumnFamilyOption(o.first, o.second, new_options,
|
||||
input_strings_escaped)) {
|
||||
auto iter = cf_options_type_info.find(o.first);
|
||||
if (iter == cf_options_type_info.end() ||
|
||||
(iter->second.verification != OptionVerificationType::kByName &&
|
||||
iter->second.verification != OptionVerificationType::kDeprecated)) {
|
||||
return Status::InvalidArgument("Can't parse option " + o.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1265,37 +1241,13 @@ Status GetDBOptionsFromMap(
|
||||
const DBOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
DBOptions* new_options, bool input_strings_escaped) {
|
||||
return GetDBOptionsFromMapInternal(
|
||||
base_options, opts_map, new_options, input_strings_escaped);
|
||||
}
|
||||
|
||||
Status GetDBOptionsFromMapInternal(
|
||||
const DBOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
DBOptions* new_options, bool input_strings_escaped,
|
||||
std::vector<std::string>* unsupported_options_names) {
|
||||
assert(new_options);
|
||||
*new_options = base_options;
|
||||
if (unsupported_options_names) {
|
||||
unsupported_options_names->clear();
|
||||
}
|
||||
for (const auto& o : opts_map) {
|
||||
auto s = ParseDBOption(o.first, o.second,
|
||||
new_options, input_strings_escaped);
|
||||
if (!s.ok()) {
|
||||
if (s.IsNotSupported()) {
|
||||
// If the deserialization of the specified option is not supported
|
||||
// and an output vector of unsupported_options is provided, then
|
||||
// we log the name of the unsupported option and proceed.
|
||||
if (unsupported_options_names != nullptr) {
|
||||
unsupported_options_names->push_back(o.first);
|
||||
}
|
||||
// Note that we still return Status::OK in such case to maintain
|
||||
// the backward compatibility in the old public API defined in
|
||||
// rocksdb/convenience.h
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
if (!ParseDBOption(o.first, o.second, new_options, input_strings_escaped)) {
|
||||
// Note that options with kDeprecated validation will pass ParseDBOption
|
||||
// and will not hit the below statement.
|
||||
return Status::InvalidArgument("Can't parse option " + o.first);
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
@@ -1323,9 +1275,8 @@ Status GetOptionsFromString(const Options& base_options,
|
||||
DBOptions new_db_options(base_options);
|
||||
ColumnFamilyOptions new_cf_options(base_options);
|
||||
for (const auto& o : opts_map) {
|
||||
if (ParseDBOption(o.first, o.second, &new_db_options).ok()) {
|
||||
} else if (ParseColumnFamilyOption(
|
||||
o.first, o.second, &new_cf_options).ok()) {
|
||||
if (ParseDBOption(o.first, o.second, &new_db_options)) {
|
||||
} else if (ParseColumnFamilyOption(o.first, o.second, &new_cf_options)) {
|
||||
} else {
|
||||
return Status::InvalidArgument("Can't parse option " + o.first);
|
||||
}
|
||||
@@ -1350,8 +1301,8 @@ Status GetTableFactoryFromMap(
|
||||
return Status::OK();
|
||||
} else if (factory_name == PlainTableFactory().Name()) {
|
||||
PlainTableOptions pt_opt;
|
||||
s = GetPlainTableOptionsFromMap(PlainTableOptions(), opt_map, &pt_opt,
|
||||
true);
|
||||
s = GetPlainTableOptionsFromMap(PlainTableOptions(), opt_map,
|
||||
&pt_opt, true);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
@@ -1364,71 +1315,5 @@ Status GetTableFactoryFromMap(
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
ColumnFamilyOptions BuildColumnFamilyOptions(
|
||||
const Options& options, const MutableCFOptions& mutable_cf_options) {
|
||||
ColumnFamilyOptions cf_opts(options);
|
||||
|
||||
// Memtable related options
|
||||
cf_opts.write_buffer_size = mutable_cf_options.write_buffer_size;
|
||||
cf_opts.max_write_buffer_number = mutable_cf_options.max_write_buffer_number;
|
||||
cf_opts.arena_block_size = mutable_cf_options.arena_block_size;
|
||||
cf_opts.memtable_prefix_bloom_bits =
|
||||
mutable_cf_options.memtable_prefix_bloom_bits;
|
||||
cf_opts.memtable_prefix_bloom_probes =
|
||||
mutable_cf_options.memtable_prefix_bloom_probes;
|
||||
cf_opts.memtable_prefix_bloom_huge_page_tlb_size =
|
||||
mutable_cf_options.memtable_prefix_bloom_huge_page_tlb_size;
|
||||
cf_opts.max_successive_merges = mutable_cf_options.max_successive_merges;
|
||||
cf_opts.filter_deletes = mutable_cf_options.filter_deletes;
|
||||
cf_opts.inplace_update_num_locks =
|
||||
mutable_cf_options.inplace_update_num_locks;
|
||||
|
||||
// Compaction related options
|
||||
cf_opts.disable_auto_compactions =
|
||||
mutable_cf_options.disable_auto_compactions;
|
||||
cf_opts.soft_rate_limit = mutable_cf_options.soft_rate_limit;
|
||||
cf_opts.level0_file_num_compaction_trigger =
|
||||
mutable_cf_options.level0_file_num_compaction_trigger;
|
||||
cf_opts.level0_slowdown_writes_trigger =
|
||||
mutable_cf_options.level0_slowdown_writes_trigger;
|
||||
cf_opts.level0_stop_writes_trigger =
|
||||
mutable_cf_options.level0_stop_writes_trigger;
|
||||
cf_opts.max_grandparent_overlap_factor =
|
||||
mutable_cf_options.max_grandparent_overlap_factor;
|
||||
cf_opts.expanded_compaction_factor =
|
||||
mutable_cf_options.expanded_compaction_factor;
|
||||
cf_opts.source_compaction_factor =
|
||||
mutable_cf_options.source_compaction_factor;
|
||||
cf_opts.target_file_size_base = mutable_cf_options.target_file_size_base;
|
||||
cf_opts.target_file_size_multiplier =
|
||||
mutable_cf_options.target_file_size_multiplier;
|
||||
cf_opts.max_bytes_for_level_base =
|
||||
mutable_cf_options.max_bytes_for_level_base;
|
||||
cf_opts.max_bytes_for_level_multiplier =
|
||||
mutable_cf_options.max_bytes_for_level_multiplier;
|
||||
|
||||
cf_opts.max_bytes_for_level_multiplier_additional.clear();
|
||||
for (auto value :
|
||||
mutable_cf_options.max_bytes_for_level_multiplier_additional) {
|
||||
cf_opts.max_bytes_for_level_multiplier_additional.emplace_back(value);
|
||||
}
|
||||
|
||||
cf_opts.verify_checksums_in_compaction =
|
||||
mutable_cf_options.verify_checksums_in_compaction;
|
||||
|
||||
// Misc options
|
||||
cf_opts.max_sequential_skip_in_iterations =
|
||||
mutable_cf_options.max_sequential_skip_in_iterations;
|
||||
cf_opts.paranoid_file_checks = mutable_cf_options.paranoid_file_checks;
|
||||
cf_opts.compaction_measure_io_stats =
|
||||
mutable_cf_options.compaction_measure_io_stats;
|
||||
|
||||
cf_opts.table_factory = options.table_factory;
|
||||
// TODO(yhchiang): find some way to handle the following derived options
|
||||
// * max_file_size
|
||||
|
||||
return cf_opts;
|
||||
}
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
} // namespace rocksdb
|
||||
|
||||
+26
-76
@@ -7,8 +7,6 @@
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/table.h"
|
||||
@@ -66,9 +64,6 @@ Status GetTableFactoryFromMap(
|
||||
Status GetStringFromTableFactory(std::string* opts_str, const TableFactory* tf,
|
||||
const std::string& delimiter = "; ");
|
||||
|
||||
ColumnFamilyOptions BuildColumnFamilyOptions(
|
||||
const Options& options, const MutableCFOptions& mutable_cf_options);
|
||||
|
||||
enum class OptionType {
|
||||
kBoolean,
|
||||
kInt,
|
||||
@@ -120,24 +115,6 @@ struct OptionTypeInfo {
|
||||
bool SerializeSingleOptionHelper(const char* opt_address,
|
||||
const OptionType opt_type, std::string* value);
|
||||
|
||||
// In addition to its public version defined in rocksdb/convenience.h,
|
||||
// this further takes an optional output vector "unsupported_options_names",
|
||||
// which stores the name of all the unsupported options specified in "opts_map".
|
||||
Status GetDBOptionsFromMapInternal(
|
||||
const DBOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
DBOptions* new_options, bool input_strings_escaped,
|
||||
std::vector<std::string>* unsupported_options_names = nullptr);
|
||||
|
||||
// In addition to its public version defined in rocksdb/convenience.h,
|
||||
// this further takes an optional output vector "unsupported_options_names",
|
||||
// which stores the name of all the unsupported options specified in "opts_map".
|
||||
Status GetColumnFamilyOptionsFromMapInternal(
|
||||
const ColumnFamilyOptions& base_options,
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
ColumnFamilyOptions* new_options, bool input_strings_escaped,
|
||||
std::vector<std::string>* unsupported_options_names = nullptr);
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> db_options_type_info = {
|
||||
/*
|
||||
// not yet supported
|
||||
@@ -493,59 +470,32 @@ static std::unordered_map<std::string,
|
||||
{offsetof(struct BlockBasedTableOptions, format_version),
|
||||
OptionType::kUInt32T, OptionVerificationType::kNormal}}};
|
||||
|
||||
static std::unordered_map<std::string, OptionTypeInfo> plain_table_type_info = {
|
||||
{"user_key_len",
|
||||
{offsetof(struct PlainTableOptions, user_key_len), OptionType::kUInt32T,
|
||||
OptionVerificationType::kNormal}},
|
||||
{"bloom_bits_per_key",
|
||||
{offsetof(struct PlainTableOptions, bloom_bits_per_key), OptionType::kInt,
|
||||
OptionVerificationType::kNormal}},
|
||||
{"hash_table_ratio",
|
||||
{offsetof(struct PlainTableOptions, hash_table_ratio), OptionType::kDouble,
|
||||
OptionVerificationType::kNormal}},
|
||||
{"index_sparseness",
|
||||
{offsetof(struct PlainTableOptions, index_sparseness), OptionType::kSizeT,
|
||||
OptionVerificationType::kNormal}},
|
||||
{"huge_page_tlb_size",
|
||||
{offsetof(struct PlainTableOptions, huge_page_tlb_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal}},
|
||||
{"encoding_type",
|
||||
{offsetof(struct PlainTableOptions, encoding_type),
|
||||
OptionType::kEncodingType, OptionVerificationType::kByName}},
|
||||
{"full_scan_mode",
|
||||
{offsetof(struct PlainTableOptions, full_scan_mode), OptionType::kBoolean,
|
||||
OptionVerificationType::kNormal}},
|
||||
{"store_index_in_file",
|
||||
{offsetof(struct PlainTableOptions, store_index_in_file),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal}}};
|
||||
|
||||
static std::unordered_map<std::string, CompressionType>
|
||||
compression_type_string_map = {
|
||||
{"kNoCompression", kNoCompression},
|
||||
{"kSnappyCompression", kSnappyCompression},
|
||||
{"kZlibCompression", kZlibCompression},
|
||||
{"kBZip2Compression", kBZip2Compression},
|
||||
{"kLZ4Compression", kLZ4Compression},
|
||||
{"kLZ4HCCompression", kLZ4HCCompression},
|
||||
{"kZSTDNotFinalCompression", kZSTDNotFinalCompression}};
|
||||
|
||||
static std::unordered_map<std::string, BlockBasedTableOptions::IndexType>
|
||||
block_base_table_index_type_string_map = {
|
||||
{"kBinarySearch", BlockBasedTableOptions::IndexType::kBinarySearch},
|
||||
{"kHashSearch", BlockBasedTableOptions::IndexType::kHashSearch}};
|
||||
|
||||
static std::unordered_map<std::string, EncodingType> encoding_type_string_map =
|
||||
{{"kPlain", kPlain}, {"kPrefix", kPrefix}};
|
||||
|
||||
static std::unordered_map<std::string, ChecksumType> checksum_type_string_map =
|
||||
{{"kNoChecksum", kNoChecksum}, {"kCRC32c", kCRC32c}, {"kxxHash", kxxHash}};
|
||||
|
||||
static std::unordered_map<std::string, CompactionStyle>
|
||||
compaction_style_string_map = {
|
||||
{"kCompactionStyleLevel", kCompactionStyleLevel},
|
||||
{"kCompactionStyleUniversal", kCompactionStyleUniversal},
|
||||
{"kCompactionStyleFIFO", kCompactionStyleFIFO},
|
||||
{"kCompactionStyleNone", kCompactionStyleNone}};
|
||||
static std::unordered_map<std::string,
|
||||
OptionTypeInfo> plain_table_type_info = {
|
||||
{"user_key_len",
|
||||
{offsetof(struct PlainTableOptions, user_key_len),
|
||||
OptionType::kUInt32T, OptionVerificationType::kNormal}},
|
||||
{"bloom_bits_per_key",
|
||||
{offsetof(struct PlainTableOptions, bloom_bits_per_key),
|
||||
OptionType::kInt, OptionVerificationType::kNormal}},
|
||||
{"hash_table_ratio",
|
||||
{offsetof(struct PlainTableOptions, hash_table_ratio),
|
||||
OptionType::kDouble, OptionVerificationType::kNormal}},
|
||||
{"index_sparseness",
|
||||
{offsetof(struct PlainTableOptions, index_sparseness),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal}},
|
||||
{"huge_page_tlb_size",
|
||||
{offsetof(struct PlainTableOptions, huge_page_tlb_size),
|
||||
OptionType::kSizeT, OptionVerificationType::kNormal}},
|
||||
{"encoding_type",
|
||||
{offsetof(struct PlainTableOptions, encoding_type),
|
||||
OptionType::kEncodingType, OptionVerificationType::kByName}},
|
||||
{"full_scan_mode",
|
||||
{offsetof(struct PlainTableOptions, full_scan_mode),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal}},
|
||||
{"store_index_in_file",
|
||||
{offsetof(struct PlainTableOptions, store_index_in_file),
|
||||
OptionType::kBoolean, OptionVerificationType::kNormal}}};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "rocksdb/db.h"
|
||||
#include "util/options_helper.h"
|
||||
#include "util/string_util.h"
|
||||
#include "util/sync_point.h"
|
||||
|
||||
#include "port/port.h"
|
||||
|
||||
@@ -35,7 +34,6 @@ Status PersistRocksDBOptions(const DBOptions& db_opt,
|
||||
const std::vector<std::string>& cf_names,
|
||||
const std::vector<ColumnFamilyOptions>& cf_opts,
|
||||
const std::string& file_name, Env* env) {
|
||||
TEST_SYNC_POINT("PersistRocksDBOptions:start");
|
||||
if (cf_names.size() != cf_opts.size()) {
|
||||
return Status::InvalidArgument(
|
||||
"cf_names.size() and cf_opts.size() must be the same");
|
||||
@@ -740,8 +738,8 @@ Status RocksDBOptionsParser::VerifyBlockBasedTableFactory(
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
const auto& base_opt = base_tf->table_options();
|
||||
const auto& file_opt = file_tf->table_options();
|
||||
const auto& base_opt = base_tf->GetTableOptions();
|
||||
const auto& file_opt = file_tf->GetTableOptions();
|
||||
|
||||
for (auto& pair : block_based_table_type_info) {
|
||||
if (pair.second.verification == OptionVerificationType::kDeprecated) {
|
||||
|
||||
@@ -80,9 +80,9 @@ class RocksDBOptionsParser {
|
||||
const std::unordered_map<std::string, std::string>* new_opt_map = nullptr,
|
||||
OptionsSanityCheckLevel sanity_check_level = kSanityLevelExactMatch);
|
||||
|
||||
static Status VerifyTableFactory(
|
||||
const TableFactory* base_tf, const TableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level = kSanityLevelExactMatch);
|
||||
static Status VerifyTableFactory(const TableFactory* base_tf,
|
||||
const TableFactory* file_tf,
|
||||
OptionsSanityCheckLevel sanity_check_level);
|
||||
|
||||
static Status VerifyBlockBasedTableFactory(
|
||||
const BlockBasedTableFactory* base_tf,
|
||||
|
||||
+439
-66
@@ -16,9 +16,14 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/compaction_filter.h"
|
||||
#include "rocksdb/convenience.h"
|
||||
#include "rocksdb/memtablerep.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/table.h"
|
||||
#include "rocksdb/utilities/leveldb_options.h"
|
||||
#include "table/block_based_table_factory.h"
|
||||
#include "table/plain_table_factory.h"
|
||||
#include "util/options_helper.h"
|
||||
#include "util/options_parser.h"
|
||||
#include "util/options_sanity_check.h"
|
||||
@@ -70,6 +75,163 @@ Options PrintAndGetOptions(size_t total_write_buffer_limit,
|
||||
return options;
|
||||
}
|
||||
|
||||
class StringEnv : public EnvWrapper {
|
||||
public:
|
||||
class SeqStringSource : public SequentialFile {
|
||||
public:
|
||||
explicit SeqStringSource(const std::string& data)
|
||||
: data_(data), offset_(0) {}
|
||||
~SeqStringSource() {}
|
||||
Status Read(size_t n, Slice* result, char* scratch) override {
|
||||
std::string output;
|
||||
if (offset_ < data_.size()) {
|
||||
n = std::min(data_.size() - offset_, n);
|
||||
memcpy(scratch, data_.data() + offset_, n);
|
||||
offset_ += n;
|
||||
*result = Slice(scratch, n);
|
||||
} else {
|
||||
return Status::InvalidArgument(
|
||||
"Attemp to read when it already reached eof.");
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status Skip(uint64_t n) override {
|
||||
if (offset_ >= data_.size()) {
|
||||
return Status::InvalidArgument(
|
||||
"Attemp to read when it already reached eof.");
|
||||
}
|
||||
// TODO(yhchiang): Currently doesn't handle the overflow case.
|
||||
offset_ += n;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string data_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
||||
class StringSink : public WritableFile {
|
||||
public:
|
||||
explicit StringSink(std::string* contents)
|
||||
: WritableFile(), contents_(contents) {}
|
||||
virtual Status Truncate(uint64_t size) override {
|
||||
contents_->resize(size);
|
||||
return Status::OK();
|
||||
}
|
||||
virtual Status Close() override { return Status::OK(); }
|
||||
virtual Status Flush() override { return Status::OK(); }
|
||||
virtual Status Sync() override { return Status::OK(); }
|
||||
virtual Status Append(const Slice& slice) override {
|
||||
contents_->append(slice.data(), slice.size());
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* contents_;
|
||||
};
|
||||
|
||||
explicit StringEnv(Env* t) : EnvWrapper(t) {}
|
||||
virtual ~StringEnv() {}
|
||||
|
||||
const std::string& GetContent(const std::string& f) { return files_[f]; }
|
||||
|
||||
const Status WriteToNewFile(const std::string& file_name,
|
||||
const std::string& content) {
|
||||
unique_ptr<WritableFile> r;
|
||||
auto s = NewWritableFile(file_name, &r, EnvOptions());
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
r->Append(content);
|
||||
r->Flush();
|
||||
r->Close();
|
||||
assert(files_[file_name] == content);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
// The following text is boilerplate that forwards all methods to target()
|
||||
Status NewSequentialFile(const std::string& f, unique_ptr<SequentialFile>* r,
|
||||
const EnvOptions& options) override {
|
||||
auto iter = files_.find(f);
|
||||
if (iter == files_.end()) {
|
||||
return Status::NotFound("The specified file does not exist", f);
|
||||
}
|
||||
r->reset(new SeqStringSource(iter->second));
|
||||
return Status::OK();
|
||||
}
|
||||
Status NewRandomAccessFile(const std::string& f,
|
||||
unique_ptr<RandomAccessFile>* r,
|
||||
const EnvOptions& options) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
Status NewWritableFile(const std::string& f, unique_ptr<WritableFile>* r,
|
||||
const EnvOptions& options) override {
|
||||
auto iter = files_.find(f);
|
||||
if (iter != files_.end()) {
|
||||
return Status::IOError("The specified file already exists", f);
|
||||
}
|
||||
r->reset(new StringSink(&files_[f]));
|
||||
return Status::OK();
|
||||
}
|
||||
virtual Status NewDirectory(const std::string& name,
|
||||
unique_ptr<Directory>* result) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
Status FileExists(const std::string& f) override {
|
||||
if (files_.find(f) == files_.end()) {
|
||||
return Status::NotFound();
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
Status GetChildren(const std::string& dir,
|
||||
std::vector<std::string>* r) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
Status DeleteFile(const std::string& f) override {
|
||||
files_.erase(f);
|
||||
return Status::OK();
|
||||
}
|
||||
Status CreateDir(const std::string& d) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
Status CreateDirIfMissing(const std::string& d) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
Status DeleteDir(const std::string& d) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
Status GetFileSize(const std::string& f, uint64_t* s) override {
|
||||
auto iter = files_.find(f);
|
||||
if (iter == files_.end()) {
|
||||
return Status::NotFound("The specified file does not exist:", f);
|
||||
}
|
||||
*s = iter->second.size();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetFileModificationTime(const std::string& fname,
|
||||
uint64_t* file_mtime) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
Status RenameFile(const std::string& s, const std::string& t) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
Status LinkFile(const std::string& s, const std::string& t) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
Status LockFile(const std::string& f, FileLock** l) override {
|
||||
return Status::NotSupported();
|
||||
}
|
||||
|
||||
Status UnlockFile(FileLock* l) override { return Status::NotSupported(); }
|
||||
|
||||
protected:
|
||||
std::unordered_map<std::string, std::string> files_;
|
||||
};
|
||||
|
||||
class OptionsTest : public testing::Test {};
|
||||
|
||||
TEST_F(OptionsTest, LooseCondition) {
|
||||
@@ -449,14 +611,6 @@ TEST_F(OptionsTest, GetColumnFamilyOptionsFromStringTest) {
|
||||
&new_cf_opt));
|
||||
ASSERT_TRUE(new_cf_opt.table_factory != nullptr);
|
||||
ASSERT_EQ(std::string(new_cf_opt.table_factory->Name()), "PlainTable");
|
||||
|
||||
// memtable factory
|
||||
ASSERT_OK(GetColumnFamilyOptionsFromString(base_cf_opt,
|
||||
"write_buffer_size=10;max_write_buffer_number=16;"
|
||||
"memtable=skip_list:10;arena_block_size=1024",
|
||||
&new_cf_opt));
|
||||
ASSERT_TRUE(new_cf_opt.memtable_factory != nullptr);
|
||||
ASSERT_EQ(std::string(new_cf_opt.memtable_factory->Name()), "SkipListFactory");
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -547,46 +701,7 @@ TEST_F(OptionsTest, GetPlainTableOptionsFromString) {
|
||||
ASSERT_NOK(GetPlainTableOptionsFromString(table_opt,
|
||||
"user_key_len=66;bloom_bits_per_key=20;hash_table_ratio=0.5;"
|
||||
"encoding_type=kPrefixXX",
|
||||
&new_opt));
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
#ifndef ROCKSDB_LITE // GetMemTableRepFactoryFromString is not supported
|
||||
TEST_F(OptionsTest, GetMemTableRepFactoryFromString) {
|
||||
std::unique_ptr<MemTableRepFactory> new_mem_factory = nullptr;
|
||||
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("skip_list", &new_mem_factory));
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("skip_list:16", &new_mem_factory));
|
||||
ASSERT_EQ(std::string(new_mem_factory->Name()), "SkipListFactory");
|
||||
ASSERT_NOK(GetMemTableRepFactoryFromString("skip_list:16:invalid_opt",
|
||||
&new_mem_factory));
|
||||
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash", &new_mem_factory));
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("prefix_hash:1000",
|
||||
&new_mem_factory));
|
||||
ASSERT_EQ(std::string(new_mem_factory->Name()), "HashSkipListRepFactory");
|
||||
ASSERT_NOK(GetMemTableRepFactoryFromString("prefix_hash:1000:invalid_opt",
|
||||
&new_mem_factory));
|
||||
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist",
|
||||
&new_mem_factory));
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("hash_linkedlist:1000",
|
||||
&new_mem_factory));
|
||||
ASSERT_EQ(std::string(new_mem_factory->Name()), "HashLinkListRepFactory");
|
||||
ASSERT_NOK(GetMemTableRepFactoryFromString("hash_linkedlist:1000:invalid_opt",
|
||||
&new_mem_factory));
|
||||
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("vector", &new_mem_factory));
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("vector:1024", &new_mem_factory));
|
||||
ASSERT_EQ(std::string(new_mem_factory->Name()), "VectorRepFactory");
|
||||
ASSERT_NOK(GetMemTableRepFactoryFromString("vector:1024:invalid_opt",
|
||||
&new_mem_factory));
|
||||
|
||||
ASSERT_NOK(GetMemTableRepFactoryFromString("cuckoo", &new_mem_factory));
|
||||
ASSERT_OK(GetMemTableRepFactoryFromString("cuckoo:1024", &new_mem_factory));
|
||||
ASSERT_EQ(std::string(new_mem_factory->Name()), "HashCuckooRepFactory");
|
||||
|
||||
ASSERT_NOK(GetMemTableRepFactoryFromString("bad_factory", &new_mem_factory));
|
||||
&new_opt));
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
@@ -610,7 +725,7 @@ TEST_F(OptionsTest, GetOptionsFromStringTest) {
|
||||
ASSERT_EQ(new_options.max_write_buffer_number, 16);
|
||||
BlockBasedTableOptions new_block_based_table_options =
|
||||
dynamic_cast<BlockBasedTableFactory*>(new_options.table_factory.get())
|
||||
->table_options();
|
||||
->GetTableOptions();
|
||||
ASSERT_EQ(new_block_based_table_options.block_cache->GetCapacity(), 1U << 20);
|
||||
ASSERT_EQ(new_block_based_table_options.block_size, 4U);
|
||||
// don't overwrite block based table options
|
||||
@@ -621,12 +736,70 @@ TEST_F(OptionsTest, GetOptionsFromStringTest) {
|
||||
ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void RandomInitDBOptions(DBOptions* db_opt, Random* rnd) {
|
||||
// boolean options
|
||||
db_opt->advise_random_on_open = rnd->Uniform(2);
|
||||
db_opt->allow_mmap_reads = rnd->Uniform(2);
|
||||
db_opt->allow_mmap_writes = rnd->Uniform(2);
|
||||
db_opt->allow_os_buffer = rnd->Uniform(2);
|
||||
db_opt->create_if_missing = rnd->Uniform(2);
|
||||
db_opt->create_missing_column_families = rnd->Uniform(2);
|
||||
db_opt->disableDataSync = rnd->Uniform(2);
|
||||
db_opt->enable_thread_tracking = rnd->Uniform(2);
|
||||
db_opt->error_if_exists = rnd->Uniform(2);
|
||||
db_opt->is_fd_close_on_exec = rnd->Uniform(2);
|
||||
db_opt->paranoid_checks = rnd->Uniform(2);
|
||||
db_opt->skip_log_error_on_recovery = rnd->Uniform(2);
|
||||
db_opt->skip_stats_update_on_db_open = rnd->Uniform(2);
|
||||
db_opt->use_adaptive_mutex = rnd->Uniform(2);
|
||||
db_opt->use_fsync = rnd->Uniform(2);
|
||||
db_opt->recycle_log_file_num = rnd->Uniform(2);
|
||||
|
||||
// int options
|
||||
db_opt->max_background_compactions = rnd->Uniform(100);
|
||||
db_opt->max_background_flushes = rnd->Uniform(100);
|
||||
db_opt->max_file_opening_threads = rnd->Uniform(100);
|
||||
db_opt->max_open_files = rnd->Uniform(100);
|
||||
db_opt->table_cache_numshardbits = rnd->Uniform(100);
|
||||
|
||||
// size_t options
|
||||
db_opt->db_write_buffer_size = rnd->Uniform(10000);
|
||||
db_opt->keep_log_file_num = rnd->Uniform(10000);
|
||||
db_opt->log_file_time_to_roll = rnd->Uniform(10000);
|
||||
db_opt->manifest_preallocation_size = rnd->Uniform(10000);
|
||||
db_opt->max_log_file_size = rnd->Uniform(10000);
|
||||
|
||||
// std::string options
|
||||
db_opt->db_log_dir = "path/to/db_log_dir";
|
||||
db_opt->wal_dir = "path/to/wal_dir";
|
||||
|
||||
// uint32_t options
|
||||
db_opt->max_subcompactions = rnd->Uniform(100000);
|
||||
|
||||
// uint64_t options
|
||||
static const uint64_t uint_max = static_cast<uint64_t>(UINT_MAX);
|
||||
db_opt->WAL_size_limit_MB = uint_max + rnd->Uniform(100000);
|
||||
db_opt->WAL_ttl_seconds = uint_max + rnd->Uniform(100000);
|
||||
db_opt->bytes_per_sync = uint_max + rnd->Uniform(100000);
|
||||
db_opt->delayed_write_rate = uint_max + rnd->Uniform(100000);
|
||||
db_opt->delete_obsolete_files_period_micros = uint_max + rnd->Uniform(100000);
|
||||
db_opt->max_manifest_file_size = uint_max + rnd->Uniform(100000);
|
||||
db_opt->max_total_wal_size = uint_max + rnd->Uniform(100000);
|
||||
db_opt->wal_bytes_per_sync = uint_max + rnd->Uniform(100000);
|
||||
|
||||
// unsigned int options
|
||||
db_opt->stats_dump_period_sec = rnd->Uniform(100000);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(OptionsTest, DBOptionsSerialization) {
|
||||
Options base_options, new_options;
|
||||
Random rnd(301);
|
||||
|
||||
// Phase 1: Make big change in base_options
|
||||
test::RandomInitDBOptions(&base_options, &rnd);
|
||||
RandomInitDBOptions(&base_options, &rnd);
|
||||
|
||||
// Phase 2: obtain a string from base_option
|
||||
std::string base_options_file_content;
|
||||
@@ -639,12 +812,212 @@ TEST_F(OptionsTest, DBOptionsSerialization) {
|
||||
ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(base_options, new_options));
|
||||
}
|
||||
|
||||
namespace {
|
||||
CompressionType RandomCompressionType(Random* rnd) {
|
||||
return static_cast<CompressionType>(rnd->Uniform(6));
|
||||
}
|
||||
|
||||
void RandomCompressionTypeVector(const size_t count,
|
||||
std::vector<CompressionType>* types,
|
||||
Random* rnd) {
|
||||
types->clear();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
types->emplace_back(RandomCompressionType(rnd));
|
||||
}
|
||||
}
|
||||
|
||||
const SliceTransform* RandomSliceTransform(Random* rnd, int pre_defined = -1) {
|
||||
int random_num = pre_defined >= 0 ? pre_defined : rnd->Uniform(4);
|
||||
switch (random_num) {
|
||||
case 0:
|
||||
return NewFixedPrefixTransform(rnd->Uniform(20) + 1);
|
||||
case 1:
|
||||
return NewCappedPrefixTransform(rnd->Uniform(20) + 1);
|
||||
case 2:
|
||||
return NewNoopTransform();
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TableFactory* RandomTableFactory(Random* rnd, int pre_defined = -1) {
|
||||
int random_num = pre_defined >= 0 ? pre_defined : rnd->Uniform(3);
|
||||
switch (random_num) {
|
||||
case 0:
|
||||
return NewPlainTableFactory();
|
||||
case 1:
|
||||
return NewCuckooTableFactory();
|
||||
default:
|
||||
return NewBlockBasedTableFactory();
|
||||
}
|
||||
}
|
||||
|
||||
std::string RandomString(Random* rnd, const size_t len) {
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
ss << static_cast<char>(rnd->Uniform(26) + 'a');
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
class ChanglingMergeOperator : public MergeOperator {
|
||||
public:
|
||||
explicit ChanglingMergeOperator(const std::string& name)
|
||||
: name_(name + "MergeOperator") {}
|
||||
~ChanglingMergeOperator() {}
|
||||
|
||||
void SetName(const std::string& name) { name_ = name; }
|
||||
|
||||
virtual bool FullMerge(const Slice& key, const Slice* existing_value,
|
||||
const std::deque<std::string>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* logger) const override {
|
||||
return false;
|
||||
}
|
||||
virtual bool PartialMergeMulti(const Slice& key,
|
||||
const std::deque<Slice>& operand_list,
|
||||
std::string* new_value,
|
||||
Logger* logger) const override {
|
||||
return false;
|
||||
}
|
||||
virtual const char* Name() const override { return name_.c_str(); }
|
||||
|
||||
protected:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
MergeOperator* RandomMergeOperator(Random* rnd) {
|
||||
return new ChanglingMergeOperator(RandomString(rnd, 10));
|
||||
}
|
||||
|
||||
class ChanglingCompactionFilter : public CompactionFilter {
|
||||
public:
|
||||
explicit ChanglingCompactionFilter(const std::string& name)
|
||||
: name_(name + "CompactionFilter") {}
|
||||
~ChanglingCompactionFilter() {}
|
||||
|
||||
void SetName(const std::string& name) { name_ = name; }
|
||||
|
||||
bool Filter(int level, const Slice& key, const Slice& existing_value,
|
||||
std::string* new_value, bool* value_changed) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* Name() const override { return name_.c_str(); }
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
CompactionFilter* RandomCompactionFilter(Random* rnd) {
|
||||
return new ChanglingCompactionFilter(RandomString(rnd, 10));
|
||||
}
|
||||
|
||||
class ChanglingCompactionFilterFactory : public CompactionFilterFactory {
|
||||
public:
|
||||
explicit ChanglingCompactionFilterFactory(const std::string& name)
|
||||
: name_(name + "CompactionFilterFactory") {}
|
||||
~ChanglingCompactionFilterFactory() {}
|
||||
|
||||
void SetName(const std::string& name) { name_ = name; }
|
||||
|
||||
std::unique_ptr<CompactionFilter> CreateCompactionFilter(
|
||||
const CompactionFilter::Context& context) override {
|
||||
return std::unique_ptr<CompactionFilter>();
|
||||
}
|
||||
|
||||
// Returns a name that identifies this compaction filter factory.
|
||||
const char* Name() const override { return name_.c_str(); }
|
||||
|
||||
protected:
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
CompactionFilterFactory* RandomCompactionFilterFactory(Random* rnd) {
|
||||
return new ChanglingCompactionFilterFactory(RandomString(rnd, 10));
|
||||
}
|
||||
|
||||
// Note that the caller is responsible for releasing non-null
|
||||
// cf_opt->compaction_filter.
|
||||
void RandomInitCFOptions(ColumnFamilyOptions* cf_opt, Random* rnd) {
|
||||
cf_opt->compaction_style = (CompactionStyle)(rnd->Uniform(4));
|
||||
|
||||
// boolean options
|
||||
cf_opt->compaction_measure_io_stats = rnd->Uniform(2);
|
||||
cf_opt->disable_auto_compactions = rnd->Uniform(2);
|
||||
cf_opt->filter_deletes = rnd->Uniform(2);
|
||||
cf_opt->inplace_update_support = rnd->Uniform(2);
|
||||
cf_opt->level_compaction_dynamic_level_bytes = rnd->Uniform(2);
|
||||
cf_opt->optimize_filters_for_hits = rnd->Uniform(2);
|
||||
cf_opt->paranoid_file_checks = rnd->Uniform(2);
|
||||
cf_opt->purge_redundant_kvs_while_flush = rnd->Uniform(2);
|
||||
cf_opt->verify_checksums_in_compaction = rnd->Uniform(2);
|
||||
|
||||
// double options
|
||||
cf_opt->hard_rate_limit = static_cast<double>(rnd->Uniform(10000)) / 13;
|
||||
cf_opt->soft_rate_limit = static_cast<double>(rnd->Uniform(10000)) / 13;
|
||||
|
||||
// int options
|
||||
cf_opt->expanded_compaction_factor = rnd->Uniform(100);
|
||||
cf_opt->level0_file_num_compaction_trigger = rnd->Uniform(100);
|
||||
cf_opt->level0_slowdown_writes_trigger = rnd->Uniform(100);
|
||||
cf_opt->level0_stop_writes_trigger = rnd->Uniform(100);
|
||||
cf_opt->max_bytes_for_level_multiplier = rnd->Uniform(100);
|
||||
cf_opt->max_grandparent_overlap_factor = rnd->Uniform(100);
|
||||
cf_opt->max_mem_compaction_level = rnd->Uniform(100);
|
||||
cf_opt->max_write_buffer_number = rnd->Uniform(100);
|
||||
cf_opt->max_write_buffer_number_to_maintain = rnd->Uniform(100);
|
||||
cf_opt->min_write_buffer_number_to_merge = rnd->Uniform(100);
|
||||
cf_opt->num_levels = rnd->Uniform(100);
|
||||
cf_opt->source_compaction_factor = rnd->Uniform(100);
|
||||
cf_opt->target_file_size_multiplier = rnd->Uniform(100);
|
||||
|
||||
// size_t options
|
||||
cf_opt->arena_block_size = rnd->Uniform(10000);
|
||||
cf_opt->inplace_update_num_locks = rnd->Uniform(10000);
|
||||
cf_opt->max_successive_merges = rnd->Uniform(10000);
|
||||
cf_opt->memtable_prefix_bloom_huge_page_tlb_size = rnd->Uniform(10000);
|
||||
cf_opt->write_buffer_size = rnd->Uniform(10000);
|
||||
|
||||
// uint32_t options
|
||||
cf_opt->bloom_locality = rnd->Uniform(10000);
|
||||
cf_opt->memtable_prefix_bloom_bits = rnd->Uniform(10000);
|
||||
cf_opt->memtable_prefix_bloom_probes = rnd->Uniform(10000);
|
||||
cf_opt->min_partial_merge_operands = rnd->Uniform(10000);
|
||||
cf_opt->max_bytes_for_level_base = rnd->Uniform(10000);
|
||||
|
||||
// uint64_t options
|
||||
static const uint64_t uint_max = static_cast<uint64_t>(UINT_MAX);
|
||||
cf_opt->max_sequential_skip_in_iterations = uint_max + rnd->Uniform(10000);
|
||||
cf_opt->target_file_size_base = uint_max + rnd->Uniform(10000);
|
||||
|
||||
// unsigned int options
|
||||
cf_opt->rate_limit_delay_max_milliseconds = rnd->Uniform(10000);
|
||||
|
||||
// pointer typed options
|
||||
cf_opt->prefix_extractor.reset(RandomSliceTransform(rnd));
|
||||
cf_opt->table_factory.reset(RandomTableFactory(rnd));
|
||||
cf_opt->merge_operator.reset(RandomMergeOperator(rnd));
|
||||
if (cf_opt->compaction_filter) {
|
||||
delete cf_opt->compaction_filter;
|
||||
}
|
||||
cf_opt->compaction_filter = RandomCompactionFilter(rnd);
|
||||
cf_opt->compaction_filter_factory.reset(RandomCompactionFilterFactory(rnd));
|
||||
|
||||
// custom typed options
|
||||
cf_opt->compression = RandomCompressionType(rnd);
|
||||
RandomCompressionTypeVector(cf_opt->num_levels,
|
||||
&cf_opt->compression_per_level, rnd);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(OptionsTest, ColumnFamilyOptionsSerialization) {
|
||||
ColumnFamilyOptions base_opt, new_opt;
|
||||
Random rnd(302);
|
||||
// Phase 1: randomly assign base_opt
|
||||
// custom type options
|
||||
test::RandomInitCFOptions(&base_opt, &rnd);
|
||||
RandomInitCFOptions(&base_opt, &rnd);
|
||||
|
||||
// Phase 2: obtain a string from base_opt
|
||||
std::string base_options_file_content;
|
||||
@@ -663,6 +1036,7 @@ TEST_F(OptionsTest, ColumnFamilyOptionsSerialization) {
|
||||
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
|
||||
Status StringToMap(
|
||||
const std::string& opts_str,
|
||||
std::unordered_map<std::string, std::string>* opts_map);
|
||||
@@ -852,7 +1226,7 @@ TEST_F(OptionsTest, ConvertOptionsTest) {
|
||||
|
||||
ASSERT_TRUE(table_factory.get() != nullptr);
|
||||
|
||||
const BlockBasedTableOptions table_opt = table_factory->table_options();
|
||||
const BlockBasedTableOptions table_opt = table_factory->GetTableOptions();
|
||||
|
||||
ASSERT_EQ(table_opt.block_cache->GetCapacity(), 8UL << 20);
|
||||
ASSERT_EQ(table_opt.block_size, leveldb_opt.block_size);
|
||||
@@ -864,10 +1238,10 @@ TEST_F(OptionsTest, ConvertOptionsTest) {
|
||||
#ifndef ROCKSDB_LITE
|
||||
class OptionsParserTest : public testing::Test {
|
||||
public:
|
||||
OptionsParserTest() { env_.reset(new test::StringEnv(Env::Default())); }
|
||||
OptionsParserTest() { env_.reset(new StringEnv(Env::Default())); }
|
||||
|
||||
protected:
|
||||
std::unique_ptr<test::StringEnv> env_;
|
||||
std::unique_ptr<StringEnv> env_;
|
||||
};
|
||||
|
||||
TEST_F(OptionsParserTest, Comment) {
|
||||
@@ -1111,7 +1485,7 @@ void VerifyCFPointerTypedOptions(
|
||||
|
||||
// change the name of merge operator back-and-forth
|
||||
{
|
||||
auto* merge_operator = dynamic_cast<test::ChanglingMergeOperator*>(
|
||||
auto* merge_operator = dynamic_cast<ChanglingMergeOperator*>(
|
||||
base_cf_opt->merge_operator.get());
|
||||
if (merge_operator != nullptr) {
|
||||
name_buffer = merge_operator->Name();
|
||||
@@ -1129,7 +1503,7 @@ void VerifyCFPointerTypedOptions(
|
||||
// change the name of the compaction filter factory back-and-forth
|
||||
{
|
||||
auto* compaction_filter_factory =
|
||||
dynamic_cast<test::ChanglingCompactionFilterFactory*>(
|
||||
dynamic_cast<ChanglingCompactionFilterFactory*>(
|
||||
base_cf_opt->compaction_filter_factory.get());
|
||||
if (compaction_filter_factory != nullptr) {
|
||||
name_buffer = compaction_filter_factory->Name();
|
||||
@@ -1199,17 +1573,17 @@ TEST_F(OptionsParserTest, DumpAndParse) {
|
||||
"###rocksdb#1-testcf#2###"};
|
||||
const int num_cf = static_cast<int>(cf_names.size());
|
||||
Random rnd(302);
|
||||
test::RandomInitDBOptions(&base_db_opt, &rnd);
|
||||
RandomInitDBOptions(&base_db_opt, &rnd);
|
||||
base_db_opt.db_log_dir += "/#odd #but #could #happen #path #/\\\\#OMG";
|
||||
for (int c = 0; c < num_cf; ++c) {
|
||||
ColumnFamilyOptions cf_opt;
|
||||
Random cf_rnd(0xFB + c);
|
||||
test::RandomInitCFOptions(&cf_opt, &cf_rnd);
|
||||
RandomInitCFOptions(&cf_opt, &cf_rnd);
|
||||
if (c < 4) {
|
||||
cf_opt.prefix_extractor.reset(test::RandomSliceTransform(&rnd, c));
|
||||
cf_opt.prefix_extractor.reset(RandomSliceTransform(&rnd, c));
|
||||
}
|
||||
if (c < 3) {
|
||||
cf_opt.table_factory.reset(test::RandomTableFactory(&rnd, c));
|
||||
cf_opt.table_factory.reset(RandomTableFactory(&rnd, c));
|
||||
}
|
||||
base_cf_opts.emplace_back(cf_opt);
|
||||
}
|
||||
@@ -1343,7 +1717,7 @@ TEST_F(OptionsSanityCheckTest, SanityCheck) {
|
||||
{
|
||||
for (int tb = 2; tb >= 0; --tb) {
|
||||
// change the table factory
|
||||
opts.table_factory.reset(test::RandomTableFactory(&rnd, tb));
|
||||
opts.table_factory.reset(RandomTableFactory(&rnd, tb));
|
||||
ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
|
||||
ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
|
||||
|
||||
@@ -1357,7 +1731,7 @@ TEST_F(OptionsSanityCheckTest, SanityCheck) {
|
||||
{
|
||||
for (int test = 0; test < 5; ++test) {
|
||||
// change the merge operator
|
||||
opts.merge_operator.reset(test::RandomMergeOperator(&rnd));
|
||||
opts.merge_operator.reset(RandomMergeOperator(&rnd));
|
||||
ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
|
||||
ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelNone));
|
||||
|
||||
@@ -1371,7 +1745,7 @@ TEST_F(OptionsSanityCheckTest, SanityCheck) {
|
||||
{
|
||||
for (int test = 0; test < 5; ++test) {
|
||||
// change the compaction filter
|
||||
opts.compaction_filter = test::RandomCompactionFilter(&rnd);
|
||||
opts.compaction_filter = RandomCompactionFilter(&rnd);
|
||||
ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
|
||||
ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
|
||||
|
||||
@@ -1387,8 +1761,7 @@ TEST_F(OptionsSanityCheckTest, SanityCheck) {
|
||||
{
|
||||
for (int test = 0; test < 5; ++test) {
|
||||
// change the compaction filter factory
|
||||
opts.compaction_filter_factory.reset(
|
||||
test::RandomCompactionFilterFactory(&rnd));
|
||||
opts.compaction_filter_factory.reset(RandomCompactionFilterFactory(&rnd));
|
||||
ASSERT_NOK(SanityCheckCFOptions(opts, kSanityLevelExactMatch));
|
||||
ASSERT_OK(SanityCheckCFOptions(opts, kSanityLevelLooselyCompatible));
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user