Compare commits

..

5 Commits

Author SHA1 Message Date
sdong 6999a230ba Include ldb_tools and sst_dump_tools libraries in shared library
Summary: Ldb and sst_dump are not included in shared library now. Add it.

Test Plan:
Build
make release
make shared_lib

Reviewers: igor, kradhakrishnan, rven, yhchiang, IslamAbdelRahman, anthony

Reviewed By: IslamAbdelRahman, anthony

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D51735
2015-12-09 11:05:01 -08:00
sdong 6880d2f545 Fix fb-only build for gcc 4.8.1
Summary: fb build for gcc 4.8.1 is broken for the ZSTD dependency is not fixed after ea11923550. Fixing it.

Test Plan: ROCKSDB_FBCODE_BUILD_WITH_481=1 make -j40 OPT=-g

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D51741
2015-12-09 11:04:06 -08:00
sdong b46e796c99 Upgrade to ZSTD 0.4.2
Summary: Change to call the new compression function.

Test Plan: build and run db_bench with the compression to make sure it compresses.

Reviewers: anthony, rven, kradhakrishnan, IslamAbdelRahman, igor, yhchiang

Reviewed By: yhchiang

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D51603
2015-12-09 11:02:49 -08:00
Yueh-Hsuan Chiang 7f64b56f6b Update HISTORY.md for RocksDB 4.1
Summary:
Update HISTORY.md for RocksDB 4.1

Test Plan:
no code change

Reviewers: igor, sdong, anthony, IslamAbdelRahman, rven, kradhakrishnan

Subscribers: leveldb
2015-11-17 13:53:06 -08:00
Yueh-Hsuan Chiang f2ebb6745a Fix Java Makefile
Summary:
In case rocksdb java package is built using make rocksdbjavastaticrelease, then
only those rocksdb binary built under the virtual environments is release build.

This patch fix this issue.

Test Plan:
PORTABLE=1 V=2 make rocksdbjavastaticrelease -j32
and make sure -O2 and -NDEBUG is included when compiling all source files.

Reviewers: sdong, anthony, IslamAbdelRahman, rven, kradhakrishnan, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D50895
2015-11-17 13:52:32 -08:00
123 changed files with 1579 additions and 5689 deletions
+1 -8
View File
@@ -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
View File
@@ -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.
+5 -14
View File
@@ -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
View File
@@ -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
+22
View File
@@ -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
+6 -1
View File
@@ -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
-19
View File
@@ -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
+52 -71
View File
@@ -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
+23 -28
View File
@@ -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
View File
@@ -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
-6
View File
@@ -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 <
+9 -96
View File
@@ -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) {
-57
View File
@@ -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
+1 -10
View File
@@ -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();
-1
View File
@@ -98,7 +98,6 @@ class CompactionIterator {
SequenceNumber visible_at_tip_;
SequenceNumber earliest_snapshot_;
SequenceNumber latest_snapshot_;
bool ignore_snapshots_;
// State
//
+4 -19
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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(
-95
View File
@@ -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
+6 -22
View File
@@ -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
View File
@@ -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(
-23
View File
@@ -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
View File
@@ -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;
+3 -16
View File
@@ -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()) {
-10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1 -48
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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() {
-4
View File
@@ -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();
-374
View File
@@ -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)
-550
View File
@@ -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
-391
View File
@@ -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();
}
+1
View File
@@ -533,3 +533,4 @@ int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
-119
View File
@@ -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
View File
@@ -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
View File
@@ -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
+9 -25
View File
@@ -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
-12
View File
@@ -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)) {
-2
View File
@@ -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
View File
@@ -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
-3
View File
@@ -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
-113
View File
@@ -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;
}
+104 -52
View File
@@ -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
-10
View File
@@ -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;
-4
View File
@@ -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);
-6
View File
@@ -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
View File
@@ -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);
}
+2 -9
View File
@@ -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)
-10
View File
@@ -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;
+1 -1
View File
@@ -48,7 +48,7 @@ class Status {
kAborted = 10,
kBusy = 11,
kExpired = 12,
kTryAgain = 13,
kTryAgain = 13
};
Code code() const { return code_; }
+8 -24
View File
@@ -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);
-80
View File
@@ -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
+3 -9
View File
@@ -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;
+1 -16
View File
@@ -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().
//
+2 -2
View File
@@ -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
+2 -25
View File
@@ -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.
+1
View File
@@ -19,3 +19,4 @@
#elif defined(OS_WIN)
#include "port/win/port_win.h"
#endif
+6 -2
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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_
+9 -9
View File
@@ -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;
-3
View File
@@ -16,9 +16,6 @@
#include "rocksdb/env.h"
#include <stdint.h>
#include <Windows.h>
namespace rocksdb {
class Env;
-5
View File
@@ -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 \
+5 -5
View File
@@ -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 =
+1 -3
View File
@@ -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_;
+3 -7
View File
@@ -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;
+1 -3
View File
@@ -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
+5 -5
View File
@@ -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_;
}
+5 -7
View File
@@ -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
View File
@@ -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;
+3 -3
View File
@@ -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); }
+4 -5
View File
@@ -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;
-35
View File
@@ -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
View File
@@ -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_) {
-65
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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);
};
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -4
View File
@@ -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) {
+3 -3
View File
@@ -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
View File
@@ -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