mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 22:55:23 +08:00
Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b50106f9a | |||
| ae8e0770b4 | |||
| c674b42d52 | |||
| 43ee5e2b3a | |||
| bcc8557901 | |||
| 65428b0c0a | |||
| 9edda37027 | |||
| aac44226a0 | |||
| 6731997f64 | |||
| 9cd221094c | |||
| fc4616d898 | |||
| 0f31843c15 | |||
| 073cbfc8f0 | |||
| cb5b2baf18 | |||
| b825df81e2 | |||
| 8457b74c26 | |||
| da2fd001a6 | |||
| fe3713961e | |||
| 86ef6c3f74 | |||
| 88f2f89068 | |||
| f8509653ba | |||
| c0ce562c32 | |||
| a8b4a69de0 | |||
| 40a1e31fa5 | |||
| d2ca2bd183 | |||
| d0beadd456 | |||
| 7ac3c796f6 | |||
| 6d5f6a4b1a | |||
| 3c37955a2f | |||
| cbf4a06427 | |||
| 116071411b | |||
| 1f8ade6bd6 | |||
| fa46ddb41f | |||
| 1a8c1b0817 | |||
| 4463b11cad | |||
| bf89edf78b | |||
| 0a9f873f4b | |||
| aad2110823 | |||
| a143ef9b38 | |||
| b3ed08129b | |||
| 854d236361 | |||
| 200c05a23f | |||
| fa798e9e28 | |||
| 658a3ce2fa | |||
| 6b34021fc2 | |||
| 71046971f0 | |||
| 861f6e48e4 | |||
| 7edb92b843 | |||
| 22bb7c754b | |||
| 8eb552bf4d | |||
| 0c4040681a | |||
| 08740b15a4 | |||
| e0aa19a94e | |||
| f1a60e5c3e | |||
| 87d6eb2f6b | |||
| 9262061b0d | |||
| 5e9f3a9aa7 | |||
| 433541823c | |||
| 4734dbb742 | |||
| 72fcbf055d | |||
| 5b76338c01 | |||
| 11c65021fb | |||
| 1d8c57db23 | |||
| 5f2c136c32 | |||
| 8866448001 | |||
| 4012ca1c7b | |||
| e2a093a6c3 | |||
| eeb90c7ee9 | |||
| 5e73c4d4ad | |||
| 1565dab809 | |||
| 0e422308aa | |||
| 6e2b5809f6 | |||
| f2f4c8072f | |||
| 32c965d417 | |||
| 197034e4c3 | |||
| de98c1d9aa | |||
| 4b785aab05 | |||
| aa5c897d42 | |||
| 42c109cc2e | |||
| 352f0636ef | |||
| b1d09f1a51 | |||
| c34271a5a5 | |||
| ab5c5c28fe | |||
| f121c4f504 | |||
| 7afdf5e9f8 | |||
| 46dcf51ca5 | |||
| 59de2dbad7 | |||
| 48e5ea0c34 | |||
| fc0c399d2e | |||
| 43eef52001 | |||
| dad2731729 | |||
| b1074ac24f | |||
| 573844807c | |||
| 5c3b254ef2 | |||
| 4504c99030 | |||
| 1186192ed1 | |||
| 6f4e3ee3e8 | |||
| 74781a0c49 | |||
| 17dc128048 | |||
| 94cf218720 | |||
| 4c6dc7a9ae | |||
| c2bd8f4824 | |||
| 60bf2b7d4a | |||
| bc8eed12d9 | |||
| cb703c9d03 | |||
| f9e2decf7c | |||
| 404d63ac3e |
@@ -21,3 +21,4 @@ util/build_version.cc
|
||||
build_tools/VALGRIND_LOGS/
|
||||
coverage/COVERAGE_REPORT
|
||||
util/build_version.cc.tmp
|
||||
.gdbhistory
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
BSD License
|
||||
|
||||
For rocksdb software
|
||||
|
||||
Copyright (c) 2013, Facebook, Inc.
|
||||
All rights reserved.
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -14,7 +14,7 @@ OPT += -O2 -fno-omit-frame-pointer -momit-leaf-frame-pointer
|
||||
#-----------------------------------------------
|
||||
|
||||
# detect what platform we're building on
|
||||
$(shell (cd build_tools/; ROCKSDB_ROOT=.. ./build_detect_platform ../build_config.mk))
|
||||
$(shell (export ROCKSDB_ROOT=$(CURDIR); $(CURDIR)/build_tools/build_detect_platform $(CURDIR)/build_config.mk))
|
||||
# this file is generated by the previous line to set build flags and sources
|
||||
include build_config.mk
|
||||
|
||||
@@ -48,6 +48,7 @@ TESTS = \
|
||||
db_test \
|
||||
dbformat_test \
|
||||
env_test \
|
||||
blob_store_test \
|
||||
filelock_test \
|
||||
filename_test \
|
||||
filter_block_test \
|
||||
@@ -64,7 +65,8 @@ TESTS = \
|
||||
ttl_test \
|
||||
version_edit_test \
|
||||
version_set_test \
|
||||
write_batch_test
|
||||
write_batch_test\
|
||||
deletefile_test
|
||||
|
||||
TOOLS = \
|
||||
sst_dump \
|
||||
@@ -121,7 +123,7 @@ release:
|
||||
|
||||
coverage:
|
||||
$(MAKE) clean
|
||||
COVERAGEFLAGS="-fprofile-arcs -ftest-coverage" $(MAKE) all check
|
||||
COVERAGEFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS+="-lgcov" $(MAKE) all check
|
||||
(cd coverage; ./coverage_test.sh)
|
||||
# Delete intermediate files
|
||||
find . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" | xargs --no-run-if-empty rm
|
||||
@@ -155,7 +157,7 @@ valgrind_check: all $(PROGRAMS) $(TESTS)
|
||||
done
|
||||
|
||||
clean:
|
||||
-rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) $(THRIFTSERVER) build_config.mk
|
||||
-rm -f $(PROGRAMS) $(BENCHMARKS) $(LIBRARY) $(SHARED) $(MEMENVLIBRARY) build_config.mk
|
||||
-rm -rf ios-x86/* ios-arm/*
|
||||
-find . -name "*.[od]" | xargs --no-run-if-empty rm
|
||||
-find . -type f -regex ".*\.\(\(gcda\)\|\(gcno\)\)" | xargs --no-run-if-empty rm
|
||||
@@ -203,6 +205,9 @@ cache_test: util/cache_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
coding_test: util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(CXX) util/coding_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
||||
|
||||
blob_store_test: util/blob_store_test.o $(LIBOBJECTS) $(TESTHARNESS) $(TESTUTIL)
|
||||
$(CXX) util/blob_store_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o$@ $(LDFLAGS) $(COVERAGEFLAGS)
|
||||
|
||||
stringappend_test: utilities/merge_operators/string_append/stringappend_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(CXX) utilities/merge_operators/string_append/stringappend_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
||||
|
||||
@@ -266,6 +271,9 @@ write_batch_test: db/write_batch_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
merge_test: db/merge_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(CXX) db/merge_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
|
||||
|
||||
deletefile_test: db/deletefile_test.o $(LIBOBJECTS) $(TESTHARNESS)
|
||||
$(CXX) db/deletefile_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS)
|
||||
|
||||
$(MEMENVLIBRARY) : $(MEMENVOBJECTS)
|
||||
rm -f $@
|
||||
$(AR) -rs $@ $(MEMENVOBJECTS)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Additional Grant of Patent Rights
|
||||
|
||||
“Software” means the rocksdb software distributed by Facebook, Inc.
|
||||
|
||||
Facebook hereby grants you a perpetual, worldwide, royalty-free,
|
||||
non-exclusive, irrevocable (subject to the termination provision below)
|
||||
license under any rights in any patent claims owned by Facebook, to make,
|
||||
have made, use, sell, offer to sell, import, and otherwise transfer the
|
||||
Software. For avoidance of doubt, no license is granted under Facebook’s
|
||||
rights in any patent claims that are infringed by (i) modifications to the
|
||||
Software made by you or a third party, or (ii) the Software in combination
|
||||
with any software or other technology provided by you or a third party.
|
||||
|
||||
The license granted hereunder will terminate, automatically and without
|
||||
notice, for anyone that makes any claim (including by filing any lawsuit,
|
||||
assertion or other action) alleging (a) direct, indirect, or contributory
|
||||
infringement or inducement to infringe any patent: (i) by Facebook or any
|
||||
of its subsidiaries or affiliates, whether or not such claim is related
|
||||
to the Software, (ii) by any party if such claim arises in whole or in
|
||||
part from any software, product or service of Facebook or any of its
|
||||
subsidiaries or affiliates, whether or not such claim is related to the
|
||||
Software, or (iii) by any party relating to the Software; or (b) that
|
||||
any right in any patent claim of Facebook is invalid or unenforceable.
|
||||
@@ -1,6 +1,6 @@
|
||||
rocksdb: A persistent key-value store for flash storage
|
||||
Authors: * The Facebook Database Engineering Team
|
||||
* Build on earlier work on leveldb by Sanjay Ghemawat
|
||||
* Build on earlier work on leveldb by Sanjay Ghemawat
|
||||
(sanjay@google.com) and Jeff Dean (jeff@google.com)
|
||||
|
||||
This code is a library that forms the core building block for a fast
|
||||
@@ -19,64 +19,64 @@ persistent key/value store.
|
||||
See doc/index.html for more explanation.
|
||||
See doc/impl.html for a brief overview of the implementation.
|
||||
|
||||
The public interface is in include/*.h. Callers should not include or
|
||||
The public interface is in include/*. Callers should not include or
|
||||
rely on the details of any other header files in this package. Those
|
||||
internal APIs may be changed without warning.
|
||||
|
||||
Guide to header files:
|
||||
|
||||
include/db.h
|
||||
include/rocksdb/db.h
|
||||
Main interface to the DB: Start here
|
||||
|
||||
include/options.h
|
||||
include/rocksdb/options.h
|
||||
Control over the behavior of an entire database, and also
|
||||
control over the behavior of individual reads and writes.
|
||||
|
||||
include/comparator.h
|
||||
include/rocksdb/comparator.h
|
||||
Abstraction for user-specified comparison function. If you want
|
||||
just bytewise comparison of keys, you can use the default comparator,
|
||||
but clients can write their own comparator implementations if they
|
||||
want custom ordering (e.g. to handle different character
|
||||
encodings, etc.)
|
||||
|
||||
include/iterator.h
|
||||
include/rocksdb/iterator.h
|
||||
Interface for iterating over data. You can get an iterator
|
||||
from a DB object.
|
||||
|
||||
include/write_batch.h
|
||||
include/rocksdb/write_batch.h
|
||||
Interface for atomically applying multiple updates to a database.
|
||||
|
||||
include/slice.h
|
||||
include/rocksdb/slice.h
|
||||
A simple module for maintaining a pointer and a length into some
|
||||
other byte array.
|
||||
|
||||
include/status.h
|
||||
include/rocksdb/status.h
|
||||
Status is returned from many of the public interfaces and is used
|
||||
to report success and various kinds of errors.
|
||||
|
||||
include/env.h
|
||||
include/rocksdb/env.h
|
||||
Abstraction of the OS environment. A posix implementation of
|
||||
this interface is in util/env_posix.cc
|
||||
|
||||
include/table_builder.h
|
||||
include/rocksdb/table_builder.h
|
||||
Lower-level modules that most clients probably won't use directly
|
||||
|
||||
include/cache.h
|
||||
include/rocksdb/cache.h
|
||||
An API for the block cache.
|
||||
|
||||
include/compaction_filter.h
|
||||
include/rocksdb/compaction_filter.h
|
||||
An API for a application filter invoked on every compaction.
|
||||
|
||||
include/filter_policy.h
|
||||
include/rocksdb/filter_policy.h
|
||||
An API for configuring a bloom filter.
|
||||
|
||||
include/memtablerep.h
|
||||
include/rocksdb/memtablerep.h
|
||||
An API for implementing a memtable.
|
||||
|
||||
include/statistics.h
|
||||
include/rocksdb/statistics.h
|
||||
An API to retrieve various database statistics.
|
||||
|
||||
include/transaction_log_iterator.h
|
||||
include/rocksdb/transaction_log.h
|
||||
An API to retrieve transaction logs from a database.
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
* Detailed instructions on how to compile using fbcode and jemalloc
|
||||
|
||||
* Latest release is 2.1.fb
|
||||
* Latest release is 2.4.fb
|
||||
|
||||
@@ -31,9 +31,9 @@ fi
|
||||
# Default to fbcode gcc on internal fb machines
|
||||
if [ -d /mnt/gvfs/third-party -a -z "$CXX" ]; then
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
source ./fbcode.gcc471.sh
|
||||
source $PWD/build_tools/fbcode.gcc471.sh
|
||||
else
|
||||
source ./fbcode.clang31.sh
|
||||
source $PWD/build_tools/fbcode.clang31.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -65,7 +65,7 @@ PLATFORM_SHARED_CFLAGS="-fPIC"
|
||||
PLATFORM_SHARED_VERSIONED=true
|
||||
|
||||
# generic port files (working on all platform by #ifdef) go directly in /port
|
||||
GENERIC_PORT_FILES=`cd $ROCKSDB_ROOT; find port -name '*.cc' | tr "\n" " "`
|
||||
GENERIC_PORT_FILES=`find $ROCKSDB_ROOT/port -name '*.cc' | tr "\n" " "`
|
||||
|
||||
# On GCC, we pick libc's memcmp over GCC's memcmp via -fno-builtin-memcmp
|
||||
case "$TARGET_OS" in
|
||||
@@ -82,7 +82,7 @@ case "$TARGET_OS" in
|
||||
if [ -z "$USE_CLANG" ]; then
|
||||
COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
|
||||
fi
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread -lrt"
|
||||
# PORT_FILES=port/linux/linux_specific.cc
|
||||
;;
|
||||
SunOS)
|
||||
@@ -127,21 +127,13 @@ case "$TARGET_OS" in
|
||||
exit 1
|
||||
esac
|
||||
|
||||
./build_detect_version
|
||||
$PWD/build_tools/build_detect_version
|
||||
|
||||
# We want to make a list of all cc files within util, db, table, and helpers
|
||||
# except for the test and benchmark files. By default, find will output a list
|
||||
# of all files matching either rule, so we need to append -print to make the
|
||||
# prune take effect.
|
||||
DIRS="util db table utilities"
|
||||
if test "$USE_THRIFT"; then
|
||||
DIRS="$DIRS thrift/server_utils.cpp thrift/gen-cpp "
|
||||
THRIFTSERVER=leveldb_server
|
||||
fi
|
||||
|
||||
if test "$USE_SCRIBE"; then
|
||||
DIRS="$DIRS scribe "
|
||||
fi
|
||||
|
||||
set -f # temporarily disable globbing so that our patterns arent expanded
|
||||
PRUNE_TEST="-name *test*.cc -prune"
|
||||
@@ -227,14 +219,6 @@ if test "$USE_HDFS"; then
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS $HDFS_LDFLAGS"
|
||||
fi
|
||||
|
||||
# shall we build thrift server or scribe logger
|
||||
if test "$USE_THRIFT" || test "$USE_SCRIBE" ; then
|
||||
THRIFT_CCFLAGS=" -I./thrift -I./thrift/gen-cpp -I./thrift/lib/cpp -I/usr/include -std=gnu++0x"
|
||||
THRIFT_LDFLAGS=" -lexample -lserver -lthrift_base -ltransport -lthrift_exception -lutil -L./thrift/libs "
|
||||
COMMON_FLAGS="$COMMON_FLAGS $THRIFT_CCFLAGS"
|
||||
PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS $THRIFT_LDFLAGS"
|
||||
fi
|
||||
|
||||
# if Intel SSE instruction set is supported, set USE_SSE=" -msse -msse4.2 "
|
||||
COMMON_FLAGS="$COMMON_FLAGS $USE_SSE"
|
||||
|
||||
@@ -254,5 +238,4 @@ echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT
|
||||
echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT
|
||||
echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT
|
||||
echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT
|
||||
echo "THRIFTSERVER=$THRIFTSERVER" >> $OUTPUT
|
||||
echo "EXEC_LDFLAGS=$EXEC_LDFLAGS" >> $OUTPUT
|
||||
|
||||
@@ -19,22 +19,22 @@ if [ "$?" = 0 ]; then
|
||||
awk '
|
||||
BEGIN {
|
||||
print "#include \"build_version.h\"\n"
|
||||
}
|
||||
{ print "const char* leveldb_build_git_sha = \"leveldb_build_git_sha:" $0"\";" }
|
||||
}
|
||||
{ print "const char* rocksdb_build_git_sha = \"rocksdb_build_git_sha:" $0"\";" }
|
||||
' > ${VFILE}
|
||||
else
|
||||
echo "git not found" |
|
||||
awk '
|
||||
BEGIN {
|
||||
print "#include \"build_version.h\""
|
||||
}
|
||||
{ print "const char* leveldb_build_git_sha = \"leveldb_build_git_sha:git not found\";" }
|
||||
print "#include \"build_version.h\""
|
||||
}
|
||||
{ print "const char* rocksdb_build_git_sha = \"rocksdb_build_git_sha:git not found\";" }
|
||||
' > ${VFILE}
|
||||
fi
|
||||
|
||||
echo "const char* leveldb_build_git_datetime = \"leveldb_build_git_datetime:$(date)\";" >> ${VFILE}
|
||||
echo "const char* leveldb_build_compile_date = __DATE__;" >> ${VFILE}
|
||||
echo "const char* leveldb_build_compile_time = __TIME__;" >> ${VFILE}
|
||||
echo "const char* rocksdb_build_git_datetime = \"rocksdb_build_git_datetime:$(date)\";" >> ${VFILE}
|
||||
echo "const char* rocksdb_build_compile_date = __DATE__;" >> ${VFILE}
|
||||
echo "const char* rocksdb_build_compile_time = __TIME__;" >> ${VFILE}
|
||||
|
||||
OUTFILE=$ROCKSDB_ROOT/util/build_version.cc
|
||||
if [ ! -e $OUTFILE ] || ! cmp -s $VFILE $OUTFILE; then
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
function print_usage {
|
||||
echo "Usage: $0 [build | release | bump_version version ]"
|
||||
}
|
||||
|
||||
function check_env {
|
||||
if [ -z $LEVELDB_HOME ] ; then
|
||||
echo "Expect LEVELDB_HOME to be SET"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z $JAVA_HOME ] ; then
|
||||
export JAVA_HOME=/usr/local/jdk-6u14-64/
|
||||
echo "JAVA_HOME not set. Assuming JAVA_HOME=$JAVA_HOME"
|
||||
fi
|
||||
if [ -z $LEVELDBJNI_HOME ] ; then
|
||||
export LEVELDBJNI_HOME=$LEVELDB_HOME/java/leveldbjni/
|
||||
echo "LEVELDBJNI_HOME not set. Assuming LEVELDBJNI_HOME=$LEVELDBJNI_HOME"
|
||||
fi
|
||||
if [ -z $SNAPPY_HOME ] ; then
|
||||
export SNAPPY_HOME="/home/dhruba/snappy-1.0.5"
|
||||
echo "SNAPPY_HOME not set. Assuming SNAPPY_HOME=$SNAPPY_HOME"
|
||||
fi
|
||||
if [ -z $LEVELDB_PATCH ] ; then
|
||||
LEVELDB_PATCH=$LEVELDB_HOME/java/leveldbjni/db.h.patch
|
||||
echo "LEVELDB_PATCH not set. Assuming LEVELDB_PATCH=$LEVELDB_PATCH"
|
||||
fi
|
||||
}
|
||||
|
||||
function build {
|
||||
cd $LEVELDB_HOME
|
||||
git apply $LEVELDB_PATCH
|
||||
make clean libleveldb.a
|
||||
cd $LEVELDB_HOME/java/leveldb/leveldb-api
|
||||
mvn clean package
|
||||
cd $LEVELDBJNI_HOME
|
||||
mvn clean install -P linux64
|
||||
cd $LEVELDB_HOME
|
||||
git checkout $LEVELDB_HOME/include/leveldb/db.h
|
||||
}
|
||||
|
||||
function release {
|
||||
cd $LEVELDB_HOME
|
||||
git apply $LEVELDB_PATCH
|
||||
make clean libleveldb.a
|
||||
cd $LEVELDB_HOME/java/leveldb/leveldb-api
|
||||
mvn clean package
|
||||
cd $LEVELDBJNI_HOME
|
||||
mvn deploy -P linux64 -DskipTests
|
||||
cd $LEVELDB_HOME
|
||||
git checkout $LEVELDB_HOME/include/leveldb/db.h
|
||||
}
|
||||
|
||||
CMD=$1
|
||||
if [ -z $CMD ]; then
|
||||
print_usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$CMD" in
|
||||
build)
|
||||
check_env
|
||||
build
|
||||
;;
|
||||
bump_version)
|
||||
if [ -z $2 ] ; then
|
||||
echo "bump_version requires a version.no parameter at the end"
|
||||
exit 1
|
||||
fi
|
||||
check_env
|
||||
VERSION=$2
|
||||
pushd $LEVELDBJNI_HOME
|
||||
mvn versions:set -DnewVersion="$VERSION"
|
||||
popd
|
||||
echo "VERSION SET TO $VERSION"
|
||||
;;
|
||||
release)
|
||||
check_env
|
||||
pushd $LEVELDBJNI_HOME
|
||||
release
|
||||
popd
|
||||
;;
|
||||
*)
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -4,21 +4,16 @@
|
||||
# fbcode settings. It uses the latest g++ compiler and also
|
||||
# uses jemalloc
|
||||
|
||||
TOOLCHAIN_REV=f365dbeae46a30414a2874a6f45e73e10f1caf7d
|
||||
TOOLCHAIN_REV=fbe3b095a4cc4a3713730050d182b7b4a80c342f
|
||||
TOOLCHAIN_EXECUTABLES="/mnt/gvfs/third-party/$TOOLCHAIN_REV/centos5.2-native"
|
||||
TOOLCHAIN_LIB_BASE="/mnt/gvfs/third-party/$TOOLCHAIN_REV/gcc-4.7.1-glibc-2.14.1"
|
||||
TOOL_JEMALLOC=jemalloc-3.0.0/2f45f3a
|
||||
TOOL_JEMALLOC=jemalloc-3.3.1/9202ce3
|
||||
GLIBC_RUNTIME_PATH=/usr/local/fbcode/gcc-4.7.1-glibc-2.14.1
|
||||
|
||||
# location of snappy headers and libraries
|
||||
SNAPPY_INCLUDE=" -I $TOOLCHAIN_LIB_BASE/snappy/snappy-1.0.3/7518bbe/include"
|
||||
SNAPPY_LIBS=" $TOOLCHAIN_LIB_BASE/snappy/snappy-1.0.3/7518bbe/lib/libsnappy.a"
|
||||
|
||||
# location of boost headers and libraries
|
||||
THRIFT_INCLUDE=" -I $TOOLCHAIN_LIB_BASE/boost/boost-1.48.0/bef9365/include -std=gnu++0x"
|
||||
THRIFT_INCLUDE+=" -I./thrift -I./thrift/gen-cpp -I./thrift/lib/cpp"
|
||||
THRIFT_LIBS=" -L $TOOLCHAIN_LIB_BASE/boost/boost-1.48.0/bef9365/lib"
|
||||
|
||||
# location of libevent
|
||||
LIBEVENT_INCLUDE=" -I $TOOLCHAIN_LIB_BASE/libevent/libevent-1.4.14b/91ddd43/include"
|
||||
LIBEVENT_LIBS=" -L $TOOLCHAIN_LIB_BASE/libevent/libevent-1.4.14b/91ddd43/lib"
|
||||
@@ -27,7 +22,7 @@ LIBEVENT_LIBS=" -L $TOOLCHAIN_LIB_BASE/libevent/libevent-1.4.14b/91ddd43/lib"
|
||||
export USE_SSE=" -msse -msse4.2 "
|
||||
|
||||
CC="$TOOLCHAIN_EXECUTABLES/clang/clang-3.1/6ca8a59/bin/clang $CLANG_INCLUDES"
|
||||
CXX="$TOOLCHAIN_EXECUTABLES/clang/clang-3.1/6ca8a59/bin/clang++ $CLANG_INCLUDES $JINCLUDE $SNAPPY_INCLUDE $THRIFT_INCLUDE $LIBEVENT_INCLUDE"
|
||||
CXX="$TOOLCHAIN_EXECUTABLES/clang/clang-3.1/6ca8a59/bin/clang++ $CLANG_INCLUDES $JINCLUDE $SNAPPY_INCLUDE $LIBEVENT_INCLUDE"
|
||||
AR=$TOOLCHAIN_EXECUTABLES/binutils/binutils-2.21.1/da39a3e/bin/ar
|
||||
RANLIB=$TOOLCHAIN_EXECUTABLES/binutils/binutils-2.21.1/da39a3e/bin/ranlib
|
||||
|
||||
@@ -37,8 +32,8 @@ CXXFLAGS="$CFLAGS -nostdinc++ -std=gnu++0x"
|
||||
CFLAGS+=" -I $TOOLCHAIN_LIB_BASE/jemalloc/$TOOL_JEMALLOC/include -DHAVE_JEMALLOC"
|
||||
|
||||
EXEC_LDFLAGS=" -Wl,--whole-archive $TOOLCHAIN_LIB_BASE/jemalloc/$TOOL_JEMALLOC/lib/libjemalloc.a"
|
||||
EXEC_LDFLAGS+=" -Wl,--no-whole-archive $TOOLCHAIN_LIB_BASE/libunwind/libunwind-1.0.1/91ddd43/lib/libunwind.a"
|
||||
EXEC_LDFLAGS+=" $HDFSLIB $SNAPPY_LIBS $THRIFT_LIBS $LIBEVENT_LIBS"
|
||||
EXEC_LDFLAGS+=" -Wl,--no-whole-archive $TOOLCHAIN_LIB_BASE/libunwind/libunwind-1.0.1/350336c/lib/libunwind.a"
|
||||
EXEC_LDFLAGS+=" $HDFSLIB $SNAPPY_LIBS $LIBEVENT_LIBS"
|
||||
EXEC_LDFLAGS+=" -Wl,--dynamic-linker,$GLIBC_RUNTIME_PATH/lib/ld-linux-x86-64.so.2"
|
||||
EXEC_LDFLAGS+=" -B$TOOLCHAIN_EXECUTABLES/binutils/binutils-2.21.1/da39a3e/bin"
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
# fbcode settings. It uses the latest g++ compiler and also
|
||||
# uses jemalloc
|
||||
|
||||
TOOLCHAIN_REV=83eb773e262fa705eaebbf3de40db71d53fabf2e
|
||||
TOOLCHAIN_REV=fbe3b095a4cc4a3713730050d182b7b4a80c342f
|
||||
TOOLCHAIN_EXECUTABLES="/mnt/gvfs/third-party/$TOOLCHAIN_REV/centos5.2-native"
|
||||
TOOLCHAIN_LIB_BASE="/mnt/gvfs/third-party/$TOOLCHAIN_REV/gcc-4.7.1-glibc-2.14.1"
|
||||
TOOL_JEMALLOC=jemalloc-3.3.1/2f45f3a
|
||||
TOOL_JEMALLOC=jemalloc-3.3.1/9202ce3
|
||||
|
||||
# location of libhdfs libraries
|
||||
if test "$USE_HDFS"; then
|
||||
@@ -27,11 +27,6 @@ SNAPPY_LIBS=" $TOOLCHAIN_LIB_BASE/snappy/snappy-1.0.3/7518bbe/lib/libsnappy.a"
|
||||
ZLIB_INCLUDE=" -I $TOOLCHAIN_LIB_BASE/zlib/zlib-1.2.5/91ddd43/include"
|
||||
ZLIB_LIBS=" $TOOLCHAIN_LIB_BASE/zlib/zlib-1.2.5/91ddd43/lib/libz.a"
|
||||
|
||||
# location of boost headers and libraries
|
||||
THRIFT_INCLUDE=" -I $TOOLCHAIN_LIB_BASE/boost/boost-1.48.0/2a0840d/include"
|
||||
THRIFT_INCLUDE+=" -I./thrift -I./thrift/gen-cpp -I./thrift/lib/cpp"
|
||||
THRIFT_LIBS=" -L $TOOLCHAIN_LIB_BASE/boost/boost-1.48.0/2a0840d/lib"
|
||||
|
||||
# location of libevent
|
||||
LIBEVENT_INCLUDE=" -I $TOOLCHAIN_LIB_BASE/libevent/libevent-1.4.14b/91ddd43/include"
|
||||
LIBEVENT_LIBS=" -L $TOOLCHAIN_LIB_BASE/libevent/libevent-1.4.14b/91ddd43/lib"
|
||||
@@ -40,7 +35,7 @@ LIBEVENT_LIBS=" -L $TOOLCHAIN_LIB_BASE/libevent/libevent-1.4.14b/91ddd43/lib"
|
||||
export USE_SSE=" -msse -msse4.2 "
|
||||
|
||||
CC="$TOOLCHAIN_EXECUTABLES/gcc/gcc-4.7.1-glibc-2.14.1/bin/gcc"
|
||||
CXX="$TOOLCHAIN_EXECUTABLES/gcc/gcc-4.7.1-glibc-2.14.1/bin/g++ $JINCLUDE $SNAPPY_INCLUDE $ZLIB_INCLUDE $THRIFT_INCLUDE $LIBEVENT_INCLUDE"
|
||||
CXX="$TOOLCHAIN_EXECUTABLES/gcc/gcc-4.7.1-glibc-2.14.1/bin/g++ $JINCLUDE $SNAPPY_INCLUDE $ZLIB_INCLUDE $LIBEVENT_INCLUDE"
|
||||
AR=$TOOLCHAIN_EXECUTABLES/binutils/binutils-2.21.1/da39a3e/bin/ar
|
||||
RANLIB=$TOOLCHAIN_EXECUTABLES/binutils/binutils-2.21.1/da39a3e/bin/ranlib
|
||||
|
||||
@@ -48,8 +43,8 @@ CFLAGS="-B$TOOLCHAIN_EXECUTABLES/binutils/binutils-2.21.1/bin/gold -m64 -mtune=g
|
||||
CFLAGS+=" -I $TOOLCHAIN_LIB_BASE/jemalloc/$TOOL_JEMALLOC/include -DHAVE_JEMALLOC"
|
||||
|
||||
EXEC_LDFLAGS=" -Wl,--whole-archive $TOOLCHAIN_LIB_BASE/jemalloc/$TOOL_JEMALLOC/lib/libjemalloc.a"
|
||||
EXEC_LDFLAGS+=" -Wl,--no-whole-archive $TOOLCHAIN_LIB_BASE/libunwind/libunwind-1.0.1/91ddd43/lib/libunwind.a"
|
||||
EXEC_LDFLAGS+=" $HDFSLIB $SNAPPY_LIBS $ZLIB_LIBS $THRIFT_LIBS $LIBEVENT_LIBS"
|
||||
EXEC_LDFLAGS+=" -Wl,--no-whole-archive $TOOLCHAIN_LIB_BASE/libunwind/libunwind-1.0.1/350336c/lib/libunwind.a"
|
||||
EXEC_LDFLAGS+=" $HDFSLIB $SNAPPY_LIBS $ZLIB_LIBS $LIBEVENT_LIBS"
|
||||
|
||||
PLATFORM_LDFLAGS="-L$TOOLCHAIN_LIB_BASE/libgcc/libgcc-4.7.1/afc21dc/lib -L$TOOLCHAIN_LIB_BASE/glibc/glibc-2.14.1/99df8fc/lib"
|
||||
|
||||
|
||||
@@ -55,12 +55,19 @@ then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
LCOV_VERSION=$(lcov -v | grep 1.1 || true)
|
||||
if [ $LCOV_VERSION ]
|
||||
then
|
||||
echo "Not supported lcov version. Expect lcov 1.1."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
(cd $ROOT; lcov --no-external \
|
||||
--capture \
|
||||
--directory $PWD \
|
||||
--gcov-tool $GCOV \
|
||||
--output-file $COVERAGE_DIR/coverage.info &>/dev/null)
|
||||
--output-file $COVERAGE_DIR/coverage.info)
|
||||
|
||||
genhtml $COVERAGE_DIR/coverage.info -o $COVERAGE_DIR &>/dev/null
|
||||
genhtml $COVERAGE_DIR/coverage.info -o $COVERAGE_DIR
|
||||
|
||||
echo "HTML Coverage report is generated in $COVERAGE_DIR"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+14
-7
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -9,12 +14,12 @@
|
||||
#include "db/merge_helper.h"
|
||||
#include "db/table_cache.h"
|
||||
#include "db/version_edit.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/iterator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "util/stop_watch.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
Status BuildTable(const std::string& dbname,
|
||||
Env* env,
|
||||
@@ -25,7 +30,8 @@ Status BuildTable(const std::string& dbname,
|
||||
FileMetaData* meta,
|
||||
const Comparator* user_comparator,
|
||||
const SequenceNumber newest_snapshot,
|
||||
const SequenceNumber earliest_seqno_in_memtable) {
|
||||
const SequenceNumber earliest_seqno_in_memtable,
|
||||
const bool enable_compression) {
|
||||
Status s;
|
||||
meta->file_size = 0;
|
||||
meta->smallest_seqno = meta->largest_seqno = 0;
|
||||
@@ -46,7 +52,8 @@ Status BuildTable(const std::string& dbname,
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
TableBuilder* builder = new TableBuilder(options, file.get(), 0);
|
||||
TableBuilder* builder = new TableBuilder(options, file.get(), 0,
|
||||
enable_compression);
|
||||
|
||||
// the first key is the smallest key
|
||||
Slice key = iter->key();
|
||||
@@ -204,4 +211,4 @@ Status BuildTable(const std::string& dbname,
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+12
-12
@@ -1,15 +1,16 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/types.h"
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_BUILDER_H_
|
||||
#define STORAGE_LEVELDB_DB_BUILDER_H_
|
||||
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "leveldb/types.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
struct Options;
|
||||
struct FileMetaData;
|
||||
@@ -34,8 +35,7 @@ extern Status BuildTable(const std::string& dbname,
|
||||
FileMetaData* meta,
|
||||
const Comparator* user_comparator,
|
||||
const SequenceNumber newest_snapshot,
|
||||
const SequenceNumber earliest_seqno_in_memtable);
|
||||
const SequenceNumber earliest_seqno_in_memtable,
|
||||
const bool enable_compression);
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_BUILDER_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -1,43 +1,48 @@
|
||||
// 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 "leveldb/c.h"
|
||||
#include "rocksdb/c.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "leveldb/cache.h"
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/filter_policy.h"
|
||||
#include "leveldb/iterator.h"
|
||||
#include "leveldb/options.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "leveldb/write_batch.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/filter_policy.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
|
||||
using leveldb::Cache;
|
||||
using leveldb::Comparator;
|
||||
using leveldb::CompressionType;
|
||||
using leveldb::DB;
|
||||
using leveldb::Env;
|
||||
using leveldb::FileLock;
|
||||
using leveldb::FilterPolicy;
|
||||
using leveldb::Iterator;
|
||||
using leveldb::Logger;
|
||||
using leveldb::NewBloomFilterPolicy;
|
||||
using leveldb::NewLRUCache;
|
||||
using leveldb::Options;
|
||||
using leveldb::RandomAccessFile;
|
||||
using leveldb::Range;
|
||||
using leveldb::ReadOptions;
|
||||
using leveldb::SequentialFile;
|
||||
using leveldb::Slice;
|
||||
using leveldb::Snapshot;
|
||||
using leveldb::Status;
|
||||
using leveldb::WritableFile;
|
||||
using leveldb::WriteBatch;
|
||||
using leveldb::WriteOptions;
|
||||
using rocksdb::Cache;
|
||||
using rocksdb::Comparator;
|
||||
using rocksdb::CompressionType;
|
||||
using rocksdb::DB;
|
||||
using rocksdb::Env;
|
||||
using rocksdb::FileLock;
|
||||
using rocksdb::FilterPolicy;
|
||||
using rocksdb::Iterator;
|
||||
using rocksdb::Logger;
|
||||
using rocksdb::NewBloomFilterPolicy;
|
||||
using rocksdb::NewLRUCache;
|
||||
using rocksdb::Options;
|
||||
using rocksdb::RandomAccessFile;
|
||||
using rocksdb::Range;
|
||||
using rocksdb::ReadOptions;
|
||||
using rocksdb::SequentialFile;
|
||||
using rocksdb::Slice;
|
||||
using rocksdb::Snapshot;
|
||||
using rocksdb::Status;
|
||||
using rocksdb::WritableFile;
|
||||
using rocksdb::WriteBatch;
|
||||
using rocksdb::WriteOptions;
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file. See the AUTHORS file for names of contributors. */
|
||||
|
||||
#include "leveldb/c.h"
|
||||
#include "rocksdb/c.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
@@ -296,7 +296,7 @@ int main(int argc, char** argv) {
|
||||
{
|
||||
char* prop = leveldb_property_value(db, "nosuchprop");
|
||||
CheckCondition(prop == NULL);
|
||||
prop = leveldb_property_value(db, "leveldb.stats");
|
||||
prop = leveldb_property_value(db, "rocksdb.stats");
|
||||
CheckCondition(prop != NULL);
|
||||
Free(&prop);
|
||||
}
|
||||
|
||||
+24
-18
@@ -1,16 +1,21 @@
|
||||
// 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 "leveldb/db.h"
|
||||
#include "rocksdb/db.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "leveldb/cache.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/write_batch.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "db/db_impl.h"
|
||||
#include "db/filename.h"
|
||||
#include "db/log_format.h"
|
||||
@@ -20,7 +25,7 @@
|
||||
#include "util/testharness.h"
|
||||
#include "util/testutil.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static const int kValueSize = 1000;
|
||||
|
||||
@@ -68,7 +73,7 @@ class CorruptionTest {
|
||||
void RepairDB() {
|
||||
delete db_;
|
||||
db_ = nullptr;
|
||||
ASSERT_OK(::leveldb::RepairDB(dbname_, options_));
|
||||
ASSERT_OK(::rocksdb::RepairDB(dbname_, options_));
|
||||
}
|
||||
|
||||
void Build(int n) {
|
||||
@@ -230,7 +235,7 @@ TEST(CorruptionTest, NewFileErrorDuringWrite) {
|
||||
TEST(CorruptionTest, TableFile) {
|
||||
Build(100);
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
dbi->TEST_CompactRange(0, nullptr, nullptr);
|
||||
dbi->TEST_CompactRange(1, nullptr, nullptr);
|
||||
|
||||
@@ -241,7 +246,7 @@ TEST(CorruptionTest, TableFile) {
|
||||
TEST(CorruptionTest, TableFileIndexData) {
|
||||
Build(10000); // Enough to build multiple Tables
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
|
||||
Corrupt(kTableFile, -2000, 500);
|
||||
Reopen();
|
||||
@@ -279,7 +284,7 @@ TEST(CorruptionTest, SequenceNumberRecovery) {
|
||||
TEST(CorruptionTest, CorruptedDescriptor) {
|
||||
ASSERT_OK(db_->Put(WriteOptions(), "foo", "hello"));
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
dbi->TEST_CompactRange(0, nullptr, nullptr);
|
||||
|
||||
Corrupt(kDescriptorFile, 0, 1000);
|
||||
@@ -296,9 +301,9 @@ TEST(CorruptionTest, CorruptedDescriptor) {
|
||||
TEST(CorruptionTest, CompactionInputError) {
|
||||
Build(10);
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
const int last = dbi->MaxMemCompactionLevel();
|
||||
ASSERT_EQ(1, Property("leveldb.num-files-at-level" + NumberToString(last)));
|
||||
ASSERT_EQ(1, Property("rocksdb.num-files-at-level" + NumberToString(last)));
|
||||
|
||||
Corrupt(kTableFile, 100, 1);
|
||||
Check(9, 9);
|
||||
@@ -319,12 +324,13 @@ TEST(CorruptionTest, CompactionInputErrorParanoid) {
|
||||
for (int level = 1; level < dbi->NumberLevels(); level++) {
|
||||
dbi->Put(WriteOptions(), "", "begin");
|
||||
dbi->Put(WriteOptions(), "~", "end");
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
}
|
||||
|
||||
Build(10);
|
||||
dbi->TEST_CompactMemTable();
|
||||
ASSERT_EQ(1, Property("leveldb.num-files-at-level0"));
|
||||
dbi->TEST_FlushMemTable();
|
||||
dbi->TEST_WaitForCompact();
|
||||
ASSERT_EQ(1, Property("rocksdb.num-files-at-level0"));
|
||||
|
||||
Corrupt(kTableFile, 100, 1);
|
||||
Check(9, 9);
|
||||
@@ -341,7 +347,7 @@ TEST(CorruptionTest, CompactionInputErrorParanoid) {
|
||||
TEST(CorruptionTest, UnrelatedKeys) {
|
||||
Build(10);
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
Corrupt(kTableFile, 100, 1);
|
||||
|
||||
std::string tmp1, tmp2;
|
||||
@@ -349,13 +355,13 @@ TEST(CorruptionTest, UnrelatedKeys) {
|
||||
std::string v;
|
||||
ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
|
||||
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
|
||||
dbi->TEST_CompactMemTable();
|
||||
dbi->TEST_FlushMemTable();
|
||||
ASSERT_OK(db_->Get(ReadOptions(), Key(1000, &tmp1), &v));
|
||||
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+370
-148
File diff suppressed because it is too large
Load Diff
+38
-32
@@ -1,3 +1,8 @@
|
||||
// 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) 2012 Facebook.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
@@ -8,12 +13,12 @@
|
||||
#include "db/db_impl.h"
|
||||
#include "db/filename.h"
|
||||
#include "db/version_set.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "port/port.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
Status DBImpl::DisableFileDeletions() {
|
||||
MutexLock l(&mutex_);
|
||||
@@ -30,16 +35,19 @@ Status DBImpl::EnableFileDeletions() {
|
||||
}
|
||||
|
||||
Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
|
||||
uint64_t* manifest_file_size) {
|
||||
uint64_t* manifest_file_size,
|
||||
bool flush_memtable) {
|
||||
|
||||
*manifest_file_size = 0;
|
||||
|
||||
// flush all dirty data to disk.
|
||||
Status status = Flush(FlushOptions());
|
||||
if (!status.ok()) {
|
||||
Log(options_.info_log, "Cannot Flush data %s\n",
|
||||
status.ToString().c_str());
|
||||
return status;
|
||||
if (flush_memtable) {
|
||||
// flush all dirty data to disk.
|
||||
Status status = Flush(FlushOptions());
|
||||
if (!status.ok()) {
|
||||
Log(options_.info_log, "Cannot Flush data %s\n",
|
||||
status.ToString().c_str());
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
MutexLock l(&mutex_);
|
||||
@@ -48,18 +56,17 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
|
||||
std::set<uint64_t> live;
|
||||
versions_->AddLiveFilesCurrentVersion(&live);
|
||||
|
||||
ret.resize(live.size() + 2); //*.sst + CURRENT + MANIFEST
|
||||
ret.clear();
|
||||
ret.reserve(live.size() + 2); //*.sst + CURRENT + MANIFEST
|
||||
|
||||
// create names of the live files. The names are not absolute
|
||||
// paths, instead they are relative to dbname_;
|
||||
std::set<uint64_t>::iterator it = live.begin();
|
||||
for (unsigned int i = 0; i < live.size(); i++, it++) {
|
||||
ret[i] = TableFileName("", *it);
|
||||
for (auto live_file : live) {
|
||||
ret.push_back(TableFileName("", live_file));
|
||||
}
|
||||
|
||||
ret[live.size()] = CurrentFileName("");
|
||||
ret[live.size()+1] = DescriptorFileName("",
|
||||
versions_->ManifestFileNumber());
|
||||
ret.push_back(CurrentFileName(""));
|
||||
ret.push_back(DescriptorFileName("", versions_->ManifestFileNumber()));
|
||||
|
||||
// find length of manifest file while holding the mutex lock
|
||||
*manifest_file_size = versions_->ManifestFileSize();
|
||||
@@ -71,9 +78,9 @@ Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
|
||||
// First get sorted files in archive dir, then append sorted files from main
|
||||
// dir to maintain sorted order
|
||||
|
||||
// list wal files in archive dir.
|
||||
// list wal files in archive dir.
|
||||
Status s;
|
||||
std::string archivedir = ArchivalDirectory(dbname_);
|
||||
std::string archivedir = ArchivalDirectory(options_.wal_dir);
|
||||
if (env_->FileExists(archivedir)) {
|
||||
s = AppendSortedWalsOfType(archivedir, files, kArchivedLogFile);
|
||||
if (!s.ok()) {
|
||||
@@ -81,26 +88,25 @@ Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
|
||||
}
|
||||
}
|
||||
// list wal files in main db dir.
|
||||
s = AppendSortedWalsOfType(dbname_, files, kAliveLogFile);
|
||||
if (!s.ok()) {
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
return AppendSortedWalsOfType(options_.wal_dir, files, kAliveLogFile);
|
||||
}
|
||||
|
||||
Status DBImpl::DeleteWalFiles(const VectorLogPtr& files) {
|
||||
Status s;
|
||||
std::string archivedir = ArchivalDirectory(dbname_);
|
||||
std::string archivedir = ArchivalDirectory(options_.wal_dir);
|
||||
std::string files_not_deleted;
|
||||
for (const auto& wal : files) {
|
||||
/* Try deleting in archive dir. If fails, try deleting in main db dir.
|
||||
* This is efficient because all except for very few wal files will be in
|
||||
* archive. Checking for WalType is not much helpful because alive wal could
|
||||
be archived now.
|
||||
/* Try deleting in the dir that pathname points to for the logfile.
|
||||
This may fail if we try to delete a log file which was live when captured
|
||||
but is archived now. Try deleting it from archive also
|
||||
*/
|
||||
if (!env_->DeleteFile(archivedir + "/" + wal->Filename()).ok() &&
|
||||
!env_->DeleteFile(dbname_ + "/" + wal->Filename()).ok()) {
|
||||
files_not_deleted.append(wal->Filename());
|
||||
Status st = env_->DeleteFile(options_.wal_dir + "/" + wal->PathName());
|
||||
if (!st.ok()) {
|
||||
if (wal->Type() == kAliveLogFile &&
|
||||
env_->DeleteFile(LogFileName(archivedir, wal->LogNumber())).ok()) {
|
||||
continue;
|
||||
}
|
||||
files_not_deleted.append(wal->PathName());
|
||||
}
|
||||
}
|
||||
if (!files_not_deleted.empty()) {
|
||||
|
||||
+411
-139
File diff suppressed because it is too large
Load Diff
+45
-33
@@ -1,10 +1,12 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_DB_IMPL_H_
|
||||
#define STORAGE_LEVELDB_DB_DB_IMPL_H_
|
||||
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <set>
|
||||
@@ -12,19 +14,15 @@
|
||||
#include "db/dbformat.h"
|
||||
#include "db/log_writer.h"
|
||||
#include "db/snapshot.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/memtablerep.h"
|
||||
#include "leveldb/transaction_log.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/memtablerep.h"
|
||||
#include "rocksdb/transaction_log.h"
|
||||
#include "port/port.h"
|
||||
#include "util/stats_logger.h"
|
||||
#include "memtablelist.h"
|
||||
|
||||
#ifdef USE_SCRIBE
|
||||
#include "scribe/scribe_logger.h"
|
||||
#endif
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class MemTable;
|
||||
class TableCache;
|
||||
@@ -64,7 +62,7 @@ class DBImpl : public DB {
|
||||
virtual bool GetProperty(const Slice& property, std::string* value);
|
||||
virtual void GetApproximateSizes(const Range* range, int n, uint64_t* sizes);
|
||||
virtual void CompactRange(const Slice* begin, const Slice* end,
|
||||
bool reduce_level = false);
|
||||
bool reduce_level = false, int target_level = -1);
|
||||
virtual int NumberLevels();
|
||||
virtual int MaxMemCompactionLevel();
|
||||
virtual int Level0StopWriteTrigger();
|
||||
@@ -72,23 +70,28 @@ class DBImpl : public DB {
|
||||
virtual Status DisableFileDeletions();
|
||||
virtual Status EnableFileDeletions();
|
||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
||||
uint64_t* manifest_file_size);
|
||||
uint64_t* manifest_file_size,
|
||||
bool flush_memtable = true);
|
||||
virtual Status GetSortedWalFiles(VectorLogPtr& files);
|
||||
virtual Status DeleteWalFiles(const VectorLogPtr& files);
|
||||
virtual SequenceNumber GetLatestSequenceNumber();
|
||||
virtual Status GetUpdatesSince(SequenceNumber seq_number,
|
||||
unique_ptr<TransactionLogIterator>* iter);
|
||||
virtual Status DeleteFile(std::string name);
|
||||
|
||||
virtual void GetLiveFilesMetaData(
|
||||
std::vector<LiveFileMetaData> *metadata);
|
||||
|
||||
// Extra methods (for testing) that are not in the public DB interface
|
||||
|
||||
// Compact any files in the named level that overlap [*begin, *end]
|
||||
void TEST_CompactRange(int level, const Slice* begin, const Slice* end);
|
||||
|
||||
// Force current memtable contents to be compacted.
|
||||
Status TEST_CompactMemTable();
|
||||
// Force current memtable contents to be flushed.
|
||||
Status TEST_FlushMemTable();
|
||||
|
||||
// Wait for memtable compaction
|
||||
Status TEST_WaitForCompactMemTable();
|
||||
Status TEST_WaitForFlushMemTable();
|
||||
|
||||
// Wait for any compaction
|
||||
Status TEST_WaitForCompact();
|
||||
@@ -111,6 +114,9 @@ class DBImpl : public DB {
|
||||
// Trigger's a background call for testing.
|
||||
void TEST_PurgeObsoleteteWAL();
|
||||
|
||||
// get total level0 file size. Only for testing.
|
||||
uint64_t TEST_GetLevel0TotalSize() { return versions_->NumLevelBytes(0);}
|
||||
|
||||
protected:
|
||||
Env* const env_;
|
||||
const std::string dbname_;
|
||||
@@ -150,9 +156,9 @@ class DBImpl : public DB {
|
||||
// Delete any unneeded files and stale in-memory entries.
|
||||
void DeleteObsoleteFiles();
|
||||
|
||||
// Compact the in-memory write buffer to disk. Switches to a new
|
||||
// Flush the in-memory write buffer to storage. Switches to a new
|
||||
// log-file/memtable and writes a new descriptor iff successful.
|
||||
Status CompactMemTable(bool* madeProgress = nullptr);
|
||||
Status FlushMemTableToOutputFile(bool* madeProgress = nullptr);
|
||||
|
||||
Status RecoverLogFile(uint64_t log_number,
|
||||
VersionEdit* edit,
|
||||
@@ -175,17 +181,20 @@ class DBImpl : public DB {
|
||||
// Force current memtable contents to be flushed.
|
||||
Status FlushMemTable(const FlushOptions& options);
|
||||
|
||||
// Wait for memtable compaction
|
||||
Status WaitForCompactMemTable();
|
||||
// Wait for memtable flushed
|
||||
Status WaitForFlushMemTable();
|
||||
|
||||
void MaybeScheduleLogDBDeployStats();
|
||||
static void BGLogDBDeployStats(void* db);
|
||||
void LogDBDeployStats();
|
||||
|
||||
void MaybeScheduleCompaction();
|
||||
static void BGWork(void* db);
|
||||
void BackgroundCall();
|
||||
void MaybeScheduleFlushOrCompaction();
|
||||
static void BGWorkCompaction(void* db);
|
||||
static void BGWorkFlush(void* db);
|
||||
void BackgroundCallCompaction();
|
||||
void BackgroundCallFlush();
|
||||
Status BackgroundCompaction(bool* madeProgress,DeletionState& deletion_state);
|
||||
Status BackgroundFlush(bool* madeProgress);
|
||||
void CleanupCompaction(CompactionState* compact);
|
||||
Status DoCompactionWork(CompactionState* compact);
|
||||
|
||||
@@ -208,6 +217,8 @@ class DBImpl : public DB {
|
||||
// Removes the file listed in files_to_evict from the table_cache
|
||||
void EvictObsoleteFiles(DeletionState& deletion_state);
|
||||
|
||||
Status DeleteLogFile(uint64_t number);
|
||||
|
||||
void PurgeObsoleteWALFiles();
|
||||
|
||||
Status AppendSortedWalsOfType(const std::string& path,
|
||||
@@ -230,16 +241,17 @@ class DBImpl : public DB {
|
||||
|
||||
void PrintStatistics();
|
||||
|
||||
// dump leveldb.stats to LOG
|
||||
// dump rocksdb.stats to LOG
|
||||
void MaybeDumpStats();
|
||||
|
||||
// Return the minimum empty level that could hold the total data in the
|
||||
// input level. Return the input level, if such level could not be found.
|
||||
int FindMinimumEmptyLevelFitting(int level);
|
||||
|
||||
// Move the files in the input level to the minimum level that could hold
|
||||
// the data set.
|
||||
void ReFitLevel(int level);
|
||||
// Move the files in the input level to the target level.
|
||||
// If target_level < 0, automatically calculate the minimum level that could
|
||||
// hold the data set.
|
||||
void ReFitLevel(int level, int target_level = -1);
|
||||
|
||||
// Constant after construction
|
||||
const InternalFilterPolicy internal_filter_policy_;
|
||||
@@ -276,6 +288,9 @@ class DBImpl : public DB {
|
||||
// count how many background compaction been scheduled or is running?
|
||||
int bg_compaction_scheduled_;
|
||||
|
||||
// number of background memtable flush jobs, submitted to the HIGH pool
|
||||
int bg_flush_scheduled_;
|
||||
|
||||
// Has a background stats log thread scheduled?
|
||||
bool bg_logstats_scheduled_;
|
||||
|
||||
@@ -420,7 +435,6 @@ class DBImpl : public DB {
|
||||
Status GetImpl(const ReadOptions& options,
|
||||
const Slice& key,
|
||||
std::string* value,
|
||||
const bool no_io = false,
|
||||
bool* value_found = nullptr);
|
||||
};
|
||||
|
||||
@@ -431,6 +445,4 @@ extern Options SanitizeOptions(const std::string& db,
|
||||
const InternalFilterPolicy* ipolicy,
|
||||
const Options& src);
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_DB_IMPL_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+10
-5
@@ -1,3 +1,8 @@
|
||||
// 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) 2012 Facebook. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
@@ -21,10 +26,10 @@
|
||||
#include "db/table_cache.h"
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "leveldb/table_builder.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/table_builder.h"
|
||||
#include "port/port.h"
|
||||
#include "table/block.h"
|
||||
#include "table/merger.h"
|
||||
@@ -34,7 +39,7 @@
|
||||
#include "util/logging.h"
|
||||
#include "util/build_version.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
DBImplReadOnly::DBImplReadOnly(const Options& options,
|
||||
const std::string& dbname)
|
||||
|
||||
+12
-14
@@ -1,10 +1,13 @@
|
||||
// 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) 2012 Facebook. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_DB_IMPL_READONLY_H_
|
||||
#define STORAGE_LEVELDB_DB_DB_IMPL_READONLY_H_
|
||||
|
||||
#pragma once
|
||||
#include "db/db_impl.h"
|
||||
|
||||
#include <deque>
|
||||
@@ -12,16 +15,12 @@
|
||||
#include "db/dbformat.h"
|
||||
#include "db/log_writer.h"
|
||||
#include "db/snapshot.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "port/port.h"
|
||||
#include "util/stats_logger.h"
|
||||
|
||||
#ifdef USE_SCRIBE
|
||||
#include "scribe/scribe_logger.h"
|
||||
#endif
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class DBImplReadOnly : public DBImpl {
|
||||
public:
|
||||
@@ -51,7 +50,7 @@ public:
|
||||
return Status::NotSupported("Not supported operation in read only mode.");
|
||||
}
|
||||
virtual void CompactRange(const Slice* begin, const Slice* end,
|
||||
bool reduce_level = false) {
|
||||
bool reduce_level = false, int target_level = -1) {
|
||||
}
|
||||
virtual Status DisableFileDeletions() {
|
||||
return Status::NotSupported("Not supported operation in read only mode.");
|
||||
@@ -60,7 +59,8 @@ public:
|
||||
return Status::NotSupported("Not supported operation in read only mode.");
|
||||
}
|
||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
||||
uint64_t* manifest_file_size) {
|
||||
uint64_t* manifest_file_size,
|
||||
bool flush_memtable = true) {
|
||||
return Status::NotSupported("Not supported operation in read only mode.");
|
||||
}
|
||||
virtual Status Flush(const FlushOptions& options) {
|
||||
@@ -76,5 +76,3 @@ private:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+52
-9
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -8,15 +13,16 @@
|
||||
|
||||
#include "db/filename.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/options.h"
|
||||
#include "leveldb/iterator.h"
|
||||
#include "leveldb/merge_operator.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "port/port.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include "util/perf_context_imp.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
#if 0
|
||||
static void DumpInternalIter(Iterator* iter) {
|
||||
@@ -65,6 +71,7 @@ class DBIter: public Iterator {
|
||||
current_entry_is_merged_(false),
|
||||
statistics_(options.statistics) {
|
||||
RecordTick(statistics_, NO_ITERATORS, 1);
|
||||
max_skip_ = options.max_sequential_skip_in_iterations;
|
||||
}
|
||||
virtual ~DBIter() {
|
||||
RecordTick(statistics_, NO_ITERATORS, -1);
|
||||
@@ -129,6 +136,7 @@ class DBIter: public Iterator {
|
||||
bool valid_;
|
||||
bool current_entry_is_merged_;
|
||||
std::shared_ptr<Statistics> statistics_;
|
||||
uint64_t max_skip_;
|
||||
|
||||
// No copying allowed
|
||||
DBIter(const DBIter&);
|
||||
@@ -188,12 +196,14 @@ void DBIter::FindNextUserEntry(bool skipping) {
|
||||
assert(iter_->Valid());
|
||||
assert(direction_ == kForward);
|
||||
current_entry_is_merged_ = false;
|
||||
uint64_t num_skipped = 0;
|
||||
do {
|
||||
ParsedInternalKey ikey;
|
||||
if (ParseKey(&ikey) && ikey.sequence <= sequence_) {
|
||||
if (skipping &&
|
||||
user_comparator_->Compare(ikey.user_key, saved_key_) <= 0) {
|
||||
// skip this entry
|
||||
num_skipped++; // skip this entry
|
||||
BumpPerfCount(&perf_context.internal_key_skipped_count);
|
||||
} else {
|
||||
skipping = false;
|
||||
switch (ikey.type) {
|
||||
@@ -202,6 +212,8 @@ void DBIter::FindNextUserEntry(bool skipping) {
|
||||
// they are hidden by this deletion.
|
||||
SaveKey(ikey.user_key, &saved_key_);
|
||||
skipping = true;
|
||||
num_skipped = 0;
|
||||
BumpPerfCount(&perf_context.internal_delete_skipped_count);
|
||||
break;
|
||||
case kTypeValue:
|
||||
valid_ = true;
|
||||
@@ -220,7 +232,20 @@ void DBIter::FindNextUserEntry(bool skipping) {
|
||||
}
|
||||
}
|
||||
}
|
||||
iter_->Next();
|
||||
// If we have sequentially iterated via numerous keys and still not
|
||||
// found the next user-key, then it is better to seek so that we can
|
||||
// avoid too many key comparisons. We seek to the last occurence of
|
||||
// our current key by looking for sequence number 0.
|
||||
if (skipping && num_skipped > max_skip_) {
|
||||
num_skipped = 0;
|
||||
std::string last_key;
|
||||
AppendInternalKey(&last_key,
|
||||
ParsedInternalKey(Slice(saved_key_), 0, kValueTypeForSeek));
|
||||
iter_->Seek(last_key);
|
||||
RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);
|
||||
} else {
|
||||
iter_->Next();
|
||||
}
|
||||
} while (iter_->Valid());
|
||||
valid_ = false;
|
||||
}
|
||||
@@ -342,11 +367,13 @@ void DBIter::Prev() {
|
||||
|
||||
void DBIter::FindPrevUserEntry() {
|
||||
assert(direction_ == kReverse);
|
||||
uint64_t num_skipped = 0;
|
||||
|
||||
ValueType value_type = kTypeDeletion;
|
||||
if (iter_->Valid()) {
|
||||
do {
|
||||
ParsedInternalKey ikey;
|
||||
bool saved_key_cleared = false;
|
||||
if (ParseKey(&ikey) && ikey.sequence <= sequence_) {
|
||||
if ((value_type != kTypeDeletion) &&
|
||||
user_comparator_->Compare(ikey.user_key, saved_key_) < 0) {
|
||||
@@ -357,6 +384,7 @@ void DBIter::FindPrevUserEntry() {
|
||||
if (value_type == kTypeDeletion) {
|
||||
saved_key_.clear();
|
||||
ClearSavedValue();
|
||||
saved_key_cleared = true;
|
||||
} else {
|
||||
Slice raw_value = iter_->value();
|
||||
if (saved_value_.capacity() > raw_value.size() + 1048576) {
|
||||
@@ -367,7 +395,22 @@ void DBIter::FindPrevUserEntry() {
|
||||
saved_value_.assign(raw_value.data(), raw_value.size());
|
||||
}
|
||||
}
|
||||
iter_->Prev();
|
||||
num_skipped++;
|
||||
// If we have sequentially iterated via numerous keys and still not
|
||||
// found the prev user-key, then it is better to seek so that we can
|
||||
// avoid too many key comparisons. We seek to the first occurence of
|
||||
// our current key by looking for max sequence number.
|
||||
if (!saved_key_cleared && num_skipped > max_skip_) {
|
||||
num_skipped = 0;
|
||||
std::string last_key;
|
||||
AppendInternalKey(&last_key,
|
||||
ParsedInternalKey(Slice(saved_key_), kMaxSequenceNumber,
|
||||
kValueTypeForSeek));
|
||||
iter_->Seek(last_key);
|
||||
RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);
|
||||
} else {
|
||||
iter_->Prev();
|
||||
}
|
||||
} while (iter_->Valid());
|
||||
}
|
||||
|
||||
@@ -435,4 +478,4 @@ Iterator* NewDBIterator(
|
||||
internal_iter, sequence);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+9
-8
@@ -1,15 +1,18 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_DB_ITER_H_
|
||||
#define STORAGE_LEVELDB_DB_DB_ITER_H_
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "leveldb/db.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "db/dbformat.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// Return a new iterator that converts internal keys (yielded by
|
||||
// "*internal_iter") that were live at the specified "sequence" number
|
||||
@@ -22,6 +25,4 @@ extern Iterator* NewDBIterator(
|
||||
Iterator* internal_iter,
|
||||
const SequenceNumber& sequence);
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_DB_ITER_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+9
-10
@@ -1,22 +1,25 @@
|
||||
// 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.
|
||||
|
||||
#ifndef LEVELDB_STORAGE_DB_DB_STATISTICS_H_
|
||||
#define LEVELDB_STORAGE_DB_DB_STATISTICS_H_
|
||||
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "leveldb/statistics.h"
|
||||
#include "rocksdb/statistics.h"
|
||||
#include "util/histogram.h"
|
||||
#include "port/port.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class DBStatistics: public Statistics {
|
||||
public:
|
||||
@@ -59,8 +62,4 @@ std::shared_ptr<Statistics> CreateDBStatistics() {
|
||||
return std::make_shared<DBStatistics>();
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // LEVELDB_STORAGE_DB_DB_STATISTICS_H_
|
||||
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -7,12 +12,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "db/version_set.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "port/port.h"
|
||||
#include "util/mutexlock.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
void DBImpl::MaybeScheduleLogDBDeployStats() {
|
||||
|
||||
|
||||
+780
-128
File diff suppressed because it is too large
Load Diff
+9
-4
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -6,9 +11,9 @@
|
||||
#include "db/dbformat.h"
|
||||
#include "port/port.h"
|
||||
#include "util/coding.h"
|
||||
#include "include/leveldb/perf_context.h"
|
||||
#include "util/perf_context_imp.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
|
||||
assert(seq <= kMaxSequenceNumber);
|
||||
@@ -54,7 +59,7 @@ int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
|
||||
// decreasing sequence number
|
||||
// decreasing type (though sequence# should be enough to disambiguate)
|
||||
int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
|
||||
perf_context.user_key_comparison_count++;
|
||||
BumpPerfCount(&perf_context.user_key_comparison_count);
|
||||
if (r == 0) {
|
||||
const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
|
||||
const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
|
||||
@@ -139,4 +144,4 @@ LookupKey::LookupKey(const Slice& user_key, SequenceNumber s) {
|
||||
end_ = dst;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+15
-14
@@ -1,21 +1,24 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_FORMAT_H_
|
||||
#define STORAGE_LEVELDB_DB_FORMAT_H_
|
||||
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/filter_policy.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/table_builder.h"
|
||||
#include "leveldb/types.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/filter_policy.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/table_builder.h"
|
||||
#include "rocksdb/types.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class InternalKey;
|
||||
|
||||
@@ -90,7 +93,7 @@ class InternalKeyComparator : public Comparator {
|
||||
std::string name_;
|
||||
public:
|
||||
explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c),
|
||||
name_("leveldb.InternalKeyComparator:" +
|
||||
name_("rocksdb.InternalKeyComparator:" +
|
||||
std::string(user_comparator_->Name())) {
|
||||
}
|
||||
|
||||
@@ -223,6 +226,4 @@ inline LookupKey::~LookupKey() {
|
||||
if (start_ != space_) delete[] start_;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_FORMAT_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+8
-3
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -6,7 +11,7 @@
|
||||
#include "util/logging.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static std::string IKey(const std::string& user_key,
|
||||
uint64_t seq,
|
||||
@@ -105,8 +110,8 @@ TEST(FormatTest, InternalKeyShortestSuccessor) {
|
||||
ShortSuccessor(IKey("\xff\xff", 100, kTypeValue)));
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
// 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 "rocksdb/db.h"
|
||||
#include "db/db_impl.h"
|
||||
#include "db/filename.h"
|
||||
#include "db/version_set.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "util/testharness.h"
|
||||
#include "util/testutil.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class DeleteFileTest {
|
||||
public:
|
||||
std::string dbname_;
|
||||
Options options_;
|
||||
DB* db_;
|
||||
Env* env_;
|
||||
int numlevels_;
|
||||
|
||||
DeleteFileTest() {
|
||||
db_ = nullptr;
|
||||
env_ = Env::Default();
|
||||
options_.write_buffer_size = 1024*1024*1000;
|
||||
options_.target_file_size_base = 1024*1024*1000;
|
||||
options_.max_bytes_for_level_base = 1024*1024*1000;
|
||||
dbname_ = test::TmpDir() + "/deletefile_test";
|
||||
DestroyDB(dbname_, options_);
|
||||
numlevels_ = 7;
|
||||
ASSERT_OK(ReopenDB(true));
|
||||
}
|
||||
|
||||
Status ReopenDB(bool create) {
|
||||
delete db_;
|
||||
if (create) {
|
||||
DestroyDB(dbname_, options_);
|
||||
}
|
||||
db_ = nullptr;
|
||||
options_.create_if_missing = create;
|
||||
return DB::Open(options_, dbname_, &db_);
|
||||
}
|
||||
|
||||
void CloseDB() {
|
||||
delete db_;
|
||||
}
|
||||
|
||||
void AddKeys(int numkeys, int startkey = 0) {
|
||||
WriteOptions options;
|
||||
options.sync = false;
|
||||
ReadOptions roptions;
|
||||
for (int i = startkey; i < (numkeys + startkey) ; i++) {
|
||||
std::string temp = std::to_string(i);
|
||||
Slice key(temp);
|
||||
Slice value(temp);
|
||||
ASSERT_OK(db_->Put(options, key, value));
|
||||
}
|
||||
}
|
||||
|
||||
int numKeysInLevels(
|
||||
std::vector<LiveFileMetaData> &metadata,
|
||||
std::vector<int> *keysperlevel = nullptr) {
|
||||
|
||||
if (keysperlevel != nullptr) {
|
||||
keysperlevel->resize(numlevels_);
|
||||
}
|
||||
|
||||
int numKeys = 0;
|
||||
for (size_t i = 0; i < metadata.size(); i++) {
|
||||
int startkey = atoi(metadata[i].smallestkey.c_str());
|
||||
int endkey = atoi(metadata[i].largestkey.c_str());
|
||||
int numkeysinfile = (endkey - startkey + 1);
|
||||
numKeys += numkeysinfile;
|
||||
if (keysperlevel != nullptr) {
|
||||
(*keysperlevel)[(int)metadata[i].level] += numkeysinfile;
|
||||
}
|
||||
fprintf(stderr, "level %d name %s smallest %s largest %s\n",
|
||||
metadata[i].level, metadata[i].name.c_str(),
|
||||
metadata[i].smallestkey.c_str(),
|
||||
metadata[i].largestkey.c_str());
|
||||
}
|
||||
return numKeys;
|
||||
}
|
||||
|
||||
void CreateTwoLevels() {
|
||||
AddKeys(50000, 10000);
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
|
||||
ASSERT_OK(dbi->TEST_FlushMemTable());
|
||||
ASSERT_OK(dbi->TEST_WaitForFlushMemTable());
|
||||
|
||||
AddKeys(50000, 10000);
|
||||
ASSERT_OK(dbi->TEST_FlushMemTable());
|
||||
ASSERT_OK(dbi->TEST_WaitForFlushMemTable());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TEST(DeleteFileTest, AddKeysAndQueryLevels) {
|
||||
CreateTwoLevels();
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
std::vector<int> keysinlevel;
|
||||
db_->GetLiveFilesMetaData(&metadata);
|
||||
|
||||
std::string level1file = "";
|
||||
int level1keycount = 0;
|
||||
std::string level2file = "";
|
||||
int level2keycount = 0;
|
||||
int level1index = 0;
|
||||
int level2index = 1;
|
||||
|
||||
ASSERT_EQ((int)metadata.size(), 2);
|
||||
if (metadata[0].level == 2) {
|
||||
level1index = 1;
|
||||
level2index = 0;
|
||||
}
|
||||
|
||||
level1file = metadata[level1index].name;
|
||||
int startkey = atoi(metadata[level1index].smallestkey.c_str());
|
||||
int endkey = atoi(metadata[level1index].largestkey.c_str());
|
||||
level1keycount = (endkey - startkey + 1);
|
||||
level2file = metadata[level2index].name;
|
||||
startkey = atoi(metadata[level2index].smallestkey.c_str());
|
||||
endkey = atoi(metadata[level2index].largestkey.c_str());
|
||||
level2keycount = (endkey - startkey + 1);
|
||||
|
||||
// COntrolled setup. Levels 1 and 2 should both have 50K files.
|
||||
// This is a little fragile as it depends on the current
|
||||
// compaction heuristics.
|
||||
ASSERT_EQ(level1keycount, 50000);
|
||||
ASSERT_EQ(level2keycount, 50000);
|
||||
|
||||
Status status = db_->DeleteFile("0.sst");
|
||||
ASSERT_TRUE(status.IsInvalidArgument());
|
||||
|
||||
// intermediate level files cannot be deleted.
|
||||
status = db_->DeleteFile(level1file);
|
||||
ASSERT_TRUE(status.IsInvalidArgument());
|
||||
|
||||
// Lowest level file deletion should succeed.
|
||||
ASSERT_OK(db_->DeleteFile(level2file));
|
||||
|
||||
CloseDB();
|
||||
}
|
||||
|
||||
|
||||
TEST(DeleteFileTest, DeleteFileWithIterator) {
|
||||
CreateTwoLevels();
|
||||
ReadOptions options;
|
||||
Iterator* it = db_->NewIterator(options);
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
db_->GetLiveFilesMetaData(&metadata);
|
||||
|
||||
std::string level2file = "";
|
||||
|
||||
ASSERT_EQ((int)metadata.size(), 2);
|
||||
if (metadata[0].level == 1) {
|
||||
level2file = metadata[1].name;
|
||||
} else {
|
||||
level2file = metadata[0].name;
|
||||
}
|
||||
|
||||
Status status = db_->DeleteFile(level2file);
|
||||
fprintf(stdout, "Deletion status %s: %s\n",
|
||||
level2file.c_str(), status.ToString().c_str());
|
||||
ASSERT_TRUE(status.ok());
|
||||
it->SeekToFirst();
|
||||
int numKeysIterated = 0;
|
||||
while(it->Valid()) {
|
||||
numKeysIterated++;
|
||||
it->Next();
|
||||
}
|
||||
ASSERT_EQ(numKeysIterated, 50000);
|
||||
delete it;
|
||||
CloseDB();
|
||||
}
|
||||
} //namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+40
-12
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -7,10 +12,10 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "db/dbformat.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// Given a path, flatten the path name by replacing all chars not in
|
||||
// {[0-9,a-z,A-Z,-,_,.]} with _. And append '\0' at the end.
|
||||
@@ -46,13 +51,10 @@ extern Status WriteStringToFileSync(Env* env, const Slice& data,
|
||||
static std::string MakeFileName(const std::string& name, uint64_t number,
|
||||
const char* suffix) {
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof(buf), "%06llu.%s",
|
||||
snprintf(buf, sizeof(buf), "/%06llu.%s",
|
||||
static_cast<unsigned long long>(number),
|
||||
suffix);
|
||||
if (name.empty()) {
|
||||
return buf;
|
||||
}
|
||||
return name + "/" + buf;
|
||||
return name + buf;
|
||||
}
|
||||
|
||||
std::string LogFileName(const std::string& name, uint64_t number) {
|
||||
@@ -60,12 +62,12 @@ std::string LogFileName(const std::string& name, uint64_t number) {
|
||||
return MakeFileName(name, number, "log");
|
||||
}
|
||||
|
||||
std::string ArchivalDirectory(const std::string& dbname) {
|
||||
return dbname + "/" + ARCHIVAL_DIR;
|
||||
std::string ArchivalDirectory(const std::string& dir) {
|
||||
return dir + "/" + ARCHIVAL_DIR;
|
||||
}
|
||||
std::string ArchivedLogFileName(const std::string& name, uint64_t number) {
|
||||
assert(number > 0);
|
||||
return MakeFileName(name + "/archive", number, "log");
|
||||
return MakeFileName(name + "/" + ARCHIVAL_DIR, number, "log");
|
||||
}
|
||||
|
||||
std::string TableFileName(const std::string& name, uint64_t number) {
|
||||
@@ -125,7 +127,12 @@ std::string MetaDatabaseName(const std::string& dbname, uint64_t number) {
|
||||
return dbname + buf;
|
||||
}
|
||||
|
||||
std::string IdentityFileName(const std::string& dbname) {
|
||||
return dbname + "/IDENTITY";
|
||||
}
|
||||
|
||||
// Owned filenames have the form:
|
||||
// dbname/IDENTITY
|
||||
// dbname/CURRENT
|
||||
// dbname/LOCK
|
||||
// dbname/LOG
|
||||
@@ -133,11 +140,18 @@ std::string MetaDatabaseName(const std::string& dbname, uint64_t number) {
|
||||
// dbname/MANIFEST-[0-9]+
|
||||
// dbname/[0-9]+.(log|sst)
|
||||
// dbname/METADB-[0-9]+
|
||||
// Disregards / at the beginning
|
||||
bool ParseFileName(const std::string& fname,
|
||||
uint64_t* number,
|
||||
FileType* type) {
|
||||
Slice rest(fname);
|
||||
if (rest == "CURRENT") {
|
||||
if (fname.length() > 1 && fname[0] == '/') {
|
||||
rest.remove_prefix(1);
|
||||
}
|
||||
if (rest == "IDENTITY") {
|
||||
*number = 0;
|
||||
*type = kIdentityFile;
|
||||
} else if (rest == "CURRENT") {
|
||||
*number = 0;
|
||||
*type = kCurrentFile;
|
||||
} else if (rest == "LOCK") {
|
||||
@@ -217,4 +231,18 @@ Status SetCurrentFile(Env* env, const std::string& dbname,
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
Status SetIdentityFile(Env* env, const std::string& dbname) {
|
||||
std::string id = env->GenerateUniqueId();
|
||||
assert(!id.empty());
|
||||
std::string tmp = TempFileName(dbname, id.size());
|
||||
Status s = WriteStringToFileSync(env, id, tmp);
|
||||
if (s.ok()) {
|
||||
s = env->RenameFile(tmp, IdentityFileName(dbname));
|
||||
}
|
||||
if (!s.ok()) {
|
||||
env->DeleteFile(tmp);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
+20
-11
@@ -1,19 +1,22 @@
|
||||
// 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.
|
||||
//
|
||||
// File names used by DB code
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_FILENAME_H_
|
||||
#define STORAGE_LEVELDB_DB_FILENAME_H_
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "port/port.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Env;
|
||||
|
||||
@@ -25,7 +28,8 @@ enum FileType {
|
||||
kCurrentFile,
|
||||
kTempFile,
|
||||
kInfoLogFile, // Either the current one, or an old one
|
||||
kMetaDatabase
|
||||
kMetaDatabase,
|
||||
kIdentityFile
|
||||
};
|
||||
|
||||
// Return the name of the log file with the specified number
|
||||
@@ -79,7 +83,12 @@ extern std::string OldInfoLogFileName(const std::string& dbname, uint64_t ts,
|
||||
extern std::string MetaDatabaseName(const std::string& dbname,
|
||||
uint64_t number);
|
||||
|
||||
// If filename is a leveldb file, store the type of the file in *type.
|
||||
// Return the name of the Identity file which stores a unique number for the db
|
||||
// that will get regenerated if the db loses all its data and is recreated fresh
|
||||
// either from a backup-image or empty
|
||||
extern std::string IdentityFileName(const std::string& dbname);
|
||||
|
||||
// If filename is a rocksdb file, store the type of the file in *type.
|
||||
// The number encoded in the filename is stored in *number. If the
|
||||
// filename was successfully parsed, returns true. Else return false.
|
||||
extern bool ParseFileName(const std::string& filename,
|
||||
@@ -91,7 +100,7 @@ extern bool ParseFileName(const std::string& filename,
|
||||
extern Status SetCurrentFile(Env* env, const std::string& dbname,
|
||||
uint64_t descriptor_number);
|
||||
|
||||
// Make the IDENTITY file for the db
|
||||
extern Status SetIdentityFile(Env* env, const std::string& dbname);
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_FILENAME_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+8
-3
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -9,7 +14,7 @@
|
||||
#include "util/logging.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class FileNameTest { };
|
||||
|
||||
@@ -128,8 +133,8 @@ TEST(FileNameTest, Construction) {
|
||||
ASSERT_EQ(kMetaDatabase, type);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -5,10 +10,8 @@
|
||||
// Log format information shared by reader and writer.
|
||||
// See ../doc/log_format.txt for more detail.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_LOG_FORMAT_H_
|
||||
#define STORAGE_LEVELDB_DB_LOG_FORMAT_H_
|
||||
|
||||
namespace leveldb {
|
||||
#pragma once
|
||||
namespace rocksdb {
|
||||
namespace log {
|
||||
|
||||
enum RecordType {
|
||||
@@ -30,6 +33,4 @@ static const unsigned int kBlockSize = 32768;
|
||||
static const int kHeaderSize = 4 + 1 + 2;
|
||||
|
||||
} // namespace log
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_LOG_FORMAT_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+8
-3
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -5,11 +10,11 @@
|
||||
#include "db/log_reader.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/crc32c.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
namespace log {
|
||||
|
||||
Reader::Reporter::~Reporter() {
|
||||
@@ -256,4 +261,4 @@ unsigned int Reader::ReadPhysicalRecord(Slice* result) {
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+10
-9
@@ -1,18 +1,21 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_LOG_READER_H_
|
||||
#define STORAGE_LEVELDB_DB_LOG_READER_H_
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "db/log_format.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class SequentialFile;
|
||||
using std::unique_ptr;
|
||||
@@ -118,6 +121,4 @@ class Reader {
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_LOG_READER_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+9
-4
@@ -1,16 +1,21 @@
|
||||
// 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/log_reader.h"
|
||||
#include "db/log_writer.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/crc32c.h"
|
||||
#include "util/random.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
namespace log {
|
||||
|
||||
// Construct a string of the specified length made out of the supplied
|
||||
@@ -516,8 +521,8 @@ TEST(LogTest, ReadPastEnd) {
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+8
-3
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -5,11 +10,11 @@
|
||||
#include "db/log_writer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/crc32c.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
namespace log {
|
||||
|
||||
Writer::Writer(unique_ptr<WritableFile>&& dest)
|
||||
@@ -100,4 +105,4 @@ Status Writer::EmitPhysicalRecord(RecordType t, const char* ptr, size_t n) {
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+10
-9
@@ -1,17 +1,20 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_LOG_WRITER_H_
|
||||
#define STORAGE_LEVELDB_DB_LOG_WRITER_H_
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include "db/log_format.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class WritableFile;
|
||||
|
||||
@@ -49,6 +52,4 @@ class Writer {
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_LOG_WRITER_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+31
-17
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -7,20 +12,14 @@
|
||||
#include <memory>
|
||||
|
||||
#include "db/dbformat.h"
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/iterator.h"
|
||||
#include "leveldb/merge_operator.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/murmurhash.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
static Slice GetLengthPrefixedSlice(const char* data) {
|
||||
uint32_t len;
|
||||
const char* p = data;
|
||||
p = GetVarint32Ptr(p, p + 5, &len); // +5: we assume "p" is not corrupted
|
||||
return Slice(p, len);
|
||||
}
|
||||
namespace rocksdb {
|
||||
|
||||
MemTable::MemTable(const InternalKeyComparator& cmp,
|
||||
std::shared_ptr<MemTableRepFactory> table_factory,
|
||||
@@ -35,6 +34,7 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
|
||||
file_number_(0),
|
||||
edit_(numlevel),
|
||||
first_seqno_(0),
|
||||
mem_next_logfile_number_(0),
|
||||
mem_logfile_number_(0) { }
|
||||
|
||||
MemTable::~MemTable() {
|
||||
@@ -42,7 +42,8 @@ MemTable::~MemTable() {
|
||||
}
|
||||
|
||||
size_t MemTable::ApproximateMemoryUsage() {
|
||||
return arena_impl_.ApproximateMemoryUsage();
|
||||
return arena_impl_.ApproximateMemoryUsage() +
|
||||
table_->ApproximateMemoryUsage();
|
||||
}
|
||||
|
||||
int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr)
|
||||
@@ -53,6 +54,11 @@ int MemTable::KeyComparator::operator()(const char* aptr, const char* bptr)
|
||||
return comparator.Compare(a, b);
|
||||
}
|
||||
|
||||
Slice MemTableRep::UserKey(const char* key) const {
|
||||
Slice slice = GetLengthPrefixedSlice(key);
|
||||
return Slice(slice.data(), slice.size() - 8);
|
||||
}
|
||||
|
||||
// Encode a suitable internal key target for "target" and return it.
|
||||
// Uses *scratch as scratch space, and the returned pointer will point
|
||||
// into this scratch space.
|
||||
@@ -68,6 +74,9 @@ class MemTableIterator: public Iterator {
|
||||
explicit MemTableIterator(MemTableRep* table)
|
||||
: iter_(table->GetIterator()) { }
|
||||
|
||||
MemTableIterator(MemTableRep* table, const Slice* prefix)
|
||||
: iter_(table->GetPrefixIterator(*prefix)) { }
|
||||
|
||||
virtual bool Valid() const { return iter_->Valid(); }
|
||||
virtual void Seek(const Slice& k) { iter_->Seek(EncodeKey(&tmp_, k)); }
|
||||
virtual void SeekToFirst() { iter_->SeekToFirst(); }
|
||||
@@ -93,8 +102,12 @@ class MemTableIterator: public Iterator {
|
||||
void operator=(const MemTableIterator&);
|
||||
};
|
||||
|
||||
Iterator* MemTable::NewIterator() {
|
||||
return new MemTableIterator(table_.get());
|
||||
Iterator* MemTable::NewIterator(const Slice* prefix) {
|
||||
if (prefix) {
|
||||
return new MemTableIterator(table_.get(), prefix);
|
||||
} else {
|
||||
return new MemTableIterator(table_.get());
|
||||
}
|
||||
}
|
||||
|
||||
void MemTable::Add(SequenceNumber s, ValueType type,
|
||||
@@ -132,7 +145,8 @@ void MemTable::Add(SequenceNumber s, ValueType type,
|
||||
bool MemTable::Get(const LookupKey& key, std::string* value, Status* s,
|
||||
std::deque<std::string>* operands, const Options& options) {
|
||||
Slice memkey = key.memtable_key();
|
||||
std::shared_ptr<MemTableRep::Iterator> iter(table_.get()->GetIterator());
|
||||
std::shared_ptr<MemTableRep::Iterator> iter(
|
||||
table_->GetIterator(key.user_key()));
|
||||
iter->Seek(memkey.data());
|
||||
|
||||
// It is the caller's responsibility to allocate/delete operands list
|
||||
@@ -229,4 +243,4 @@ bool MemTable::Get(const LookupKey& key, std::string* value, Status* s,
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+30
-10
@@ -1,21 +1,24 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_MEMTABLE_H_
|
||||
#define STORAGE_LEVELDB_DB_MEMTABLE_H_
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
#include "db/dbformat.h"
|
||||
#include "db/skiplist.h"
|
||||
#include "db/version_set.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/memtablerep.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/memtablerep.h"
|
||||
#include "util/arena_impl.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Mutex;
|
||||
class MemTableIterator;
|
||||
@@ -61,7 +64,11 @@ class MemTable {
|
||||
// while the returned iterator is live. The keys returned by this
|
||||
// iterator are internal keys encoded by AppendInternalKey in the
|
||||
// db/dbformat.{h,cc} module.
|
||||
Iterator* NewIterator();
|
||||
//
|
||||
// If a prefix is supplied, it is passed to the underlying MemTableRep as a
|
||||
// hint that the iterator only need to support access to keys with that
|
||||
// prefix.
|
||||
Iterator* NewIterator(const Slice* prefix = nullptr);
|
||||
|
||||
// Add an entry into memtable that maps key to value at the
|
||||
// specified sequence number and with the specified type.
|
||||
@@ -88,6 +95,14 @@ class MemTable {
|
||||
// into the memtable
|
||||
SequenceNumber GetFirstSequenceNumber() { return first_seqno_; }
|
||||
|
||||
// Returns the next active logfile number when this memtable is about to
|
||||
// be flushed to storage
|
||||
uint64_t GetNextLogNumber() { return mem_next_logfile_number_; }
|
||||
|
||||
// Sets the next active logfile number when this memtable is about to
|
||||
// be flushed to storage
|
||||
void SetNextLogNumber(uint64_t num) { mem_next_logfile_number_ = num; }
|
||||
|
||||
// Returns the logfile number that can be safely deleted when this
|
||||
// memstore is flushed to storage
|
||||
uint64_t GetLogNumber() { return mem_logfile_number_; }
|
||||
@@ -96,6 +111,9 @@ class MemTable {
|
||||
// memstore is flushed to storage
|
||||
void SetLogNumber(uint64_t num) { mem_logfile_number_ = num; }
|
||||
|
||||
// Notify the underlying storage that no more items will be added
|
||||
void MarkImmutable() { table_->MarkReadOnly(); }
|
||||
|
||||
private:
|
||||
~MemTable(); // Private since only Unref() should be used to delete it
|
||||
friend class MemTableIterator;
|
||||
@@ -120,6 +138,10 @@ class MemTable {
|
||||
SequenceNumber first_seqno_;
|
||||
|
||||
// The log files earlier than this number can be deleted.
|
||||
uint64_t mem_next_logfile_number_;
|
||||
|
||||
// The log file that backs this memtable (to be deleted when
|
||||
// memtable flush is done)
|
||||
uint64_t mem_logfile_number_;
|
||||
|
||||
// No copying allowed
|
||||
@@ -127,6 +149,4 @@ class MemTable {
|
||||
void operator=(const MemTable&);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_MEMTABLE_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+14
-9
@@ -1,16 +1,18 @@
|
||||
// Copyright (c) 2012 Facebook.
|
||||
|
||||
|
||||
// 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.
|
||||
//
|
||||
#include "db/memtablelist.h"
|
||||
|
||||
#include <string>
|
||||
#include "leveldb/db.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "db/memtable.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/iterator.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class InternalKeyComparator;
|
||||
class Mutex;
|
||||
@@ -42,7 +44,8 @@ int MemTableList::size() {
|
||||
// Returns true if there is at least one memtable on which flush has
|
||||
// not yet started.
|
||||
bool MemTableList::IsFlushPending(int min_write_buffer_number_to_merge) {
|
||||
if (num_flush_not_started_ >= min_write_buffer_number_to_merge) {
|
||||
if ((flush_requested_ && num_flush_not_started_ >= 1) ||
|
||||
(num_flush_not_started_ >= min_write_buffer_number_to_merge)) {
|
||||
assert(imm_flush_needed.NoBarrier_Load() != nullptr);
|
||||
return true;
|
||||
}
|
||||
@@ -63,6 +66,7 @@ void MemTableList::PickMemtablesToFlush(std::vector<MemTable*>* ret) {
|
||||
ret->push_back(m);
|
||||
}
|
||||
}
|
||||
flush_requested_ = false; // start-flush request is complete
|
||||
}
|
||||
|
||||
// Record a successful flush in the manifest file
|
||||
@@ -172,6 +176,7 @@ void MemTableList::Add(MemTable* m) {
|
||||
assert(size_ >= num_flush_not_started_);
|
||||
size_++;
|
||||
memlist_.push_front(m);
|
||||
m->MarkImmutable();
|
||||
num_flush_not_started_++;
|
||||
if (num_flush_not_started_ == 1) {
|
||||
imm_flush_needed.Release_Store((void *)1);
|
||||
@@ -207,4 +212,4 @@ void MemTableList::GetMemTables(std::vector<MemTable*>* output) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+17
-10
@@ -1,17 +1,19 @@
|
||||
// Copyright (c) 2012 Facebook.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_MEMTABLELIST_H_
|
||||
#define STORAGE_LEVELDB_DB_MEMTABLELIST_H_
|
||||
// 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include "leveldb/db.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "db/skiplist.h"
|
||||
#include "memtable.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class InternalKeyComparator;
|
||||
class Mutex;
|
||||
@@ -29,7 +31,8 @@ class MemTableList {
|
||||
public:
|
||||
// A list of memtables.
|
||||
MemTableList() : size_(0), num_flush_not_started_(0),
|
||||
commit_in_progress_(false) {
|
||||
commit_in_progress_(false),
|
||||
flush_requested_(false) {
|
||||
imm_flush_needed.Release_Store(nullptr);
|
||||
}
|
||||
~MemTableList() {};
|
||||
@@ -76,6 +79,9 @@ class MemTableList {
|
||||
// Returns the list of underlying memtables.
|
||||
void GetMemTables(std::vector<MemTable*>* list);
|
||||
|
||||
// Request a flush of all existing memtables to storage
|
||||
void FlushRequested() { flush_requested_ = true; }
|
||||
|
||||
// Copying allowed
|
||||
// MemTableList(const MemTableList&);
|
||||
// void operator=(const MemTableList&);
|
||||
@@ -90,8 +96,9 @@ class MemTableList {
|
||||
// committing in progress
|
||||
bool commit_in_progress_;
|
||||
|
||||
// Requested a flush of all memtables to storage
|
||||
bool flush_requested_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_MEMTABLELIST_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+10
-5
@@ -1,12 +1,17 @@
|
||||
// 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.
|
||||
//
|
||||
#include "merge_helper.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/merge_operator.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// PRE: iter points to the first merge type entry
|
||||
// POST: iter points to the first entry beyond the merge process (or the end)
|
||||
@@ -189,4 +194,4 @@ void MergeHelper::MergeUntil(Iterator* iter, SequenceNumber stop_before,
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+9
-4
@@ -1,13 +1,18 @@
|
||||
// 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 MERGE_HELPER_H
|
||||
#define MERGE_HELPER_H
|
||||
|
||||
#include "db/dbformat.h"
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/statistics.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/statistics.h"
|
||||
#include <string>
|
||||
#include <deque>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Comparator;
|
||||
class Iterator;
|
||||
@@ -93,6 +98,6 @@ class MergeHelper {
|
||||
bool success_;
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// 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.
|
||||
//
|
||||
/**
|
||||
* Back-end implementation details specific to the Merge Operator.
|
||||
*
|
||||
* @author Deon Nicholas (dnicholas@fb.com)
|
||||
* Copyright 2013 Facebook
|
||||
*/
|
||||
|
||||
#include "leveldb/merge_operator.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// Given a "real" merge from the library, call the user's
|
||||
// associative merge function one-by-one on each of the operands.
|
||||
@@ -48,4 +50,4 @@ bool AssociativeMergeOperator::PartialMerge(
|
||||
return Merge(key, &left_operand, right_operand, new_value, logger);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+14
-9
@@ -1,12 +1,17 @@
|
||||
// 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.
|
||||
//
|
||||
#include <assert.h>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include "leveldb/cache.h"
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/merge_operator.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "db/db_impl.h"
|
||||
#include "utilities/merge_operators.h"
|
||||
@@ -14,7 +19,7 @@
|
||||
#include "utilities/utility_db.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace leveldb;
|
||||
using namespace rocksdb;
|
||||
|
||||
|
||||
std::shared_ptr<DB> OpenDb(const string& dbname, const bool ttl = false) {
|
||||
@@ -85,7 +90,7 @@ class Counters {
|
||||
}
|
||||
}
|
||||
|
||||
// mapped to a leveldb Delete
|
||||
// mapped to a rocksdb Delete
|
||||
bool remove(const string& key) {
|
||||
auto s = db_->Delete(delete_option_, key);
|
||||
|
||||
@@ -97,7 +102,7 @@ class Counters {
|
||||
}
|
||||
}
|
||||
|
||||
// mapped to a leveldb Get
|
||||
// mapped to a rocksdb Get
|
||||
bool get(const string& key, uint64_t *value) {
|
||||
string str;
|
||||
auto s = db_->Get(get_option_, key, &str);
|
||||
@@ -159,7 +164,7 @@ class MergeBasedCounters : public Counters {
|
||||
merge_option_() {
|
||||
}
|
||||
|
||||
// mapped to a leveldb Merge operation
|
||||
// mapped to a rocksdb Merge operation
|
||||
virtual bool add(const string& key, uint64_t value) override {
|
||||
char encoded[sizeof(uint64_t)];
|
||||
EncodeFixed64(encoded, value);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "include/leveldb/perf_context.h"
|
||||
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
void PerfContext::Reset() {
|
||||
user_key_comparison_count = 0;
|
||||
}
|
||||
|
||||
__thread PerfContext perf_context;
|
||||
|
||||
}
|
||||
+272
-28
@@ -1,20 +1,57 @@
|
||||
// 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.
|
||||
//
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "/usr/include/valgrind/callgrind.h"
|
||||
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/perf_context.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/perf_context.h"
|
||||
#include "util/histogram.h"
|
||||
#include "util/stop_watch.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
|
||||
namespace leveldb {
|
||||
bool FLAGS_random_key = false;
|
||||
bool FLAGS_use_set_based_memetable = false;
|
||||
int FLAGS_total_keys = 100;
|
||||
int FLAGS_write_buffer_size = 1000000000;
|
||||
int FLAGS_max_write_buffer_number = 8;
|
||||
int FLAGS_min_write_buffer_number_to_merge = 7;
|
||||
|
||||
// Path to the database on file system
|
||||
const std::string kDbName = test::TmpDir() + "/perf_context_test";
|
||||
const std::string kDbName = rocksdb::test::TmpDir() + "/perf_context_test";
|
||||
|
||||
void SeekToFirst(rocksdb::Iterator* iter) {
|
||||
// std::cout << "Press a key to continue:";
|
||||
// std::string s;
|
||||
// std::cin >> s;
|
||||
iter->SeekToFirst();
|
||||
// std::cout << "Press a key to continue:";
|
||||
// std::string s2;
|
||||
// std::cin >> s2;
|
||||
}
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
std::shared_ptr<DB> OpenDb() {
|
||||
DB* db;
|
||||
Options options;
|
||||
options.create_if_missing = true;
|
||||
options.write_buffer_size = 1000000000; // give it a big memtable
|
||||
options.write_buffer_size = FLAGS_write_buffer_size;
|
||||
options.max_write_buffer_number = FLAGS_max_write_buffer_number;
|
||||
options.min_write_buffer_number_to_merge =
|
||||
FLAGS_min_write_buffer_number_to_merge;
|
||||
|
||||
if (FLAGS_use_set_based_memetable) {
|
||||
auto prefix_extractor = rocksdb::NewFixedPrefixTransform(0);
|
||||
options.memtable_factory =
|
||||
std::make_shared<rocksdb::PrefixHashRepFactory>(prefix_extractor);
|
||||
}
|
||||
|
||||
Status s = DB::Open(options, kDbName, &db);
|
||||
ASSERT_OK(s);
|
||||
return std::shared_ptr<DB>(db);
|
||||
@@ -22,10 +59,125 @@ std::shared_ptr<DB> OpenDb() {
|
||||
|
||||
class PerfContextTest { };
|
||||
|
||||
int kTotalKeys = 100;
|
||||
TEST(PerfContextTest, SeekIntoDeletion) {
|
||||
DestroyDB(kDbName, Options());
|
||||
auto db = OpenDb();
|
||||
WriteOptions write_options;
|
||||
ReadOptions read_options;
|
||||
|
||||
TEST(PerfContextTest, KeyComparisonCount) {
|
||||
for (int i = 0; i < FLAGS_total_keys; ++i) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string value = "v" + std::to_string(i);
|
||||
|
||||
db->Put(write_options, key, value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < FLAGS_total_keys -1 ; ++i) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
db->Delete(write_options, key);
|
||||
}
|
||||
|
||||
HistogramImpl hist_get;
|
||||
HistogramImpl hist_get_time;
|
||||
for (int i = 0; i < FLAGS_total_keys - 1; ++i) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string value;
|
||||
|
||||
perf_context.Reset();
|
||||
StopWatchNano timer(Env::Default(), true);
|
||||
auto status = db->Get(read_options, key, &value);
|
||||
auto elapsed_nanos = timer.ElapsedNanos();
|
||||
ASSERT_TRUE(status.IsNotFound());
|
||||
hist_get.Add(perf_context.user_key_comparison_count);
|
||||
hist_get_time.Add(elapsed_nanos);
|
||||
}
|
||||
|
||||
std::cout << "Get uesr key comparison: \n" << hist_get.ToString()
|
||||
<< "Get time: \n" << hist_get_time.ToString();
|
||||
|
||||
HistogramImpl hist_seek_to_first;
|
||||
std::unique_ptr<Iterator> iter(db->NewIterator(read_options));
|
||||
|
||||
perf_context.Reset();
|
||||
StopWatchNano timer(Env::Default(), true);
|
||||
//CALLGRIND_ZERO_STATS;
|
||||
SeekToFirst(iter.get());
|
||||
//iter->SeekToFirst();
|
||||
//CALLGRIND_DUMP_STATS;
|
||||
hist_seek_to_first.Add(perf_context.user_key_comparison_count);
|
||||
auto elapsed_nanos = timer.ElapsedNanos();
|
||||
|
||||
std::cout << "SeekToFirst uesr key comparison: \n" << hist_seek_to_first.ToString()
|
||||
<< "ikey skipped: " << perf_context.internal_key_skipped_count << "\n"
|
||||
<< "idelete skipped: " << perf_context.internal_delete_skipped_count << "\n"
|
||||
<< "elapsed: " << elapsed_nanos << "\n";
|
||||
|
||||
HistogramImpl hist_seek;
|
||||
for (int i = 0; i < FLAGS_total_keys; ++i) {
|
||||
std::unique_ptr<Iterator> iter(db->NewIterator(read_options));
|
||||
std::string key = "k" + std::to_string(i);
|
||||
|
||||
perf_context.Reset();
|
||||
StopWatchNano timer(Env::Default(), true);
|
||||
iter->Seek(key);
|
||||
auto elapsed_nanos = timer.ElapsedNanos();
|
||||
hist_seek.Add(perf_context.user_key_comparison_count);
|
||||
std::cout << "seek cmp: " << perf_context.user_key_comparison_count
|
||||
<< " ikey skipped " << perf_context.internal_key_skipped_count
|
||||
<< " idelete skipped " << perf_context.internal_delete_skipped_count
|
||||
<< " elapsed: " << elapsed_nanos << "ns\n";
|
||||
|
||||
perf_context.Reset();
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
StopWatchNano timer2(Env::Default(), true);
|
||||
iter->Next();
|
||||
auto elapsed_nanos2 = timer2.ElapsedNanos();
|
||||
std::cout << "next cmp: " << perf_context.user_key_comparison_count
|
||||
<< "elapsed: " << elapsed_nanos2 << "ns\n";
|
||||
}
|
||||
|
||||
std::cout << "Seek uesr key comparison: \n" << hist_seek.ToString();
|
||||
}
|
||||
|
||||
TEST(PerfContextTest, StopWatchNanoOverhead) {
|
||||
// profile the timer cost by itself!
|
||||
const int kTotalIterations = 1000000;
|
||||
std::vector<uint64_t> timings(kTotalIterations);
|
||||
|
||||
StopWatchNano timer(Env::Default(), true);
|
||||
for (auto& timing : timings) {
|
||||
timing = timer.ElapsedNanos(true /* reset */);
|
||||
}
|
||||
|
||||
HistogramImpl histogram;
|
||||
for (const auto timing : timings) {
|
||||
histogram.Add(timing);
|
||||
}
|
||||
|
||||
std::cout << histogram.ToString();
|
||||
}
|
||||
|
||||
TEST(PerfContextTest, StopWatchOverhead) {
|
||||
// profile the timer cost by itself!
|
||||
const int kTotalIterations = 1000000;
|
||||
std::vector<uint64_t> timings(kTotalIterations);
|
||||
|
||||
StopWatch timer(Env::Default());
|
||||
for (auto& timing : timings) {
|
||||
timing = timer.ElapsedMicros();
|
||||
}
|
||||
|
||||
HistogramImpl histogram;
|
||||
uint64_t prev_timing = 0;
|
||||
for (const auto timing : timings) {
|
||||
histogram.Add(timing - prev_timing);
|
||||
prev_timing = timing;
|
||||
}
|
||||
|
||||
std::cout << histogram.ToString();
|
||||
}
|
||||
|
||||
void ProfileKeyComparison() {
|
||||
DestroyDB(kDbName, Options()); // Start this test with a fresh DB
|
||||
|
||||
auto db = OpenDb();
|
||||
@@ -33,49 +185,141 @@ TEST(PerfContextTest, KeyComparisonCount) {
|
||||
WriteOptions write_options;
|
||||
ReadOptions read_options;
|
||||
|
||||
uint64_t total_user_key_comparison_get = 0;
|
||||
uint64_t total_user_key_comparison_put = 0;
|
||||
uint64_t max_user_key_comparison_get = 0;
|
||||
HistogramImpl hist_put;
|
||||
HistogramImpl hist_get;
|
||||
|
||||
std::cout << "Inserting " << kTotalKeys << " key/value pairs\n...\n";
|
||||
std::cout << "Inserting " << FLAGS_total_keys << " key/value pairs\n...\n";
|
||||
|
||||
for (int i = 0; i < kTotalKeys; ++i) {
|
||||
std::vector<int> keys;
|
||||
for (int i = 0; i < FLAGS_total_keys; ++i) {
|
||||
keys.push_back(i);
|
||||
}
|
||||
|
||||
if (FLAGS_random_key) {
|
||||
std::random_shuffle(keys.begin(), keys.end());
|
||||
}
|
||||
|
||||
for (const int i : keys) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string value = "v" + std::to_string(i);
|
||||
|
||||
perf_context.Reset();
|
||||
db->Put(write_options, key, value);
|
||||
total_user_key_comparison_put += perf_context.user_key_comparison_count;
|
||||
hist_put.Add(perf_context.user_key_comparison_count);
|
||||
|
||||
perf_context.Reset();
|
||||
db->Get(read_options, key, &value);
|
||||
total_user_key_comparison_get += perf_context.user_key_comparison_count;
|
||||
max_user_key_comparison_get =
|
||||
std::max(max_user_key_comparison_get,
|
||||
perf_context.user_key_comparison_count);
|
||||
hist_get.Add(perf_context.user_key_comparison_count);
|
||||
}
|
||||
|
||||
std::cout << "total user key comparison get: "
|
||||
<< total_user_key_comparison_get << "\n"
|
||||
<< "total user key comparison put: "
|
||||
<< total_user_key_comparison_put << "\n"
|
||||
<< "max user key comparison get: "
|
||||
<< max_user_key_comparison_get << "\n"
|
||||
<< "avg user key comparison get:"
|
||||
<< total_user_key_comparison_get/kTotalKeys << "\n";
|
||||
std::cout << "Put uesr key comparison: \n" << hist_put.ToString()
|
||||
<< "Get uesr key comparison: \n" << hist_get.ToString();
|
||||
|
||||
}
|
||||
|
||||
TEST(PerfContextTest, KeyComparisonCount) {
|
||||
SetPerfLevel(kEnableCount);
|
||||
ProfileKeyComparison();
|
||||
|
||||
SetPerfLevel(kDisable);
|
||||
ProfileKeyComparison();
|
||||
|
||||
SetPerfLevel(kEnableTime);
|
||||
ProfileKeyComparison();
|
||||
}
|
||||
|
||||
// make perf_context_test
|
||||
// export ROCKSDB_TESTS=PerfContextTest.SeekKeyComparison
|
||||
// For one memtable:
|
||||
// ./perf_context_test --write_buffer_size=500000 --total_keys=10000
|
||||
// For two memtables:
|
||||
// ./perf_context_test --write_buffer_size=250000 --total_keys=10000
|
||||
// Specify --random_key=1 to shuffle the key before insertion
|
||||
// Results show that, for sequential insertion, worst-case Seek Key comparison
|
||||
// is close to the total number of keys (linear), when there is only one
|
||||
// memtable. When there are two memtables, even the avg Seek Key comparison
|
||||
// starts to become linear to the input size.
|
||||
|
||||
TEST(PerfContextTest, SeekKeyComparison) {
|
||||
DestroyDB(kDbName, Options());
|
||||
auto db = OpenDb();
|
||||
WriteOptions write_options;
|
||||
ReadOptions read_options;
|
||||
|
||||
std::cout << "Inserting " << FLAGS_total_keys << " key/value pairs\n...\n";
|
||||
|
||||
std::vector<int> keys;
|
||||
for (int i = 0; i < FLAGS_total_keys; ++i) {
|
||||
keys.push_back(i);
|
||||
}
|
||||
|
||||
if (FLAGS_random_key) {
|
||||
std::random_shuffle(keys.begin(), keys.end());
|
||||
}
|
||||
|
||||
for (const int i : keys) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string value = "v" + std::to_string(i);
|
||||
|
||||
db->Put(write_options, key, value);
|
||||
}
|
||||
|
||||
HistogramImpl hist_seek;
|
||||
HistogramImpl hist_next;
|
||||
|
||||
for (int i = 0; i < FLAGS_total_keys; ++i) {
|
||||
std::string key = "k" + std::to_string(i);
|
||||
std::string value = "v" + std::to_string(i);
|
||||
|
||||
std::unique_ptr<Iterator> iter(db->NewIterator(read_options));
|
||||
perf_context.Reset();
|
||||
iter->Seek(key);
|
||||
ASSERT_TRUE(iter->Valid());
|
||||
ASSERT_EQ(iter->value().ToString(), value);
|
||||
hist_seek.Add(perf_context.user_key_comparison_count);
|
||||
}
|
||||
|
||||
std::unique_ptr<Iterator> iter(db->NewIterator(read_options));
|
||||
for (iter->SeekToFirst(); iter->Valid();) {
|
||||
perf_context.Reset();
|
||||
iter->Next();
|
||||
hist_next.Add(perf_context.user_key_comparison_count);
|
||||
}
|
||||
|
||||
std::cout << "Seek:\n" << hist_seek.ToString()
|
||||
<< "Next:\n" << hist_next.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
if (argc > 1) {
|
||||
leveldb::kTotalKeys = std::stoi(argv[1]);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
int n;
|
||||
char junk;
|
||||
|
||||
if (sscanf(argv[i], "--write_buffer_size=%d%c", &n, &junk) == 1) {
|
||||
FLAGS_write_buffer_size = n;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--total_keys=%d%c", &n, &junk) == 1) {
|
||||
FLAGS_total_keys = n;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--random_key=%d%c", &n, &junk) == 1 &&
|
||||
(n == 0 || n == 1)) {
|
||||
FLAGS_random_key = n;
|
||||
}
|
||||
|
||||
if (sscanf(argv[i], "--use_set_based_memetable=%d%c", &n, &junk) == 1 &&
|
||||
(n == 0 || n == 1)) {
|
||||
FLAGS_use_set_based_memetable = n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
leveldb::test::RunAllTests();
|
||||
std::cout << kDbName << "\n";
|
||||
|
||||
rocksdb::test::RunAllTests();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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.
|
||||
// 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.
|
||||
//
|
||||
// Wrap an underlying iterator, but exclude any results not starting
|
||||
// with a given prefix. Seeking to keys not beginning with the prefix
|
||||
@@ -9,12 +10,10 @@
|
||||
// underlying iterator would if there happened to be no non-matching
|
||||
// keys in the dataset.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_PREFIX_FILTER_ITERATOR_H_
|
||||
#define STORAGE_LEVELDB_DB_PREFIX_FILTER_ITERATOR_H_
|
||||
#pragma once
|
||||
#include "rocksdb/iterator.h"
|
||||
|
||||
#include "leveldb/iterator.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class PrefixFilterIterator : public Iterator {
|
||||
private:
|
||||
@@ -71,6 +70,4 @@ class PrefixFilterIterator : public Iterator {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif
|
||||
} // namespace rocksdb
|
||||
|
||||
+12
-7
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -34,11 +39,11 @@
|
||||
#include "db/table_cache.h"
|
||||
#include "db/version_edit.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "leveldb/comparator.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/comparator.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -74,7 +79,7 @@ class Repairer {
|
||||
bytes += tables_[i].meta.file_size;
|
||||
}
|
||||
Log(options_.info_log,
|
||||
"**** Repaired leveldb %s; "
|
||||
"**** Repaired rocksdb %s; "
|
||||
"recovered %d files; %llu bytes. "
|
||||
"Some data may have been lost. "
|
||||
"****",
|
||||
@@ -221,7 +226,7 @@ class Repairer {
|
||||
Iterator* iter = mem->NewIterator();
|
||||
status = BuildTable(dbname_, env_, options_, storage_options_,
|
||||
table_cache_, iter, &meta,
|
||||
icmp_.user_comparator(), 0, 0);
|
||||
icmp_.user_comparator(), 0, 0, true);
|
||||
delete iter;
|
||||
mem->Unref();
|
||||
mem = nullptr;
|
||||
@@ -383,4 +388,4 @@ Status RepairDB(const std::string& dbname, const Options& options) {
|
||||
return repairer.Run();
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+18
-7
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -25,15 +30,13 @@
|
||||
// ... prev vs. next pointer ordering ...
|
||||
//
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_SKIPLIST_H_
|
||||
#define STORAGE_LEVELDB_DB_SKIPLIST_H_
|
||||
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "port/port.h"
|
||||
#include "util/random.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
template<typename Key, class Comparator>
|
||||
class SkipList {
|
||||
@@ -107,6 +110,7 @@ class SkipList {
|
||||
|
||||
// Used for optimizing sequential insert patterns
|
||||
Node* prev_[kMaxHeight];
|
||||
int prev_height_;
|
||||
|
||||
inline int GetMaxHeight() const {
|
||||
return static_cast<int>(
|
||||
@@ -267,6 +271,10 @@ typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOr
|
||||
Node* x = prev[0];
|
||||
Node* next = x->Next(0);
|
||||
if ((x == head_) || KeyIsAfterNode(key, x)) {
|
||||
// Adjust all relevant insertion points to the previous entry
|
||||
for (int i = 1; i < prev_height_; i++) {
|
||||
prev[i] = x;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
}
|
||||
@@ -275,6 +283,9 @@ typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOr
|
||||
int level = GetMaxHeight() - 1;
|
||||
while (true) {
|
||||
Node* next = x->Next(level);
|
||||
// Make sure the lists are sorted.
|
||||
// If x points to head_ or next points nullptr, it is trivially satisfied.
|
||||
assert((x == head_) || (next == nullptr) || KeyIsAfterNode(next->key, x));
|
||||
if (KeyIsAfterNode(key, next)) {
|
||||
// Keep searching in this list
|
||||
x = next;
|
||||
@@ -337,6 +348,7 @@ SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)
|
||||
arena_(arena),
|
||||
head_(NewNode(0 /* any key will do */, kMaxHeight)),
|
||||
max_height_(reinterpret_cast<void*>(1)),
|
||||
prev_height_(1),
|
||||
rnd_(0xdeadbeef) {
|
||||
for (int i = 0; i < kMaxHeight; i++) {
|
||||
head_->SetNext(i, nullptr);
|
||||
@@ -378,6 +390,7 @@ void SkipList<Key,Comparator>::Insert(const Key& key) {
|
||||
prev_[i]->SetNext(i, x);
|
||||
}
|
||||
prev_[0] = x;
|
||||
prev_height_ = height;
|
||||
}
|
||||
|
||||
template<typename Key, class Comparator>
|
||||
@@ -390,6 +403,4 @@ bool SkipList<Key,Comparator>::Contains(const Key& key) const {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_SKIPLIST_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+9
-4
@@ -1,16 +1,21 @@
|
||||
// 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/skiplist.h"
|
||||
#include <set>
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/arena_impl.h"
|
||||
#include "util/hash.h"
|
||||
#include "util/random.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
typedef uint64_t Key;
|
||||
|
||||
@@ -371,8 +376,8 @@ TEST(SkipTest, Concurrent3) { RunConcurrent(3); }
|
||||
TEST(SkipTest, Concurrent4) { RunConcurrent(4); }
|
||||
TEST(SkipTest, Concurrent5) { RunConcurrent(5); }
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+9
-8
@@ -1,13 +1,16 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_SNAPSHOT_H_
|
||||
#define STORAGE_LEVELDB_DB_SNAPSHOT_H_
|
||||
#pragma once
|
||||
#include "rocksdb/db.h"
|
||||
|
||||
#include "leveldb/db.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class SnapshotList;
|
||||
|
||||
@@ -80,6 +83,4 @@ class SnapshotList {
|
||||
SnapshotImpl list_;
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_SNAPSHOT_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+38
-11
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -6,12 +11,12 @@
|
||||
|
||||
#include "db/filename.h"
|
||||
|
||||
#include "leveldb/statistics.h"
|
||||
#include "rocksdb/statistics.h"
|
||||
#include "table/table.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/stop_watch.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static void DeleteEntry(const Slice& key, void* value) {
|
||||
Table* table = reinterpret_cast<Table*>(value);
|
||||
@@ -32,7 +37,10 @@ TableCache::TableCache(const std::string& dbname,
|
||||
dbname_(dbname),
|
||||
options_(options),
|
||||
storage_options_(storage_options),
|
||||
cache_(NewLRUCache(entries, options->table_cache_numshardbits)) {}
|
||||
cache_(
|
||||
NewLRUCache(entries, options->table_cache_numshardbits,
|
||||
options->table_cache_remove_scan_count_limit)) {
|
||||
}
|
||||
|
||||
TableCache::~TableCache() {
|
||||
}
|
||||
@@ -48,7 +56,7 @@ Status TableCache::FindTable(const EnvOptions& toptions,
|
||||
*handle = cache_->Lookup(key);
|
||||
if (*handle == nullptr) {
|
||||
if (no_io) { // Dont do IO and return a not-found status
|
||||
return Status::NotFound("Table not found in table_cache, no_io is set");
|
||||
return Status::Incomplete("Table not found in table_cache, no_io is set");
|
||||
}
|
||||
if (table_io != nullptr) {
|
||||
*table_io = true; // we had to do IO from storage
|
||||
@@ -90,7 +98,8 @@ Iterator* TableCache::NewIterator(const ReadOptions& options,
|
||||
}
|
||||
|
||||
Cache::Handle* handle = nullptr;
|
||||
Status s = FindTable(toptions, file_number, file_size, &handle);
|
||||
Status s = FindTable(toptions, file_number, file_size, &handle,
|
||||
nullptr, options.read_tier == kBlockCacheTier);
|
||||
if (!s.ok()) {
|
||||
return NewErrorIterator(s);
|
||||
}
|
||||
@@ -117,17 +126,17 @@ Status TableCache::Get(const ReadOptions& options,
|
||||
void* arg,
|
||||
bool (*saver)(void*, const Slice&, const Slice&, bool),
|
||||
bool* table_io,
|
||||
void (*mark_key_may_exist)(void*),
|
||||
const bool no_io) {
|
||||
void (*mark_key_may_exist)(void*)) {
|
||||
Cache::Handle* handle = nullptr;
|
||||
Status s = FindTable(storage_options_, file_number, file_size,
|
||||
&handle, table_io, no_io);
|
||||
&handle, table_io,
|
||||
options.read_tier == kBlockCacheTier);
|
||||
if (s.ok()) {
|
||||
Table* t =
|
||||
reinterpret_cast<Table*>(cache_->Value(handle));
|
||||
s = t->InternalGet(options, k, arg, saver, mark_key_may_exist, no_io);
|
||||
s = t->InternalGet(options, k, arg, saver, mark_key_may_exist);
|
||||
cache_->Release(handle);
|
||||
} else if (no_io && s.IsNotFound()) {
|
||||
} else if (options.read_tier && s.IsIncomplete()) {
|
||||
// Couldnt find Table in cache but treat as kFound if no_io set
|
||||
(*mark_key_may_exist)(arg);
|
||||
return Status::OK();
|
||||
@@ -135,10 +144,28 @@ Status TableCache::Get(const ReadOptions& options,
|
||||
return s;
|
||||
}
|
||||
|
||||
bool TableCache::PrefixMayMatch(const ReadOptions& options,
|
||||
uint64_t file_number,
|
||||
uint64_t file_size,
|
||||
const Slice& internal_prefix,
|
||||
bool* table_io) {
|
||||
Cache::Handle* handle = nullptr;
|
||||
Status s = FindTable(storage_options_, file_number,
|
||||
file_size, &handle, table_io);
|
||||
bool may_match = true;
|
||||
if (s.ok()) {
|
||||
Table* t =
|
||||
reinterpret_cast<Table*>(cache_->Value(handle));
|
||||
may_match = t->PrefixMayMatch(internal_prefix);
|
||||
cache_->Release(handle);
|
||||
}
|
||||
return may_match;
|
||||
}
|
||||
|
||||
void TableCache::Evict(uint64_t file_number) {
|
||||
char buf[sizeof(file_number)];
|
||||
EncodeFixed64(buf, file_number);
|
||||
cache_->Erase(Slice(buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+17
-11
@@ -1,21 +1,24 @@
|
||||
// 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.
|
||||
//
|
||||
// Thread-safe (provides internal synchronization)
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_TABLE_CACHE_H_
|
||||
#define STORAGE_LEVELDB_DB_TABLE_CACHE_H_
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "db/dbformat.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/cache.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "port/port.h"
|
||||
#include "table/table.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Env;
|
||||
|
||||
@@ -49,8 +52,13 @@ class TableCache {
|
||||
void* arg,
|
||||
bool (*handle_result)(void*, const Slice&, const Slice&, bool),
|
||||
bool* table_io,
|
||||
void (*mark_key_may_exist)(void*) = nullptr,
|
||||
const bool no_io = false);
|
||||
void (*mark_key_may_exist)(void*) = nullptr);
|
||||
|
||||
// Determine whether the table may contain the specified prefix. If
|
||||
// the table index of blooms are not in memory, this may cause an I/O
|
||||
bool PrefixMayMatch(const ReadOptions& options, uint64_t file_number,
|
||||
uint64_t file_size, const Slice& internal_prefix,
|
||||
bool* table_io);
|
||||
|
||||
// Evict any entry for the specified file number
|
||||
void Evict(uint64_t file_number);
|
||||
@@ -67,6 +75,4 @@ class TableCache {
|
||||
const bool no_io = false);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_TABLE_CACHE_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+140
-69
@@ -1,16 +1,21 @@
|
||||
// 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.
|
||||
//
|
||||
#include "db/transaction_log_impl.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
TransactionLogIteratorImpl::TransactionLogIteratorImpl(
|
||||
const std::string& dbname,
|
||||
const std::string& dir,
|
||||
const Options* options,
|
||||
const EnvOptions& soptions,
|
||||
const SequenceNumber seq,
|
||||
std::unique_ptr<VectorLogPtr> files,
|
||||
SequenceNumber const * const lastFlushedSequence) :
|
||||
dbname_(dbname),
|
||||
dir_(dir),
|
||||
options_(options),
|
||||
soptions_(soptions),
|
||||
startingSequenceNumber_(seq),
|
||||
@@ -18,31 +23,34 @@ TransactionLogIteratorImpl::TransactionLogIteratorImpl(
|
||||
started_(false),
|
||||
isValid_(false),
|
||||
currentFileIndex_(0),
|
||||
currentBatchSeq_(0),
|
||||
currentBatchCount_(0),
|
||||
lastFlushedSequence_(lastFlushedSequence) {
|
||||
assert(startingSequenceNumber_ <= *lastFlushedSequence_);
|
||||
assert(files_.get() != nullptr);
|
||||
assert(files_ != nullptr);
|
||||
|
||||
reporter_.env = options_->env;
|
||||
reporter_.info_log = options_->info_log.get();
|
||||
SeekToStartSequence(); // Seek till starting sequence
|
||||
}
|
||||
|
||||
Status TransactionLogIteratorImpl::OpenLogFile(
|
||||
const LogFile* logFile,
|
||||
unique_ptr<SequentialFile>* file) {
|
||||
const LogFile* logFile,
|
||||
unique_ptr<SequentialFile>* file) {
|
||||
Env* env = options_->env;
|
||||
if (logFile->Type() == kArchivedLogFile) {
|
||||
std::string fname = ArchivedLogFileName(dbname_, logFile->LogNumber());
|
||||
std::string fname = ArchivedLogFileName(dir_, logFile->LogNumber());
|
||||
return env->NewSequentialFile(fname, file, soptions_);
|
||||
} else {
|
||||
std::string fname = LogFileName(dbname_, logFile->LogNumber());
|
||||
std::string fname = LogFileName(dir_, logFile->LogNumber());
|
||||
Status status = env->NewSequentialFile(fname, file, soptions_);
|
||||
if (!status.ok()) {
|
||||
// If cannot open file in DB directory.
|
||||
// Try the archive dir, as it could have moved in the meanwhile.
|
||||
fname = ArchivedLogFileName(dbname_, logFile->LogNumber());
|
||||
fname = ArchivedLogFileName(dir_, logFile->LogNumber());
|
||||
status = env->NewSequentialFile(fname, file, soptions_);
|
||||
if (!status.ok()) {
|
||||
return Status::IOError(" Requested file not present in the dir");
|
||||
return Status::IOError("Requested file not present in the dir");
|
||||
}
|
||||
}
|
||||
return status;
|
||||
@@ -52,7 +60,7 @@ Status TransactionLogIteratorImpl::OpenLogFile(
|
||||
BatchResult TransactionLogIteratorImpl::GetBatch() {
|
||||
assert(isValid_); // cannot call in a non valid state.
|
||||
BatchResult result;
|
||||
result.sequence = currentSequence_;
|
||||
result.sequence = currentBatchSeq_;
|
||||
result.writeBatchPtr = std::move(currentBatch_);
|
||||
return result;
|
||||
}
|
||||
@@ -65,92 +73,155 @@ bool TransactionLogIteratorImpl::Valid() {
|
||||
return started_ && isValid_;
|
||||
}
|
||||
|
||||
void TransactionLogIteratorImpl::Next() {
|
||||
LogFile* currentLogFile = files_.get()->at(currentFileIndex_).get();
|
||||
bool TransactionLogIteratorImpl::RestrictedRead(
|
||||
Slice* record,
|
||||
std::string* scratch) {
|
||||
// Don't read if no more complete entries to read from logs
|
||||
if (currentBatchSeq_ >= *lastFlushedSequence_) {
|
||||
return false;
|
||||
}
|
||||
return currentLogReader_->ReadRecord(record, scratch);
|
||||
}
|
||||
|
||||
// First seek to the given seqNo. in the current file.
|
||||
void TransactionLogIteratorImpl::SeekToStartSequence(
|
||||
uint64_t startFileIndex,
|
||||
bool strict) {
|
||||
std::string scratch;
|
||||
Slice record;
|
||||
if (!started_) {
|
||||
started_ = true; // this piece only runs onced.
|
||||
isValid_ = false;
|
||||
if (startingSequenceNumber_ > *lastFlushedSequence_) {
|
||||
currentStatus_ = Status::IOError("Looking for a sequence, "
|
||||
"which is not flushed yet.");
|
||||
return;
|
||||
started_ = false;
|
||||
isValid_ = false;
|
||||
if (startingSequenceNumber_ > *lastFlushedSequence_) {
|
||||
currentStatus_ = Status::IOError("Looking for a sequence, "
|
||||
"which is not flushed yet.");
|
||||
return;
|
||||
}
|
||||
if (files_->size() <= startFileIndex) {
|
||||
return;
|
||||
}
|
||||
Status s = OpenLogReader(files_->at(startFileIndex).get());
|
||||
if (!s.ok()) {
|
||||
currentStatus_ = s;
|
||||
return;
|
||||
}
|
||||
while (RestrictedRead(&record, &scratch)) {
|
||||
if (record.size() < 12) {
|
||||
reporter_.Corruption(
|
||||
record.size(), Status::Corruption("very small log record"));
|
||||
continue;
|
||||
}
|
||||
Status s = OpenLogReader(currentLogFile);
|
||||
if (!s.ok()) {
|
||||
currentStatus_ = s;
|
||||
UpdateCurrentWriteBatch(record);
|
||||
if (currentBatchSeq_ + currentBatchCount_ - 1 >=
|
||||
startingSequenceNumber_) {
|
||||
if (strict && currentBatchSeq_ != startingSequenceNumber_) {
|
||||
currentStatus_ = Status::Corruption("Gap in sequence number. Could not "
|
||||
"seek to required sequence number");
|
||||
reporter_.Info(currentStatus_.ToString().c_str());
|
||||
return;
|
||||
} else if (strict) {
|
||||
reporter_.Info("Could seek required sequence number. Iterator will "
|
||||
"continue.");
|
||||
}
|
||||
isValid_ = true;
|
||||
started_ = true; // set started_ as we could seek till starting sequence
|
||||
return;
|
||||
} else {
|
||||
isValid_ = false;
|
||||
return;
|
||||
}
|
||||
while (currentLogReader_->ReadRecord(&record, &scratch)) {
|
||||
if (record.size() < 12) {
|
||||
reporter_.Corruption(
|
||||
record.size(), Status::Corruption("log record too small"));
|
||||
continue;
|
||||
}
|
||||
UpdateCurrentWriteBatch(record);
|
||||
if (currentSequence_ >= startingSequenceNumber_) {
|
||||
assert(currentSequence_ <= *lastFlushedSequence_);
|
||||
isValid_ = true;
|
||||
break;
|
||||
} else {
|
||||
isValid_ = false;
|
||||
}
|
||||
}
|
||||
if (isValid_) {
|
||||
// Done for this iteration
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool openNextFile = true;
|
||||
while(openNextFile) {
|
||||
// Could not find start sequence in first file. Normally this must be the
|
||||
// only file. Otherwise log the error and let the iterator return next entry
|
||||
if (files_->size() != 1) {
|
||||
currentStatus_ = Status::Corruption("Start sequence was not found, "
|
||||
"skipping to the next available");
|
||||
reporter_.Corruption(0, currentStatus_);
|
||||
started_ = true; // Let Next find next available entry
|
||||
Next();
|
||||
}
|
||||
}
|
||||
|
||||
void TransactionLogIteratorImpl::Next() {
|
||||
std::string scratch;
|
||||
Slice record;
|
||||
isValid_ = false;
|
||||
if (!started_) { // Runs every time until we can seek to the start sequence
|
||||
return SeekToStartSequence();
|
||||
}
|
||||
while(true) {
|
||||
assert(currentLogReader_);
|
||||
if (currentSequence_ < *lastFlushedSequence_) {
|
||||
if (currentBatchSeq_ < *lastFlushedSequence_) {
|
||||
if (currentLogReader_->IsEOF()) {
|
||||
currentLogReader_->UnmarkEOF();
|
||||
}
|
||||
while (currentLogReader_->ReadRecord(&record, &scratch)) {
|
||||
if (record.size() < 12) {
|
||||
reporter_.Corruption(
|
||||
record.size(), Status::Corruption("log record too small"));
|
||||
record.size(), Status::Corruption("very small log record"));
|
||||
continue;
|
||||
} else {
|
||||
UpdateCurrentWriteBatch(record);
|
||||
openNextFile = false;
|
||||
break;
|
||||
return UpdateCurrentWriteBatch(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (openNextFile) {
|
||||
if (currentFileIndex_ < files_.get()->size() - 1) {
|
||||
++currentFileIndex_;
|
||||
Status status =OpenLogReader(files_.get()->at(currentFileIndex_).get());
|
||||
if (!status.ok()) {
|
||||
isValid_ = false;
|
||||
currentStatus_ = status;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Open the next file
|
||||
if (currentFileIndex_ < files_->size() - 1) {
|
||||
++currentFileIndex_;
|
||||
Status status =OpenLogReader(files_->at(currentFileIndex_).get());
|
||||
if (!status.ok()) {
|
||||
isValid_ = false;
|
||||
openNextFile = false;
|
||||
if (currentSequence_ == *lastFlushedSequence_) {
|
||||
currentStatus_ = Status::OK();
|
||||
} else {
|
||||
currentStatus_ = Status::IOError(" NO MORE DATA LEFT");
|
||||
}
|
||||
currentStatus_ = status;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
isValid_ = false;
|
||||
if (currentBatchSeq_ == *lastFlushedSequence_) {
|
||||
currentStatus_ = Status::OK();
|
||||
} else {
|
||||
currentStatus_ = Status::IOError(" NO MORE DATA LEFT");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TransactionLogIteratorImpl::IsBatchContinuous(
|
||||
const WriteBatch* batch,
|
||||
const SequenceNumber expectedSeq) {
|
||||
assert(batch);
|
||||
SequenceNumber batchSeq = WriteBatchInternal::Sequence(batch);
|
||||
if (started_ && batchSeq != expectedSeq) {
|
||||
char buf[200];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"Discontinuity in log records. Got seq=%lu, Expected seq=%lu, "
|
||||
"Last flushed seq=%lu. Log iterator will seek the correct batch.",
|
||||
batchSeq, expectedSeq, *lastFlushedSequence_);
|
||||
reporter_.Info(buf);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransactionLogIteratorImpl::UpdateCurrentWriteBatch(const Slice& record) {
|
||||
WriteBatch* batch = new WriteBatch();
|
||||
WriteBatchInternal::SetContents(batch, record);
|
||||
currentSequence_ = WriteBatchInternal::Sequence(batch);
|
||||
|
||||
SequenceNumber expectedSeq = currentBatchSeq_ + currentBatchCount_;
|
||||
if (!IsBatchContinuous(batch, expectedSeq)) {
|
||||
// Seek to the batch having expected sequence number
|
||||
if (expectedSeq < files_->at(currentFileIndex_)->StartSequence()) {
|
||||
// Expected batch must lie in the previous log file
|
||||
currentFileIndex_--;
|
||||
currentFileIndex_ = (currentFileIndex_ >= 0) ? currentFileIndex_ : 0;
|
||||
}
|
||||
startingSequenceNumber_ = expectedSeq;
|
||||
return SeekToStartSequence(currentFileIndex_, true);
|
||||
}
|
||||
|
||||
currentBatchSeq_ = WriteBatchInternal::Sequence(batch);
|
||||
currentBatchCount_ = WriteBatchInternal::Count(batch);
|
||||
// currentBatchSeq_ can only change here
|
||||
assert(currentBatchSeq_ <= *lastFlushedSequence_);
|
||||
|
||||
currentBatch_.reset(batch);
|
||||
isValid_ = true;
|
||||
currentStatus_ = Status::OK();
|
||||
@@ -168,4 +239,4 @@ Status TransactionLogIteratorImpl::OpenLogReader(const LogFile* logFile) {
|
||||
);
|
||||
return Status::OK();
|
||||
}
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+34
-20
@@ -1,17 +1,19 @@
|
||||
// Copyright 2008-present Facebook. All Rights Reserved.
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_WRITES_ITERATOR_IMPL_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_WRITES_ITERATOR_IMPL_H_
|
||||
|
||||
// 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.
|
||||
//
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/options.h"
|
||||
#include "leveldb/types.h"
|
||||
#include "leveldb/transaction_log.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/types.h"
|
||||
#include "rocksdb/transaction_log.h"
|
||||
#include "db/log_reader.h"
|
||||
#include "db/filename.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
struct LogReporter : public log::Reader::Reporter {
|
||||
Env* env;
|
||||
@@ -19,6 +21,9 @@ struct LogReporter : public log::Reader::Reporter {
|
||||
virtual void Corruption(size_t bytes, const Status& s) {
|
||||
Log(info_log, "dropping %zu bytes; %s", bytes, s.ToString().c_str());
|
||||
}
|
||||
virtual void Info(const char* s) {
|
||||
Log(info_log, "%s", s);
|
||||
}
|
||||
};
|
||||
|
||||
class LogFileImpl : public LogFile {
|
||||
@@ -31,7 +36,12 @@ class LogFileImpl : public LogFile {
|
||||
sizeFileBytes_(sizeBytes) {
|
||||
}
|
||||
|
||||
std::string Filename() const { return LogFileName("", logNumber_); }
|
||||
std::string PathName() const {
|
||||
if (type_ == kArchivedLogFile) {
|
||||
return ArchivedLogFileName("", logNumber_);
|
||||
}
|
||||
return LogFileName("", logNumber_);
|
||||
}
|
||||
|
||||
uint64_t LogNumber() const { return logNumber_; }
|
||||
|
||||
@@ -55,7 +65,7 @@ class LogFileImpl : public LogFile {
|
||||
|
||||
class TransactionLogIteratorImpl : public TransactionLogIterator {
|
||||
public:
|
||||
TransactionLogIteratorImpl(const std::string& dbname,
|
||||
TransactionLogIteratorImpl(const std::string& dir,
|
||||
const Options* options,
|
||||
const EnvOptions& soptions,
|
||||
const SequenceNumber seqNum,
|
||||
@@ -71,10 +81,10 @@ class TransactionLogIteratorImpl : public TransactionLogIterator {
|
||||
virtual BatchResult GetBatch();
|
||||
|
||||
private:
|
||||
const std::string& dbname_;
|
||||
const std::string& dir_;
|
||||
const Options* options_;
|
||||
const EnvOptions& soptions_;
|
||||
const SequenceNumber startingSequenceNumber_;
|
||||
SequenceNumber startingSequenceNumber_;
|
||||
std::unique_ptr<VectorLogPtr> files_;
|
||||
bool started_;
|
||||
bool isValid_; // not valid when it starts of.
|
||||
@@ -84,15 +94,19 @@ class TransactionLogIteratorImpl : public TransactionLogIterator {
|
||||
unique_ptr<log::Reader> currentLogReader_;
|
||||
Status OpenLogFile(const LogFile* logFile, unique_ptr<SequentialFile>* file);
|
||||
LogReporter reporter_;
|
||||
SequenceNumber currentBatchSeq_; // sequence number at start of current batch
|
||||
uint64_t currentBatchCount_; // count in current batch
|
||||
SequenceNumber const * const lastFlushedSequence_;
|
||||
// represents the sequence number being read currently.
|
||||
SequenceNumber currentSequence_;
|
||||
|
||||
// Reads from transaction log only if the writebatch record has been written
|
||||
bool RestrictedRead(Slice* record, std::string* scratch);
|
||||
// Seeks to startingSequenceNumber reading from startFileIndex in files_.
|
||||
// If strict is set,then must get a batch starting with startingSequenceNumber
|
||||
void SeekToStartSequence(uint64_t startFileIndex = 0, bool strict = false);
|
||||
// Check if batch is continuous starting from expectedSeq, else return false
|
||||
bool IsBatchContinuous(const WriteBatch* batch, SequenceNumber expectedSeq);
|
||||
// Update current batch if a continuous batch is found, else return false
|
||||
void UpdateCurrentWriteBatch(const Slice& record);
|
||||
Status OpenLogReader(const LogFile* file);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace leveldb
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_WRITES_ITERATOR_IMPL_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+7
-2
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -7,7 +12,7 @@
|
||||
#include "db/version_set.h"
|
||||
#include "util/coding.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// Tag numbers for serialized VersionEdit. These numbers are written to
|
||||
// disk and should not be changed.
|
||||
@@ -293,4 +298,4 @@ std::string VersionEdit::DebugString(bool hex_key) const {
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+8
-7
@@ -1,16 +1,19 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_VERSION_EDIT_H_
|
||||
#define STORAGE_LEVELDB_DB_VERSION_EDIT_H_
|
||||
|
||||
#pragma once
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "db/dbformat.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class VersionSet;
|
||||
|
||||
@@ -122,6 +125,4 @@ class VersionEdit {
|
||||
std::vector< std::pair<int, FileMetaData> > new_files_;
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_VERSION_EDIT_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -5,7 +10,7 @@
|
||||
#include "db/version_edit.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static void TestEncodeDecode(const VersionEdit& edit) {
|
||||
std::string encoded, encoded2;
|
||||
@@ -41,8 +46,8 @@ TEST(VersionEditTest, EncodeDecode) {
|
||||
TestEncodeDecode(edit);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+350
-144
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -12,16 +17,16 @@
|
||||
#include "db/log_writer.h"
|
||||
#include "db/memtable.h"
|
||||
#include "db/table_cache.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/merge_operator.h"
|
||||
#include "leveldb/table_builder.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/merge_operator.h"
|
||||
#include "rocksdb/table_builder.h"
|
||||
#include "table/merger.h"
|
||||
#include "table/two_level_iterator.h"
|
||||
#include "util/coding.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/stop_watch.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static uint64_t TotalFileSize(const std::vector<FileMetaData*>& files) {
|
||||
uint64_t sum = 0;
|
||||
@@ -189,7 +194,14 @@ static Iterator* GetFileIterator(void* arg,
|
||||
return NewErrorIterator(
|
||||
Status::Corruption("FileReader invoked with unexpected value"));
|
||||
} else {
|
||||
return cache->NewIterator(options,
|
||||
ReadOptions options_copy;
|
||||
if (options.prefix) {
|
||||
// suppress prefix filtering since we have already checked the
|
||||
// filters once at this point
|
||||
options_copy = options;
|
||||
options_copy.prefix = nullptr;
|
||||
}
|
||||
return cache->NewIterator(options.prefix ? options_copy : options,
|
||||
soptions,
|
||||
DecodeFixed64(file_value.data()),
|
||||
DecodeFixed64(file_value.data() + 8),
|
||||
@@ -198,22 +210,55 @@ static Iterator* GetFileIterator(void* arg,
|
||||
}
|
||||
}
|
||||
|
||||
bool Version::PrefixMayMatch(const ReadOptions& options,
|
||||
const EnvOptions& soptions,
|
||||
const Slice& internal_prefix,
|
||||
Iterator* level_iter) const {
|
||||
bool may_match = true;
|
||||
level_iter->Seek(internal_prefix);
|
||||
if (!level_iter->Valid()) {
|
||||
// we're past end of level
|
||||
may_match = false;
|
||||
} else if (ExtractUserKey(level_iter->key()).starts_with(
|
||||
ExtractUserKey(internal_prefix))) {
|
||||
// TODO(tylerharter): do we need this case? Or are we guaranteed
|
||||
// key() will always be the biggest value for this SST?
|
||||
may_match = true;
|
||||
} else {
|
||||
may_match = vset_->table_cache_->PrefixMayMatch(
|
||||
options,
|
||||
DecodeFixed64(level_iter->value().data()),
|
||||
DecodeFixed64(level_iter->value().data() + 8),
|
||||
internal_prefix, nullptr);
|
||||
}
|
||||
return may_match;
|
||||
}
|
||||
|
||||
Iterator* Version::NewConcatenatingIterator(const ReadOptions& options,
|
||||
const EnvOptions& soptions,
|
||||
int level) const {
|
||||
return NewTwoLevelIterator(
|
||||
new LevelFileNumIterator(vset_->icmp_, &files_[level]),
|
||||
&GetFileIterator, vset_->table_cache_, options, soptions);
|
||||
Iterator* level_iter = new LevelFileNumIterator(vset_->icmp_, &files_[level]);
|
||||
if (options.prefix) {
|
||||
InternalKey internal_prefix(*options.prefix, 0, kTypeValue);
|
||||
if (!PrefixMayMatch(options, soptions,
|
||||
internal_prefix.Encode(), level_iter)) {
|
||||
delete level_iter;
|
||||
// nothing in this level can match the prefix
|
||||
return NewEmptyIterator();
|
||||
}
|
||||
}
|
||||
return NewTwoLevelIterator(level_iter, &GetFileIterator,
|
||||
vset_->table_cache_, options, soptions);
|
||||
}
|
||||
|
||||
void Version::AddIterators(const ReadOptions& options,
|
||||
const EnvOptions& soptions,
|
||||
std::vector<Iterator*>* iters) {
|
||||
// Merge all level zero files together since they may overlap
|
||||
for (size_t i = 0; i < files_[0].size(); i++) {
|
||||
for (const FileMetaData* file : files_[0]) {
|
||||
iters->push_back(
|
||||
vset_->table_cache_->NewIterator(
|
||||
options, soptions, files_[0][i]->number, files_[0][i]->file_size));
|
||||
options, soptions, file->number, file->file_size));
|
||||
}
|
||||
|
||||
// For levels > 0, we can use a concatenating iterator that sequentially
|
||||
@@ -357,6 +402,7 @@ static bool NewestFirstBySeqNo(FileMetaData* a, FileMetaData* b) {
|
||||
|
||||
Version::Version(VersionSet* vset, uint64_t version_number)
|
||||
: vset_(vset), next_(this), prev_(this), refs_(0),
|
||||
files_(new std::vector<FileMetaData*>[vset->NumberLevels()]),
|
||||
files_by_size_(vset->NumberLevels()),
|
||||
next_file_to_compact_by_size_(vset->NumberLevels()),
|
||||
file_to_compact_(nullptr),
|
||||
@@ -365,7 +411,6 @@ Version::Version(VersionSet* vset, uint64_t version_number)
|
||||
compaction_level_(vset->NumberLevels()),
|
||||
offset_manifest_file_(0),
|
||||
version_number_(version_number) {
|
||||
files_ = new std::vector<FileMetaData*>[vset->NumberLevels()];
|
||||
}
|
||||
|
||||
void Version::Get(const ReadOptions& options,
|
||||
@@ -375,7 +420,6 @@ void Version::Get(const ReadOptions& options,
|
||||
std::deque<std::string>* operands,
|
||||
GetStats* stats,
|
||||
const Options& db_options,
|
||||
const bool no_io,
|
||||
bool* value_found) {
|
||||
Slice ikey = k.internal_key();
|
||||
Slice user_key = k.user_key();
|
||||
@@ -385,9 +429,6 @@ void Version::Get(const ReadOptions& options,
|
||||
auto logger = db_options.info_log;
|
||||
|
||||
assert(status->ok() || status->IsMergeInProgress());
|
||||
if (no_io) {
|
||||
assert(status->ok());
|
||||
}
|
||||
Saver saver;
|
||||
saver.state = status->ok()? kNotFound : kMerge;
|
||||
saver.ucmp = ucmp;
|
||||
@@ -476,7 +517,7 @@ void Version::Get(const ReadOptions& options,
|
||||
bool tableIO = false;
|
||||
*status = vset_->table_cache_->Get(options, f->number, f->file_size,
|
||||
ikey, &saver, SaveValue, &tableIO,
|
||||
MarkKeyMayExist, no_io);
|
||||
MarkKeyMayExist);
|
||||
// TODO: examine the behavior for corrupted key
|
||||
if (!status->ok()) {
|
||||
return;
|
||||
@@ -1394,9 +1435,9 @@ Status VersionSet::Recover() {
|
||||
if (s.ok()) {
|
||||
if (edit.has_comparator_ &&
|
||||
edit.comparator_ != icmp_.user_comparator()->Name()) {
|
||||
s = Status::InvalidArgument(
|
||||
edit.comparator_ + "does not match existing comparator ",
|
||||
icmp_.user_comparator()->Name());
|
||||
s = Status::InvalidArgument(icmp_.user_comparator()->Name(),
|
||||
"does not match existing comparator " +
|
||||
edit.comparator_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1512,9 +1553,9 @@ Status VersionSet::DumpManifest(Options& options, std::string& dscname,
|
||||
if (s.ok()) {
|
||||
if (edit.has_comparator_ &&
|
||||
edit.comparator_ != icmp_.user_comparator()->Name()) {
|
||||
s = Status::InvalidArgument(
|
||||
edit.comparator_ + "does not match existing comparator ",
|
||||
icmp_.user_comparator()->Name());
|
||||
s = Status::InvalidArgument(icmp_.user_comparator()->Name(),
|
||||
"does not match existing comparator " +
|
||||
edit.comparator_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1609,7 +1650,12 @@ void VersionSet::Finalize(Version* v,
|
||||
double max_score = 0;
|
||||
int max_score_level = 0;
|
||||
|
||||
for (int level = 0; level < NumberLevels()-1; level++) {
|
||||
int num_levels_to_check =
|
||||
(options_->compaction_style != kCompactionStyleUniversal) ?
|
||||
NumberLevels() - 1 : 1;
|
||||
|
||||
for (int level = 0; level < num_levels_to_check; level++) {
|
||||
|
||||
double score;
|
||||
if (level == 0) {
|
||||
// We treat level-0 specially by bounding the number of files
|
||||
@@ -2123,17 +2169,236 @@ void VersionSet::SizeBeingCompacted(std::vector<uint64_t>& sizes) {
|
||||
}
|
||||
}
|
||||
|
||||
Compaction* VersionSet::PickCompactionUniversal(int level, double score) {
|
||||
//
|
||||
// Look at overall size amplification. If size amplification
|
||||
// exceeeds the configured value, then do a compaction
|
||||
// of the candidate files all the way upto the earliest
|
||||
// base file (overrides configured values of file-size ratios,
|
||||
// min_merge_width and max_merge_width).
|
||||
//
|
||||
Compaction* VersionSet::PickCompactionUniversalSizeAmp(
|
||||
int level, double score) {
|
||||
assert (level == 0);
|
||||
|
||||
// percentage flexibilty while comparing file sizes
|
||||
uint64_t ratio = options_->compaction_options_universal.size_ratio;
|
||||
// percentage flexibilty while reducing size amplification
|
||||
uint64_t ratio = options_->compaction_options_universal.
|
||||
max_size_amplification_percent;
|
||||
|
||||
// The files are sorted from newest first to oldest last.
|
||||
std::vector<int>& file_by_time = current_->files_by_size_[level];
|
||||
assert(file_by_time.size() == current_->files_[level].size());
|
||||
|
||||
unsigned int candidate_count = 0;
|
||||
uint64_t candidate_size = 0;
|
||||
unsigned int start_index = 0;
|
||||
FileMetaData* f = nullptr;
|
||||
|
||||
// Skip files that are already being compacted
|
||||
for (unsigned int loop = 0; loop < file_by_time.size() - 1; loop++) {
|
||||
int index = file_by_time[loop];
|
||||
f = current_->files_[level][index];
|
||||
if (!f->being_compacted) {
|
||||
start_index = loop; // Consider this as the first candidate.
|
||||
break;
|
||||
}
|
||||
Log(options_->info_log, "Universal: skipping file %ld[%d] compacted %s",
|
||||
f->number, loop, " cannot be a candidate to reduce size amp.\n");
|
||||
f = nullptr;
|
||||
}
|
||||
if (f == nullptr) {
|
||||
return nullptr; // no candidate files
|
||||
}
|
||||
|
||||
Log(options_->info_log, "Universal: First candidate file %ld[%d] %s",
|
||||
f->number, start_index, " to reduce size amp.\n");
|
||||
|
||||
// keep adding up all the remaining files
|
||||
for (unsigned int loop = start_index; loop < file_by_time.size() - 1;
|
||||
loop++) {
|
||||
int index = file_by_time[loop];
|
||||
f = current_->files_[level][index];
|
||||
if (f->being_compacted) {
|
||||
Log(options_->info_log,
|
||||
"Universal: Possible candidate file %ld[%d] %s.", f->number, loop,
|
||||
" is already being compacted. No size amp reduction possible.\n");
|
||||
return nullptr;
|
||||
}
|
||||
candidate_size += f->file_size;
|
||||
candidate_count++;
|
||||
}
|
||||
if (candidate_count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// size of earliest file
|
||||
int index = file_by_time[file_by_time.size() - 1];
|
||||
uint64_t earliest_file_size = current_->files_[level][index]->file_size;
|
||||
|
||||
// size amplification = percentage of additional size
|
||||
if (candidate_size * 100 < ratio * earliest_file_size) {
|
||||
Log(options_->info_log,
|
||||
"Universal: size amp not needed. newer-files-total-size %ld "
|
||||
"earliest-file-size %ld",
|
||||
candidate_size, earliest_file_size);
|
||||
return nullptr;
|
||||
} else {
|
||||
Log(options_->info_log,
|
||||
"Universal: size amp needed. newer-files-total-size %ld "
|
||||
"earliest-file-size %ld",
|
||||
candidate_size, earliest_file_size);
|
||||
}
|
||||
assert(start_index >= 0 && start_index < file_by_time.size() - 1);
|
||||
|
||||
// create a compaction request
|
||||
// We always compact all the files, so always compress.
|
||||
Compaction* c = new Compaction(level, level, MaxFileSizeForLevel(level),
|
||||
LLONG_MAX, NumberLevels(), false,
|
||||
true);
|
||||
c->score_ = score;
|
||||
for (unsigned int loop = start_index; loop < file_by_time.size(); loop++) {
|
||||
int index = file_by_time[loop];
|
||||
f = current_->files_[level][index];
|
||||
c->inputs_[0].push_back(f);
|
||||
Log(options_->info_log,
|
||||
"Universal: size amp picking file %ld[%d] with size %ld",
|
||||
f->number, index, f->file_size);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//
|
||||
// Consider compaction files based on their size differences with
|
||||
// the next file in time order.
|
||||
//
|
||||
Compaction* VersionSet::PickCompactionUniversalReadAmp(
|
||||
int level, double score, unsigned int ratio,
|
||||
unsigned int max_number_of_files_to_compact) {
|
||||
|
||||
unsigned int min_merge_width =
|
||||
options_->compaction_options_universal.min_merge_width;
|
||||
unsigned int max_merge_width =
|
||||
options_->compaction_options_universal.max_merge_width;
|
||||
|
||||
if ((current_->files_[level].size() <=
|
||||
// The files are sorted from newest first to oldest last.
|
||||
std::vector<int>& file_by_time = current_->files_by_size_[level];
|
||||
FileMetaData* f = nullptr;
|
||||
bool done = false;
|
||||
int start_index = 0;
|
||||
unsigned int candidate_count;
|
||||
assert(file_by_time.size() == current_->files_[level].size());
|
||||
|
||||
unsigned int max_files_to_compact = std::min(max_merge_width,
|
||||
max_number_of_files_to_compact);
|
||||
min_merge_width = std::max(min_merge_width, 2U);
|
||||
|
||||
// Considers a candidate file only if it is smaller than the
|
||||
// total size accumulated so far.
|
||||
for (unsigned int loop = 0; loop < file_by_time.size(); loop++) {
|
||||
|
||||
candidate_count = 0;
|
||||
|
||||
// Skip files that are already being compacted
|
||||
for (f = nullptr; loop < file_by_time.size(); loop++) {
|
||||
int index = file_by_time[loop];
|
||||
f = current_->files_[level][index];
|
||||
|
||||
if (!f->being_compacted) {
|
||||
candidate_count = 1;
|
||||
break;
|
||||
}
|
||||
Log(options_->info_log,
|
||||
"Universal: file %ld[%d] being compacted, skipping",
|
||||
f->number, loop);
|
||||
f = nullptr;
|
||||
}
|
||||
|
||||
// This file is not being compacted. Consider it as the
|
||||
// first candidate to be compacted.
|
||||
uint64_t candidate_size = f != nullptr? f->file_size : 0;
|
||||
if (f != nullptr) {
|
||||
Log(options_->info_log, "Universal: Possible candidate file %ld[%d].",
|
||||
f->number, loop);
|
||||
}
|
||||
|
||||
// Check if the suceeding files need compaction.
|
||||
for (unsigned int i = loop+1;
|
||||
candidate_count < max_files_to_compact && i < file_by_time.size();
|
||||
i++) {
|
||||
int index = file_by_time[i];
|
||||
FileMetaData* f = current_->files_[level][index];
|
||||
if (f->being_compacted) {
|
||||
break;
|
||||
}
|
||||
// pick files if the total candidate file size (increased by the
|
||||
// specified ratio) is still larger than the next candidate file.
|
||||
uint64_t sz = (candidate_size * (100L + ratio)) /100;
|
||||
if (sz < f->file_size) {
|
||||
break;
|
||||
}
|
||||
candidate_count++;
|
||||
candidate_size += f->file_size;
|
||||
}
|
||||
|
||||
// Found a series of consecutive files that need compaction.
|
||||
if (candidate_count >= (unsigned int)min_merge_width) {
|
||||
start_index = loop;
|
||||
done = true;
|
||||
break;
|
||||
} else {
|
||||
for (unsigned int i = loop;
|
||||
i < loop + candidate_count && i < file_by_time.size(); i++) {
|
||||
int index = file_by_time[i];
|
||||
FileMetaData* f = current_->files_[level][index];
|
||||
Log(options_->info_log,
|
||||
"Universal: Skipping file %ld[%d] with size %ld %d\n",
|
||||
f->number, i, f->file_size, f->being_compacted);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!done || candidate_count <= 1) {
|
||||
return nullptr;
|
||||
}
|
||||
unsigned int first_index_after = start_index + candidate_count;
|
||||
// Compression is enabled if files compacted earlier already reached
|
||||
// size ratio of compression.
|
||||
bool enable_compression = true;
|
||||
int ratio_to_compress =
|
||||
options_->compaction_options_universal.compression_size_percent;
|
||||
if (ratio_to_compress >= 0) {
|
||||
uint64_t total_size = TotalFileSize(current_->files_[level]);
|
||||
uint64_t older_file_size = 0;
|
||||
for (unsigned int i = file_by_time.size() - 1; i >= first_index_after;
|
||||
i--) {
|
||||
older_file_size += current_->files_[level][file_by_time[i]]->file_size;
|
||||
if (older_file_size * 100L >= total_size * (long) ratio_to_compress) {
|
||||
enable_compression = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Compaction* c = new Compaction(level, level, MaxFileSizeForLevel(level),
|
||||
LLONG_MAX, NumberLevels(), false,
|
||||
enable_compression);
|
||||
c->score_ = score;
|
||||
|
||||
for (unsigned int i = start_index; i < first_index_after; i++) {
|
||||
int index = file_by_time[i];
|
||||
FileMetaData* f = current_->files_[level][index];
|
||||
c->inputs_[0].push_back(f);
|
||||
Log(options_->info_log, "Universal: Picking file %ld[%d] with size %ld\n",
|
||||
f->number, i, f->file_size);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//
|
||||
// Universal style of compaction. Pick files that are contiguous in
|
||||
// time-range to compact.
|
||||
//
|
||||
Compaction* VersionSet::PickCompactionUniversal(int level, double score) {
|
||||
assert (level == 0);
|
||||
|
||||
if ((current_->files_[level].size() <
|
||||
(unsigned int)options_->level0_file_num_compaction_trigger)) {
|
||||
Log(options_->info_log, "Universal: nothing to do\n");
|
||||
return nullptr;
|
||||
@@ -2143,127 +2408,29 @@ Compaction* VersionSet::PickCompactionUniversal(int level, double score) {
|
||||
current_->files_[level].size(),
|
||||
LevelFileSummary(&tmp, 0));
|
||||
|
||||
Compaction* c = nullptr;
|
||||
c = new Compaction(level, level, MaxFileSizeForLevel(level),
|
||||
LLONG_MAX, NumberLevels());
|
||||
c->score_ = score;
|
||||
// Check for size amplification first.
|
||||
Compaction* c = PickCompactionUniversalSizeAmp(level, score);
|
||||
if (c == nullptr) {
|
||||
|
||||
// The files are sorted from newest first to oldest last.
|
||||
std::vector<int>& file_by_time = current_->files_by_size_[level];
|
||||
FileMetaData* f = nullptr;
|
||||
bool done = false;
|
||||
assert(file_by_time.size() == current_->files_[level].size());
|
||||
// Size amplification is within limits. Try reducing read
|
||||
// amplification while maintaining file size ratios.
|
||||
unsigned int ratio = options_->compaction_options_universal.size_ratio;
|
||||
c = PickCompactionUniversalReadAmp(level, score, ratio, UINT_MAX);
|
||||
|
||||
unsigned int max_files_to_compact = std::min(max_merge_width, UINT_MAX);
|
||||
|
||||
// Make two pass. The first pass considers a candidate file
|
||||
// only if it is smaller than the total size accumulated so far.
|
||||
// The second pass does not look at the slope of the
|
||||
// file-size curve to decide what to pick for compaction.
|
||||
for (int iter = 0; !done && iter < 2; iter++) {
|
||||
|
||||
for (unsigned int loop = 0; loop < file_by_time.size(); ) {
|
||||
|
||||
// Skip files that are already being compacted
|
||||
for (f = nullptr; loop < file_by_time.size(); loop++) {
|
||||
int index = file_by_time[loop];
|
||||
f = current_->files_[level][index];
|
||||
|
||||
if (!f->being_compacted) {
|
||||
break;
|
||||
}
|
||||
Log(options_->info_log, "Universal: file %ld[%d] being compacted, skipping",
|
||||
f->number, loop);
|
||||
f = nullptr;
|
||||
}
|
||||
|
||||
// This file is not being compacted. Consider it as the
|
||||
// first candidate to be compacted.
|
||||
unsigned int candidate_count = 1;
|
||||
uint64_t candidate_size = f != nullptr? f->file_size : 0;
|
||||
if (f != nullptr) {
|
||||
Log(options_->info_log, "Universal: Possible candidate file %ld[%d] %s.",
|
||||
f->number, loop, iter == 0? "" : "forced ");
|
||||
}
|
||||
|
||||
// Check if the suceeding files need compaction.
|
||||
for (unsigned int i = loop+1;
|
||||
candidate_count < max_files_to_compact && i < file_by_time.size();
|
||||
i++) {
|
||||
int index = file_by_time[i];
|
||||
FileMetaData* f = current_->files_[level][index];
|
||||
if (f->being_compacted) {
|
||||
break;
|
||||
}
|
||||
// If this is the first iteration, then we pick files if the
|
||||
// total candidate file size (increased by the specified ratio)
|
||||
// is still larger than the next candidate file.
|
||||
if (iter == 0) {
|
||||
uint64_t sz = (candidate_size * (100 + ratio)) /100;
|
||||
if (sz < f->file_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
candidate_count++;
|
||||
candidate_size += f->file_size;
|
||||
}
|
||||
|
||||
// Found a series of consecutive files that need compaction.
|
||||
if (candidate_count >= (unsigned int)min_merge_width) {
|
||||
for (unsigned int i = loop; i < loop + candidate_count; i++) {
|
||||
int index = file_by_time[i];
|
||||
FileMetaData* f = current_->files_[level][index];
|
||||
c->inputs_[0].push_back(f);
|
||||
Log(options_->info_log, "Universal: Picking file %ld[%d] with size %ld %s",
|
||||
f->number, i, f->file_size,
|
||||
(iter == 0 ? "" : "forced"));
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
} else {
|
||||
for (unsigned int i = loop;
|
||||
i < loop + candidate_count && i < file_by_time.size(); i++) {
|
||||
int index = file_by_time[i];
|
||||
FileMetaData* f = current_->files_[level][index];
|
||||
Log(options_->info_log, "Universal: Skipping file %ld[%d] with size %ld %d %s",
|
||||
f->number, i, f->file_size, f->being_compacted,
|
||||
(iter == 0 ? "" : "forced"));
|
||||
}
|
||||
}
|
||||
loop += candidate_count;
|
||||
}
|
||||
assert(done || c->inputs_[0].size() == 0);
|
||||
|
||||
// If we are unable to find a normal compaction run and we are still
|
||||
// above the compaction threshold, iterate again to pick compaction
|
||||
// candidates, this time without considering their size differences.
|
||||
if (!done) {
|
||||
int files_not_in_compaction = 0;
|
||||
for (unsigned int i = 0; i < current_->files_[level].size(); i++) {
|
||||
f = current_->files_[level][i];
|
||||
if (!f->being_compacted) {
|
||||
files_not_in_compaction++;
|
||||
}
|
||||
}
|
||||
int expected_num_files = files_not_in_compaction +
|
||||
compactions_in_progress_[level].size();
|
||||
if (expected_num_files <=
|
||||
options_->level0_file_num_compaction_trigger + 1) {
|
||||
done = true; // nothing more to do
|
||||
} else {
|
||||
max_files_to_compact = std::min((int)max_merge_width,
|
||||
expected_num_files - options_->level0_file_num_compaction_trigger);
|
||||
Log(options_->info_log, "Universal: second loop with maxfiles %d",
|
||||
max_files_to_compact);
|
||||
}
|
||||
// Size amplification and file size ratios are within configured limits.
|
||||
// If max read amplification is exceeding configured limits, then force
|
||||
// compaction without looking at filesize ratios and try to reduce
|
||||
// the number of files to fewer than level0_file_num_compaction_trigger.
|
||||
if (c == nullptr) {
|
||||
unsigned int num_files = current_->files_[level].size() -
|
||||
options_->level0_file_num_compaction_trigger;
|
||||
c = PickCompactionUniversalReadAmp(level, score, UINT_MAX, num_files);
|
||||
}
|
||||
}
|
||||
if (c->inputs_[0].size() <= 1) {
|
||||
Log(options_->info_log, "Universal: only %ld files, nothing to do.\n",
|
||||
c->inputs_[0].size());
|
||||
delete c;
|
||||
if (c == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
assert(c->inputs_[0].size() > 1);
|
||||
|
||||
// validate that all the chosen files are non overlapping in time
|
||||
FileMetaData* newerfile __attribute__((unused)) = nullptr;
|
||||
@@ -2275,6 +2442,9 @@ Compaction* VersionSet::PickCompactionUniversal(int level, double score) {
|
||||
newerfile = f;
|
||||
}
|
||||
|
||||
// The files are sorted from newest first to oldest last.
|
||||
std::vector<int>& file_by_time = current_->files_by_size_[level];
|
||||
|
||||
// Is the earliest file part of this compaction?
|
||||
int last_index = file_by_time[file_by_time.size()-1];
|
||||
FileMetaData* last_file = current_->files_[level][last_index];
|
||||
@@ -2637,6 +2807,41 @@ void VersionSet::SetupOtherInputs(Compaction* c) {
|
||||
c->edit_->SetCompactPointer(level, largest);
|
||||
}
|
||||
|
||||
Status VersionSet::GetMetadataForFile(
|
||||
uint64_t number,
|
||||
int *filelevel,
|
||||
FileMetaData *meta) {
|
||||
for (int level = 0; level < NumberLevels(); level++) {
|
||||
const std::vector<FileMetaData*>& files = current_->files_[level];
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
if (files[i]->number == number) {
|
||||
*meta = *files[i];
|
||||
*filelevel = level;
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Status::NotFound("File not present in any level");
|
||||
}
|
||||
|
||||
void VersionSet::GetLiveFilesMetaData(
|
||||
std::vector<LiveFileMetaData> * metadata) {
|
||||
for (int level = 0; level < NumberLevels(); level++) {
|
||||
const std::vector<FileMetaData*>& files = current_->files_[level];
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
LiveFileMetaData filemetadata;
|
||||
filemetadata.name = TableFileName("", files[i]->number);
|
||||
filemetadata.level = level;
|
||||
filemetadata.size = files[i]->file_size;
|
||||
filemetadata.smallestkey = files[i]->smallest.user_key().ToString();
|
||||
filemetadata.largestkey = files[i]->largest.user_key().ToString();
|
||||
filemetadata.smallest_seqno = files[i]->smallest_seqno;
|
||||
filemetadata.largest_seqno = files[i]->largest_seqno;
|
||||
metadata->push_back(filemetadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Compaction* VersionSet::CompactRange(
|
||||
int level,
|
||||
const InternalKey* begin,
|
||||
@@ -2700,7 +2905,7 @@ Compaction* VersionSet::CompactRange(
|
||||
|
||||
Compaction::Compaction(int level, int out_level, uint64_t target_file_size,
|
||||
uint64_t max_grandparent_overlap_bytes, int number_levels,
|
||||
bool seek_compaction)
|
||||
bool seek_compaction, bool enable_compression)
|
||||
: level_(level),
|
||||
out_level_(out_level),
|
||||
max_output_file_size_(target_file_size),
|
||||
@@ -2708,6 +2913,7 @@ Compaction::Compaction(int level, int out_level, uint64_t target_file_size,
|
||||
input_version_(nullptr),
|
||||
number_levels_(number_levels),
|
||||
seek_compaction_(seek_compaction),
|
||||
enable_compression_(enable_compression),
|
||||
grandparent_index_(0),
|
||||
seen_key_(false),
|
||||
overlapped_bytes_(0),
|
||||
@@ -2881,4 +3087,4 @@ void Compaction::Summary(char* output, int len) {
|
||||
level_low_summary, level_up_summary);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+40
-12
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -12,9 +17,7 @@
|
||||
// Version,VersionSet are thread-compatible, but require external
|
||||
// synchronization on all accesses.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_VERSION_SET_H_
|
||||
#define STORAGE_LEVELDB_DB_VERSION_SET_H_
|
||||
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -25,18 +28,16 @@
|
||||
#include "port/port.h"
|
||||
#include "db/table_cache.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
namespace log { class Writer; }
|
||||
|
||||
class Compaction;
|
||||
class Iterator;
|
||||
class MemTable;
|
||||
class TableBuilder;
|
||||
class TableCache;
|
||||
class Version;
|
||||
class VersionSet;
|
||||
class WritableFile;
|
||||
|
||||
// Return the smallest index i such that files[i]->largest >= key.
|
||||
// Return files.size() if there is no such file.
|
||||
@@ -76,7 +77,7 @@ class Version {
|
||||
};
|
||||
void Get(const ReadOptions&, const LookupKey& key, std::string* val,
|
||||
Status* status, std::deque<std::string>* operands, GetStats* stats,
|
||||
const Options& db_option, const bool no_io = false,
|
||||
const Options& db_option,
|
||||
bool* value_found = nullptr);
|
||||
|
||||
// Adds "stats" into the current state. Returns true if a new
|
||||
@@ -152,6 +153,8 @@ class Version {
|
||||
Iterator* NewConcatenatingIterator(const ReadOptions&,
|
||||
const EnvOptions& soptions,
|
||||
int level) const;
|
||||
bool PrefixMayMatch(const ReadOptions& options, const EnvOptions& soptions,
|
||||
const Slice& internal_prefix, Iterator* level_iter) const;
|
||||
|
||||
VersionSet* vset_; // VersionSet to which this Version belongs
|
||||
Version* next_; // Next version in linked list
|
||||
@@ -314,7 +317,17 @@ class VersionSet {
|
||||
// Returns true iff some level needs a compaction because it has
|
||||
// exceeded its target size.
|
||||
bool NeedsSizeCompaction() const {
|
||||
for (int i = 0; i < NumberLevels()-1; i++) {
|
||||
// In universal compaction case, this check doesn't really
|
||||
// check the compaction condition, but checks num of files threshold
|
||||
// only. We are not going to miss any compaction opportunity
|
||||
// but it's likely that more compactions are scheduled but
|
||||
// ending up with nothing to do. We can improve it later.
|
||||
// TODO: improve this function to be accurate for universal
|
||||
// compactions.
|
||||
int num_levels_to_check =
|
||||
(options_->compaction_style != kCompactionStyleUniversal) ?
|
||||
NumberLevels() - 1 : 1;
|
||||
for (int i = 0; i < num_levels_to_check; i++) {
|
||||
if (current_->compaction_score_[i] >= 1) {
|
||||
return true;
|
||||
}
|
||||
@@ -381,6 +394,13 @@ class VersionSet {
|
||||
// Pick files to compact in Universal mode
|
||||
Compaction* PickCompactionUniversal(int level, double score);
|
||||
|
||||
// Pick Universal compaction to limit read amplification
|
||||
Compaction* PickCompactionUniversalReadAmp(int level, double score,
|
||||
unsigned int ratio, unsigned int num_files);
|
||||
|
||||
// Pick Universal compaction to limit space amplification.
|
||||
Compaction* PickCompactionUniversalSizeAmp(int level, double score);
|
||||
|
||||
// Free up the files that were participated in a compaction
|
||||
void ReleaseCompactionFiles(Compaction* c, Status status);
|
||||
|
||||
@@ -405,6 +425,12 @@ class VersionSet {
|
||||
|
||||
double MaxBytesForLevel(int level);
|
||||
|
||||
Status GetMetadataForFile(
|
||||
uint64_t number, int *filelevel, FileMetaData *metadata);
|
||||
|
||||
void GetLiveFilesMetaData(
|
||||
std::vector<LiveFileMetaData> *metadata);
|
||||
|
||||
private:
|
||||
class Builder;
|
||||
struct ManifestWriter;
|
||||
@@ -532,6 +558,9 @@ class Compaction {
|
||||
// Maximum size of files to build during this compaction.
|
||||
uint64_t MaxOutputFileSize() const { return max_output_file_size_; }
|
||||
|
||||
// Whether compression will be enabled for compaction outputs
|
||||
bool enable_compression() const { return enable_compression_; }
|
||||
|
||||
// Is this a trivial compaction that can be implemented by just
|
||||
// moving a single input file to the next level (no merging or splitting)
|
||||
bool IsTrivialMove() const;
|
||||
@@ -566,7 +595,7 @@ class Compaction {
|
||||
|
||||
explicit Compaction(int level, int out_level, uint64_t target_file_size,
|
||||
uint64_t max_grandparent_overlap_bytes, int number_levels,
|
||||
bool seek_compaction = false);
|
||||
bool seek_compaction = false, bool enable_compression = true);
|
||||
|
||||
int level_;
|
||||
int out_level_; // levels to which output files are stored
|
||||
@@ -577,6 +606,7 @@ class Compaction {
|
||||
int number_levels_;
|
||||
|
||||
bool seek_compaction_;
|
||||
bool enable_compression_;
|
||||
|
||||
// Each compaction reads inputs from "level_" and "level_+1"
|
||||
std::vector<FileMetaData*> inputs_[2]; // The two sets of inputs
|
||||
@@ -612,6 +642,4 @@ class Compaction {
|
||||
void ResetNextCompactionIndex();
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_VERSION_SET_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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) 2012 Facebook. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
@@ -10,7 +15,7 @@
|
||||
#include "db/log_writer.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
Status VersionSet::ReduceNumberOfLevels(int new_levels, port::Mutex* mu) {
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -7,7 +12,7 @@
|
||||
#include "util/testharness.h"
|
||||
#include "util/testutil.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class FindFileTest {
|
||||
public:
|
||||
@@ -172,8 +177,8 @@ TEST(FindFileTest, OverlappingFiles) {
|
||||
ASSERT_TRUE(Overlaps("600", "700"));
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
+15
-6
@@ -1,3 +1,8 @@
|
||||
// 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.
|
||||
@@ -14,10 +19,10 @@
|
||||
// len: varint32
|
||||
// data: uint8[len]
|
||||
|
||||
#include "leveldb/write_batch.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
|
||||
#include "leveldb/options.h"
|
||||
#include "leveldb/statistics.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/statistics.h"
|
||||
#include "db/dbformat.h"
|
||||
#include "db/db_impl.h"
|
||||
#include "db/memtable.h"
|
||||
@@ -26,7 +31,7 @@
|
||||
#include "util/coding.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// WriteBatch header has an 8-byte sequence number followed by a 4-byte count.
|
||||
static const size_t kHeader = 12;
|
||||
@@ -48,6 +53,10 @@ void WriteBatch::Handler::LogData(const Slice& blob) {
|
||||
// them.
|
||||
}
|
||||
|
||||
bool WriteBatch::Handler::Continue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriteBatch::Clear() {
|
||||
rep_.clear();
|
||||
rep_.resize(kHeader);
|
||||
@@ -66,7 +75,7 @@ Status WriteBatch::Iterate(Handler* handler) const {
|
||||
input.remove_prefix(kHeader);
|
||||
Slice key, value, blob;
|
||||
int found = 0;
|
||||
while (!input.empty()) {
|
||||
while (!input.empty() && handler->Continue()) {
|
||||
char tag = input[0];
|
||||
input.remove_prefix(1);
|
||||
switch (tag) {
|
||||
@@ -223,4 +232,4 @@ void WriteBatchInternal::Append(WriteBatch* dst, const WriteBatch* src) {
|
||||
dst->rep_.append(src->rep_.data() + kHeader, src->rep_.size() - kHeader);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
+12
-12
@@ -1,16 +1,19 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
|
||||
#define STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
|
||||
#pragma once
|
||||
#include "rocksdb/types.h"
|
||||
#include "rocksdb/write_batch.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/options.h"
|
||||
|
||||
#include "leveldb/types.h"
|
||||
#include "leveldb/write_batch.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/options.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class MemTable;
|
||||
|
||||
@@ -51,7 +54,4 @@ class WriteBatchInternal {
|
||||
static void Append(WriteBatch* dst, const WriteBatch* src);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_WRITE_BATCH_INTERNAL_H_
|
||||
} // namespace rocksdb
|
||||
|
||||
+69
-21
@@ -1,18 +1,23 @@
|
||||
// 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 "leveldb/db.h"
|
||||
#include "rocksdb/db.h"
|
||||
|
||||
#include <memory>
|
||||
#include "db/skiplistrep.h"
|
||||
#include "db/memtable.h"
|
||||
#include "db/write_batch_internal.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/memtablerep.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/testharness.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static std::string PrintContents(WriteBatch* b) {
|
||||
InternalKeyComparator cmp(BytewiseComparator());
|
||||
@@ -134,6 +139,24 @@ TEST(WriteBatchTest, Append) {
|
||||
ASSERT_EQ(4, b1.Count());
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct TestHandler : public WriteBatch::Handler {
|
||||
std::string seen;
|
||||
virtual void Put(const Slice& key, const Slice& value) {
|
||||
seen += "Put(" + key.ToString() + ", " + value.ToString() + ")";
|
||||
}
|
||||
virtual void Merge(const Slice& key, const Slice& value) {
|
||||
seen += "Merge(" + key.ToString() + ", " + value.ToString() + ")";
|
||||
}
|
||||
virtual void LogData(const Slice& blob) {
|
||||
seen += "LogData(" + blob.ToString() + ")";
|
||||
}
|
||||
virtual void Delete(const Slice& key) {
|
||||
seen += "Delete(" + key.ToString() + ")";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST(WriteBatchTest, Blob) {
|
||||
WriteBatch batch;
|
||||
batch.Put(Slice("k1"), Slice("v1"));
|
||||
@@ -151,21 +174,7 @@ TEST(WriteBatchTest, Blob) {
|
||||
"Put(k3, v3)@2",
|
||||
PrintContents(&batch));
|
||||
|
||||
struct Handler : public WriteBatch::Handler {
|
||||
std::string seen;
|
||||
virtual void Put(const Slice& key, const Slice& value) {
|
||||
seen += "Put(" + key.ToString() + ", " + value.ToString() + ")";
|
||||
}
|
||||
virtual void Merge(const Slice& key, const Slice& value) {
|
||||
seen += "Merge(" + key.ToString() + ", " + value.ToString() + ")";
|
||||
}
|
||||
virtual void LogData(const Slice& blob) {
|
||||
seen += "LogData(" + blob.ToString() + ")";
|
||||
}
|
||||
virtual void Delete(const Slice& key) {
|
||||
seen += "Delete(" + key.ToString() + ")";
|
||||
}
|
||||
} handler;
|
||||
TestHandler handler;
|
||||
batch.Iterate(&handler);
|
||||
ASSERT_EQ(
|
||||
"Put(k1, v1)"
|
||||
@@ -178,8 +187,47 @@ TEST(WriteBatchTest, Blob) {
|
||||
handler.seen);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
TEST(WriteBatchTest, Continue) {
|
||||
WriteBatch batch;
|
||||
|
||||
struct Handler : public TestHandler {
|
||||
int num_seen = 0;
|
||||
virtual void Put(const Slice& key, const Slice& value) {
|
||||
++num_seen;
|
||||
TestHandler::Put(key, value);
|
||||
}
|
||||
virtual void Merge(const Slice& key, const Slice& value) {
|
||||
++num_seen;
|
||||
TestHandler::Merge(key, value);
|
||||
}
|
||||
virtual void LogData(const Slice& blob) {
|
||||
++num_seen;
|
||||
TestHandler::LogData(blob);
|
||||
}
|
||||
virtual void Delete(const Slice& key) {
|
||||
++num_seen;
|
||||
TestHandler::Delete(key);
|
||||
}
|
||||
virtual bool Continue() override {
|
||||
return num_seen < 3;
|
||||
}
|
||||
} handler;
|
||||
|
||||
batch.Put(Slice("k1"), Slice("v1"));
|
||||
batch.PutLogData(Slice("blob1"));
|
||||
batch.Delete(Slice("k1"));
|
||||
batch.PutLogData(Slice("blob2"));
|
||||
batch.Merge(Slice("foo"), Slice("bar"));
|
||||
batch.Iterate(&handler);
|
||||
ASSERT_EQ(
|
||||
"Put(k1, v1)"
|
||||
"LogData(blob1)"
|
||||
"Delete(k1)",
|
||||
handler.seen);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ static void WalCheckpoint(sqlite3* db_) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// Helper for quickly generating random data.
|
||||
namespace {
|
||||
@@ -664,7 +664,7 @@ class Benchmark {
|
||||
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::string default_db_path;
|
||||
@@ -672,7 +672,7 @@ int main(int argc, char** argv) {
|
||||
double d;
|
||||
int n;
|
||||
char junk;
|
||||
if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
|
||||
if (rocksdb::Slice(argv[i]).starts_with("--benchmarks=")) {
|
||||
FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
|
||||
} else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&
|
||||
(n == 0 || n == 1)) {
|
||||
@@ -688,7 +688,7 @@ int main(int argc, char** argv) {
|
||||
FLAGS_reads = n;
|
||||
} else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {
|
||||
FLAGS_value_size = n;
|
||||
} else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) {
|
||||
} else if (rocksdb::Slice(argv[i]) == rocksdb::Slice("--no_transaction")) {
|
||||
FLAGS_transaction = false;
|
||||
} else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) {
|
||||
FLAGS_page_size = n;
|
||||
@@ -707,12 +707,12 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Choose a location for the test database if none given with --db=<path>
|
||||
if (FLAGS_db == NULL) {
|
||||
leveldb::Env::Default()->GetTestDirectory(&default_db_path);
|
||||
rocksdb::Env::Default()->GetTestDirectory(&default_db_path);
|
||||
default_db_path += "/dbbench";
|
||||
FLAGS_db = default_db_path.c_str();
|
||||
}
|
||||
|
||||
leveldb::Benchmark benchmark;
|
||||
rocksdb::Benchmark benchmark;
|
||||
benchmark.Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ static void DBSynchronize(kyotocabinet::TreeDB* db_)
|
||||
}
|
||||
}
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
// Helper for quickly generating random data.
|
||||
namespace {
|
||||
@@ -479,7 +479,7 @@ class Benchmark {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
std::string default_db_path;
|
||||
@@ -487,7 +487,7 @@ int main(int argc, char** argv) {
|
||||
double d;
|
||||
int n;
|
||||
char junk;
|
||||
if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
|
||||
if (rocksdb::Slice(argv[i]).starts_with("--benchmarks=")) {
|
||||
FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
|
||||
} else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {
|
||||
FLAGS_compression_ratio = d;
|
||||
@@ -517,12 +517,12 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Choose a location for the test database if none given with --db=<path>
|
||||
if (FLAGS_db == NULL) {
|
||||
leveldb::Env::Default()->GetTestDirectory(&default_db_path);
|
||||
rocksdb::Env::Default()->GetTestDirectory(&default_db_path);
|
||||
default_db_path += "/dbbench";
|
||||
FLAGS_db = default_db_path.c_str();
|
||||
}
|
||||
|
||||
leveldb::Benchmark benchmark;
|
||||
rocksdb::Benchmark benchmark;
|
||||
benchmark.Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+52
-52
@@ -25,27 +25,27 @@ creating it if necessary:
|
||||
#include <assert>
|
||||
#include "leveldb/db.h"
|
||||
|
||||
leveldb::DB* db;
|
||||
leveldb::Options options;
|
||||
rocksdb::DB* db;
|
||||
rocksdb::Options options;
|
||||
options.create_if_missing = true;
|
||||
leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
|
||||
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
|
||||
assert(status.ok());
|
||||
...
|
||||
</pre>
|
||||
If you want to raise an error if the database already exists, add
|
||||
the following line before the <code>leveldb::DB::Open</code> call:
|
||||
the following line before the <code>rocksdb::DB::Open</code> call:
|
||||
<pre>
|
||||
options.error_if_exists = true;
|
||||
</pre>
|
||||
<h1>Status</h1>
|
||||
<p>
|
||||
You may have noticed the <code>leveldb::Status</code> type above. Values of this
|
||||
You may have noticed the <code>rocksdb::Status</code> type above. Values of this
|
||||
type are returned by most functions in <code>leveldb</code> that may encounter an
|
||||
error. You can check if such a result is ok, and also print an
|
||||
associated error message:
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::Status s = ...;
|
||||
rocksdb::Status s = ...;
|
||||
if (!s.ok()) cerr << s.ToString() << endl;
|
||||
</pre>
|
||||
<h1>Closing A Database</h1>
|
||||
@@ -65,9 +65,9 @@ modify/query the database. For example, the following code
|
||||
moves the value stored under key1 to key2.
|
||||
<pre>
|
||||
std::string value;
|
||||
leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
|
||||
if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
|
||||
if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
|
||||
rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
|
||||
if (s.ok()) s = db->Put(rocksdb::WriteOptions(), key2, value);
|
||||
if (s.ok()) s = db->Delete(rocksdb::WriteOptions(), key1);
|
||||
</pre>
|
||||
|
||||
<h1>Atomic Updates</h1>
|
||||
@@ -81,12 +81,12 @@ atomically apply a set of updates:
|
||||
#include "leveldb/write_batch.h"
|
||||
...
|
||||
std::string value;
|
||||
leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
|
||||
rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
|
||||
if (s.ok()) {
|
||||
leveldb::WriteBatch batch;
|
||||
rocksdb::WriteBatch batch;
|
||||
batch.Delete(key1);
|
||||
batch.Put(key2, value);
|
||||
s = db->Write(leveldb::WriteOptions(), &batch);
|
||||
s = db->Write(rocksdb::WriteOptions(), &batch);
|
||||
}
|
||||
</pre>
|
||||
The <code>WriteBatch</code> holds a sequence of edits to be made to the database,
|
||||
@@ -109,7 +109,7 @@ persistent storage. (On Posix systems, this is implemented by calling
|
||||
either <code>fsync(...)</code> or <code>fdatasync(...)</code> or
|
||||
<code>msync(..., MS_SYNC)</code> before the write operation returns.)
|
||||
<pre>
|
||||
leveldb::WriteOptions write_options;
|
||||
rocksdb::WriteOptions write_options;
|
||||
write_options.sync = true;
|
||||
db->Put(write_options, ...);
|
||||
</pre>
|
||||
@@ -144,7 +144,7 @@ the batch.
|
||||
A database may only be opened by one process at a time.
|
||||
The <code>leveldb</code> implementation acquires a lock from the
|
||||
operating system to prevent misuse. Within a single process, the
|
||||
same <code>leveldb::DB</code> object may be safely shared by multiple
|
||||
same <code>rocksdb::DB</code> object may be safely shared by multiple
|
||||
concurrent threads. I.e., different threads may write into or fetch
|
||||
iterators or call <code>Get</code> on the same database without any
|
||||
external synchronization (the leveldb implementation will
|
||||
@@ -160,7 +160,7 @@ The following example demonstrates how to print all key,value pairs
|
||||
in a database.
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
|
||||
rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
cout << it->key().ToString() << ": " << it->value().ToString() << endl;
|
||||
}
|
||||
@@ -196,10 +196,10 @@ implicit snapshot of the current state.
|
||||
Snapshots are created by the DB::GetSnapshot() method:
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::ReadOptions options;
|
||||
rocksdb::ReadOptions options;
|
||||
options.snapshot = db->GetSnapshot();
|
||||
... apply some updates to db ...
|
||||
leveldb::Iterator* iter = db->NewIterator(options);
|
||||
rocksdb::Iterator* iter = db->NewIterator(options);
|
||||
... read using iter to view the state when the snapshot was created ...
|
||||
delete iter;
|
||||
db->ReleaseSnapshot(options.snapshot);
|
||||
@@ -211,7 +211,7 @@ support reading as of that snapshot.
|
||||
<h1>Slice</h1>
|
||||
<p>
|
||||
The return value of the <code>it->key()</code> and <code>it->value()</code> calls above
|
||||
are instances of the <code>leveldb::Slice</code> type. <code>Slice</code> is a simple
|
||||
are instances of the <code>rocksdb::Slice</code> type. <code>Slice</code> is a simple
|
||||
structure that contains a length and a pointer to an external byte
|
||||
array. Returning a <code>Slice</code> is a cheaper alternative to returning a
|
||||
<code>std::string</code> since we do not need to copy potentially large keys and
|
||||
@@ -223,10 +223,10 @@ C++ strings and null-terminated C-style strings can be easily converted
|
||||
to a Slice:
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::Slice s1 = "hello";
|
||||
rocksdb::Slice s1 = "hello";
|
||||
|
||||
std::string str("world");
|
||||
leveldb::Slice s2 = str;
|
||||
rocksdb::Slice s2 = str;
|
||||
</pre>
|
||||
A Slice can be easily converted back to a C++ string:
|
||||
<pre>
|
||||
@@ -238,7 +238,7 @@ the external byte array into which the Slice points remains live while
|
||||
the Slice is in use. For example, the following is buggy:
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::Slice slice;
|
||||
rocksdb::Slice slice;
|
||||
if (...) {
|
||||
std::string str = ...;
|
||||
slice = str;
|
||||
@@ -255,16 +255,16 @@ which orders bytes lexicographically. You can however supply a custom
|
||||
comparator when opening a database. For example, suppose each
|
||||
database key consists of two numbers and we should sort by the first
|
||||
number, breaking ties by the second number. First, define a proper
|
||||
subclass of <code>leveldb::Comparator</code> that expresses these rules:
|
||||
subclass of <code>rocksdb::Comparator</code> that expresses these rules:
|
||||
<p>
|
||||
<pre>
|
||||
class TwoPartComparator : public leveldb::Comparator {
|
||||
class TwoPartComparator : public rocksdb::Comparator {
|
||||
public:
|
||||
// Three-way comparison function:
|
||||
// if a < b: negative result
|
||||
// if a > b: positive result
|
||||
// else: zero result
|
||||
int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
|
||||
int Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const {
|
||||
int a1, a2, b1, b2;
|
||||
ParseKey(a, &a1, &a2);
|
||||
ParseKey(b, &b1, &b2);
|
||||
@@ -277,7 +277,7 @@ subclass of <code>leveldb::Comparator</code> that expresses these rules:
|
||||
|
||||
// Ignore the following methods for now:
|
||||
const char* Name() const { return "TwoPartComparator"; }
|
||||
void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
|
||||
void FindShortestSeparator(std::string*, const rocksdb::Slice&) const { }
|
||||
void FindShortSuccessor(std::string*) const { }
|
||||
};
|
||||
</pre>
|
||||
@@ -285,18 +285,18 @@ Now create a database using this custom comparator:
|
||||
<p>
|
||||
<pre>
|
||||
TwoPartComparator cmp;
|
||||
leveldb::DB* db;
|
||||
leveldb::Options options;
|
||||
rocksdb::DB* db;
|
||||
rocksdb::Options options;
|
||||
options.create_if_missing = true;
|
||||
options.comparator = &cmp;
|
||||
leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
|
||||
rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
|
||||
...
|
||||
</pre>
|
||||
<h2>Backwards compatibility</h2>
|
||||
<p>
|
||||
The result of the comparator's <code>Name</code> method is attached to the
|
||||
database when it is created, and is checked on every subsequent
|
||||
database open. If the name changes, the <code>leveldb::DB::Open</code> call will
|
||||
database open. If the name changes, the <code>rocksdb::DB::Open</code> call will
|
||||
fail. Therefore, change the name if and only if the new key format
|
||||
and comparison function are incompatible with existing databases, and
|
||||
it is ok to discard the contents of all existing databases.
|
||||
@@ -339,9 +339,9 @@ compression entirely, but should only do so if benchmarks show a
|
||||
performance improvement:
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::Options options;
|
||||
options.compression = leveldb::kNoCompression;
|
||||
... leveldb::DB::Open(options, name, ...) ....
|
||||
rocksdb::Options options;
|
||||
options.compression = rocksdb::kNoCompression;
|
||||
... rocksdb::DB::Open(options, name, ...) ....
|
||||
</pre>
|
||||
<h2>Cache</h2>
|
||||
<p>
|
||||
@@ -353,10 +353,10 @@ uncompressed block contents.
|
||||
<pre>
|
||||
#include "leveldb/cache.h"
|
||||
|
||||
leveldb::Options options;
|
||||
options.cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache
|
||||
leveldb::DB* db;
|
||||
leveldb::DB::Open(options, name, &db);
|
||||
rocksdb::Options options;
|
||||
options.cache = rocksdb::NewLRUCache(100 * 1048576); // 100MB cache
|
||||
rocksdb::DB* db;
|
||||
rocksdb::DB::Open(options, name, &db);
|
||||
... use the db ...
|
||||
delete db
|
||||
delete options.cache;
|
||||
@@ -373,9 +373,9 @@ displacing most of the cached contents. A per-iterator option can be
|
||||
used to achieve this:
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::ReadOptions options;
|
||||
rocksdb::ReadOptions options;
|
||||
options.fill_cache = false;
|
||||
leveldb::Iterator* it = db->NewIterator(options);
|
||||
rocksdb::Iterator* it = db->NewIterator(options);
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
||||
...
|
||||
}
|
||||
@@ -407,10 +407,10 @@ a single <code>Get()</code> call may involve multiple reads from disk.
|
||||
The optional <code>FilterPolicy</code> mechanism can be used to reduce
|
||||
the number of disk reads substantially.
|
||||
<pre>
|
||||
leveldb::Options options;
|
||||
rocksdb::Options options;
|
||||
options.filter_policy = NewBloomFilter(10);
|
||||
leveldb::DB* db;
|
||||
leveldb::DB::Open(options, "/tmp/testdb", &db);
|
||||
rocksdb::DB* db;
|
||||
rocksdb::DB::Open(options, "/tmp/testdb", &db);
|
||||
... use the database ...
|
||||
delete db;
|
||||
delete options.filter_policy;
|
||||
@@ -434,7 +434,7 @@ consider a comparator that ignores trailing spaces when comparing keys.
|
||||
Instead, the application should provide a custom filter policy that
|
||||
also ignores trailing spaces. For example:
|
||||
<pre>
|
||||
class CustomFilterPolicy : public leveldb::FilterPolicy {
|
||||
class CustomFilterPolicy : public rocksdb::FilterPolicy {
|
||||
private:
|
||||
FilterPolicy* builtin_policy_;
|
||||
public:
|
||||
@@ -484,7 +484,7 @@ checksums are verified:
|
||||
parts of its persistent storage have been corrupted.
|
||||
<p>
|
||||
If a database is corrupted (perhaps it cannot be opened when
|
||||
paranoid checking is turned on), the <code>leveldb::RepairDB</code> function
|
||||
paranoid checking is turned on), the <code>rocksdb::RepairDB</code> function
|
||||
may be used to recover as much of the data as possible
|
||||
<p>
|
||||
</ul>
|
||||
@@ -494,11 +494,11 @@ The <code>GetApproximateSizes</code> method can used to get the approximate
|
||||
number of bytes of file system space used by one or more key ranges.
|
||||
<p>
|
||||
<pre>
|
||||
leveldb::Range ranges[2];
|
||||
ranges[0] = leveldb::Range("a", "c");
|
||||
ranges[1] = leveldb::Range("x", "z");
|
||||
rocksdb::Range ranges[2];
|
||||
ranges[0] = rocksdb::Range("a", "c");
|
||||
ranges[1] = rocksdb::Range("x", "z");
|
||||
uint64_t sizes[2];
|
||||
leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
|
||||
rocksdb::Status s = db->GetApproximateSizes(ranges, 2, sizes);
|
||||
</pre>
|
||||
The preceding call will set <code>sizes[0]</code> to the approximate number of
|
||||
bytes of file system space used by the key range <code>[a..c)</code> and
|
||||
@@ -508,21 +508,21 @@ bytes of file system space used by the key range <code>[a..c)</code> and
|
||||
<h1>Environment</h1>
|
||||
<p>
|
||||
All file operations (and other operating system calls) issued by the
|
||||
<code>leveldb</code> implementation are routed through a <code>leveldb::Env</code> object.
|
||||
<code>leveldb</code> implementation are routed through a <code>rocksdb::Env</code> object.
|
||||
Sophisticated clients may wish to provide their own <code>Env</code>
|
||||
implementation to get better control. For example, an application may
|
||||
introduce artificial delays in the file IO paths to limit the impact
|
||||
of <code>leveldb</code> on other activities in the system.
|
||||
<p>
|
||||
<pre>
|
||||
class SlowEnv : public leveldb::Env {
|
||||
class SlowEnv : public rocksdb::Env {
|
||||
.. implementation of the Env interface ...
|
||||
};
|
||||
|
||||
SlowEnv env;
|
||||
leveldb::Options options;
|
||||
rocksdb::Options options;
|
||||
options.env = &env;
|
||||
Status s = leveldb::DB::Open(options, ...);
|
||||
Status s = rocksdb::DB::Open(options, ...);
|
||||
</pre>
|
||||
<h1>Porting</h1>
|
||||
<p>
|
||||
@@ -531,7 +531,7 @@ specific implementations of the types/methods/functions exported by
|
||||
<code>leveldb/port/port.h</code>. See <code>leveldb/port/port_example.h</code> for more
|
||||
details.
|
||||
<p>
|
||||
In addition, the new platform may need a new default <code>leveldb::Env</code>
|
||||
In addition, the new platform may need a new default <code>rocksdb::Env</code>
|
||||
implementation. See <code>leveldb/util/env_posix.h</code> for an example.
|
||||
|
||||
<h1>Other Information</h1>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
+4
-4
@@ -1,4 +1,4 @@
|
||||
This directory contains the hdfs extensions needed to make leveldb store
|
||||
This directory contains the hdfs extensions needed to make rocksdb store
|
||||
files in HDFS.
|
||||
|
||||
The hdfs.h file is copied from the Apache Hadoop 1.0 source code.
|
||||
@@ -7,12 +7,12 @@ It defines the libhdfs library
|
||||
data in HDFS. The libhdfs.a is copied from the Apache Hadoop 1.0 build.
|
||||
It implements the API defined in hdfs.h. If your hadoop cluster is running
|
||||
a different hadoop release, then install these two files manually from your
|
||||
hadoop distribution and then recompile leveldb.
|
||||
hadoop distribution and then recompile rocksdb.
|
||||
|
||||
The env_hdfs.h file defines the leveldb objects that are needed to talk to an
|
||||
The env_hdfs.h file defines the rocksdb objects that are needed to talk to an
|
||||
underlying filesystem.
|
||||
|
||||
If you want to compile leveldb with hdfs support, please set the following
|
||||
If you want to compile rocksdb with hdfs support, please set the following
|
||||
enviroment variables appropriately:
|
||||
USE_HDFS=1
|
||||
JAVA_HOME=/usr/local/jdk-6u22-64
|
||||
|
||||
+31
-36
@@ -1,37 +1,22 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright (c) 2012 Facebook. All rights reserved.
|
||||
|
||||
#ifndef LEVELDB_HDFS_FILE_H
|
||||
#define LEVELDB_HDFS_FILE_H
|
||||
// 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.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <iostream>
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
#ifdef USE_HDFS
|
||||
#include "hdfs/hdfs.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static const std::string kProto = "hdfs://";
|
||||
static const std::string pathsep = "/";
|
||||
@@ -55,7 +40,7 @@ private:
|
||||
};
|
||||
|
||||
//
|
||||
// The HDFS environment for leveldb. This class overrides all the
|
||||
// The HDFS environment for rocksdb. This class overrides all the
|
||||
// file/dir access methods and delegates the thread-mgmt methods to the
|
||||
// default posix environment.
|
||||
//
|
||||
@@ -81,6 +66,10 @@ class HdfsEnv : public Env {
|
||||
virtual Status NewWritableFile(const std::string& fname,
|
||||
WritableFile** result);
|
||||
|
||||
virtual Status NewRandomRWFile(const std::string& fname,
|
||||
unique_ptr<RandomRWFile>* result,
|
||||
const EnvOptions& options);
|
||||
|
||||
virtual bool FileExists(const std::string& fname);
|
||||
|
||||
virtual Status GetChildren(const std::string& path,
|
||||
@@ -107,8 +96,9 @@ class HdfsEnv : public Env {
|
||||
|
||||
virtual Status NewLogger(const std::string& fname, Logger** result);
|
||||
|
||||
virtual void Schedule( void (*function)(void* arg), void* arg) {
|
||||
posixEnv->Schedule(function, arg);
|
||||
virtual void Schedule(void (*function)(void* arg), void* arg,
|
||||
Priority pri = LOW) {
|
||||
posixEnv->Schedule(function, arg, pri);
|
||||
}
|
||||
|
||||
virtual void StartThread(void (*function)(void* arg), void* arg) {
|
||||
@@ -140,8 +130,8 @@ class HdfsEnv : public Env {
|
||||
return posixEnv->GetAbsolutePath(db_path, output_path);
|
||||
}
|
||||
|
||||
virtual void SetBackgroundThreads(int number) {
|
||||
posixEnv->SetBackgroundThreads(number);
|
||||
virtual void SetBackgroundThreads(int number, Priority pri = LOW) {
|
||||
posixEnv->SetBackgroundThreads(number, pri);
|
||||
}
|
||||
|
||||
virtual std::string TimeToString(uint64_t number) {
|
||||
@@ -213,12 +203,12 @@ class HdfsEnv : public Env {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#else // USE_HDFS
|
||||
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
static const Status notsup;
|
||||
|
||||
@@ -226,7 +216,7 @@ class HdfsEnv : public Env {
|
||||
|
||||
public:
|
||||
HdfsEnv(const std::string& fsname) {
|
||||
fprintf(stderr, "You have not build leveldb with HDFS support\n");
|
||||
fprintf(stderr, "You have not build rocksdb with HDFS support\n");
|
||||
fprintf(stderr, "Please see hdfs/README for details\n");
|
||||
throw new std::exception();
|
||||
}
|
||||
@@ -250,6 +240,12 @@ class HdfsEnv : public Env {
|
||||
return notsup;
|
||||
}
|
||||
|
||||
virtual Status NewRandomRWFile(const std::string& fname,
|
||||
unique_ptr<RandomRWFile>* result,
|
||||
const EnvOptions& options) {
|
||||
return notsup;
|
||||
}
|
||||
|
||||
virtual bool FileExists(const std::string& fname){return false;}
|
||||
|
||||
virtual Status GetChildren(const std::string& path,
|
||||
@@ -279,7 +275,8 @@ class HdfsEnv : public Env {
|
||||
virtual Status NewLogger(const std::string& fname,
|
||||
shared_ptr<Logger>* result){return notsup;}
|
||||
|
||||
virtual void Schedule( void (*function)(void* arg), void* arg) {}
|
||||
virtual void Schedule(void (*function)(void* arg), void* arg,
|
||||
Priority pri = LOW) {}
|
||||
|
||||
virtual void StartThread(void (*function)(void* arg), void* arg) {}
|
||||
|
||||
@@ -296,12 +293,10 @@ class HdfsEnv : public Env {
|
||||
virtual Status GetAbsolutePath(const std::string& db_path,
|
||||
std::string* outputpath) {return notsup;}
|
||||
|
||||
virtual void SetBackgroundThreads(int number) {}
|
||||
virtual void SetBackgroundThreads(int number, Priority pri = LOW) {}
|
||||
|
||||
virtual std::string TimeToString(uint64_t number) { return "";}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // USE_HDFS
|
||||
|
||||
#endif // LEVELDB_HDFS_FILE_H
|
||||
|
||||
+5
-18
@@ -1,21 +1,8 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// 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 LIBHDFS_HDFS_H
|
||||
#define LIBHDFS_HDFS_H
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include "helpers/memenv/memenv.h"
|
||||
|
||||
#include "leveldb/env.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "rocksdb/status.h"
|
||||
#include "port/port.h"
|
||||
#include "util/mutexlock.h"
|
||||
#include <map>
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -383,4 +383,4 @@ Env* NewMemEnv(Env* base_env) {
|
||||
return new InMemoryEnv(base_env);
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_
|
||||
#define STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_
|
||||
|
||||
namespace leveldb {
|
||||
#ifndef STORAGE_ROCKSDB_HELPERS_MEMENV_MEMENV_H_
|
||||
#define STORAGE_ROCKSDB_HELPERS_MEMENV_MEMENV_H_
|
||||
namespace rocksdb {
|
||||
|
||||
class Env;
|
||||
|
||||
@@ -15,6 +14,6 @@ class Env;
|
||||
// *base_env must remain live while the result is in use.
|
||||
Env* NewMemEnv(Env* base_env);
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_HELPERS_MEMENV_MEMENV_H_
|
||||
#endif // STORAGE_ROCKSDB_HELPERS_MEMENV_MEMENV_H_
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
#include "helpers/memenv/memenv.h"
|
||||
|
||||
#include "db/db_impl.h"
|
||||
#include "leveldb/db.h"
|
||||
#include "leveldb/env.h"
|
||||
#include "rocksdb/db.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/testharness.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class MemEnvTest {
|
||||
public:
|
||||
@@ -215,7 +215,7 @@ TEST(MemEnvTest, DBTest) {
|
||||
delete iterator;
|
||||
|
||||
DBImpl* dbi = reinterpret_cast<DBImpl*>(db);
|
||||
ASSERT_OK(dbi->TEST_CompactMemTable());
|
||||
ASSERT_OK(dbi->TEST_FlushMemTable());
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
std::string res;
|
||||
@@ -226,8 +226,8 @@ TEST(MemEnvTest, DBTest) {
|
||||
delete db;
|
||||
}
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return leveldb::test::RunAllTests();
|
||||
return rocksdb::test::RunAllTests();
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright 2008-present Facebook. All Rights Reserved.
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_LDB_TOOL_H
|
||||
#define STORAGE_LEVELDB_INCLUDE_LDB_TOOL_H
|
||||
#include "leveldb/options.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class LDBTool {
|
||||
public:
|
||||
void Run(int argc, char** argv, Options = Options());
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_LDB_TOOL_H
|
||||
@@ -1,88 +0,0 @@
|
||||
// This file contains the interface that must be implemented by any collection
|
||||
// to be used as the backing store for a MemTable. Such a collection must
|
||||
// satisfy the following properties:
|
||||
// (1) It does not store duplicate items.
|
||||
// (2) It uses MemTableRep::KeyComparator to compare items for iteration and
|
||||
// equality.
|
||||
// (3) It can be accessed concurrently by multiple readers but need not support
|
||||
// concurrent writes.
|
||||
// (4) Items are never deleted.
|
||||
// The liberal use of assertions is encouraged to enforce (1).
|
||||
|
||||
#ifndef STORAGE_LEVELDB_DB_TABLE_H_
|
||||
#define STORAGE_LEVELDB_DB_TABLE_H_
|
||||
|
||||
#include <memory>
|
||||
#include "leveldb/arena.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
class MemTableRep {
|
||||
public:
|
||||
// KeyComparator(a, b) returns a negative value if a is less than b, 0 if they
|
||||
// are equal, and a positive value if b is greater than a
|
||||
class KeyComparator {
|
||||
public:
|
||||
virtual int operator()(const char* a, const char* b) const = 0;
|
||||
virtual ~KeyComparator() { }
|
||||
};
|
||||
|
||||
// Insert key into the collection. (The caller will pack key and value into a
|
||||
// single buffer and pass that in as the parameter to Insert)
|
||||
// REQUIRES: nothing that compares equal to key is currently in the
|
||||
// collection.
|
||||
virtual void Insert(const char* key) = 0;
|
||||
|
||||
// Returns true iff an entry that compares equal to key is in the collection.
|
||||
virtual bool Contains(const char* key) const = 0;
|
||||
|
||||
virtual ~MemTableRep() { }
|
||||
|
||||
// Iteration over the contents of a skip collection
|
||||
class Iterator {
|
||||
public:
|
||||
// Initialize an iterator over the specified collection.
|
||||
// The returned iterator is not valid.
|
||||
// explicit Iterator(const MemTableRep* collection);
|
||||
virtual ~Iterator() { };
|
||||
|
||||
// Returns true iff the iterator is positioned at a valid node.
|
||||
virtual bool Valid() const = 0;
|
||||
|
||||
// Returns the key at the current position.
|
||||
// REQUIRES: Valid()
|
||||
virtual const char* key() const = 0;
|
||||
|
||||
// Advances to the next position.
|
||||
// REQUIRES: Valid()
|
||||
virtual void Next() = 0;
|
||||
|
||||
// Advances to the previous position.
|
||||
// REQUIRES: Valid()
|
||||
virtual void Prev() = 0;
|
||||
|
||||
// Advance to the first entry with a key >= target
|
||||
virtual void Seek(const char* target) = 0;
|
||||
|
||||
// Position at the first entry in collection.
|
||||
// Final state of iterator is Valid() iff collection is not empty.
|
||||
virtual void SeekToFirst() = 0;
|
||||
|
||||
// Position at the last entry in collection.
|
||||
// Final state of iterator is Valid() iff collection is not empty.
|
||||
virtual void SeekToLast() = 0;
|
||||
};
|
||||
|
||||
virtual std::shared_ptr<Iterator> GetIterator() = 0;
|
||||
};
|
||||
|
||||
class MemTableRepFactory {
|
||||
public:
|
||||
virtual ~MemTableRepFactory() { };
|
||||
virtual std::shared_ptr<MemTableRep> CreateMemTableRep(
|
||||
MemTableRep::KeyComparator&, Arena* arena) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STORAGE_LEVELDB_DB_TABLE_H_
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_PERF_CONTEXT_H
|
||||
#define STORAGE_LEVELDB_INCLUDE_PERF_CONTEXT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
// A thread local context for gathering performance counter efficiently
|
||||
// and transparently.
|
||||
|
||||
struct PerfContext {
|
||||
|
||||
void Reset(); // reset all performance counters to zero
|
||||
|
||||
|
||||
uint64_t user_key_comparison_count; // total number of user key comparisons
|
||||
};
|
||||
|
||||
extern __thread PerfContext perf_context;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_TYPES_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_TYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
// Define all public custom types here.
|
||||
|
||||
// Represents a sequence number in a WAL file.
|
||||
typedef uint64_t SequenceNumber;
|
||||
|
||||
} // namespace leveldb
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_TYPES_H_
|
||||
@@ -1,57 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_ROCKSDB_UNIVERSAL_COMPACTION_OPTIONS_H
|
||||
#define STORAGE_ROCKSDB_UNIVERSAL_COMPACTION_OPTIONS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <climits>
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/statistics.h"
|
||||
|
||||
namespace leveldb {
|
||||
|
||||
//
|
||||
// Algorithm used to make a compaction request stop picking new files
|
||||
// into a single compaction run
|
||||
//
|
||||
enum CompactionStopStyle {
|
||||
kCompactionStopStyleSimilarSize, // pick files of similar size
|
||||
kCompactionStopStyleTotalSize // total size of picked files > next file
|
||||
};
|
||||
|
||||
class CompactionOptionsUniversal {
|
||||
public:
|
||||
|
||||
// Percentage flexibilty while comparing file size. If the candidate file(s)
|
||||
// size is 1% smaller than the next file's size, then include next file into
|
||||
// this candidate set. // Default: 1
|
||||
unsigned int size_ratio;
|
||||
|
||||
// The minimum number of files in a single compaction run. Default: 2
|
||||
unsigned int min_merge_width;
|
||||
|
||||
// The maximum number of files in a single compaction run. Default: INT_MAX
|
||||
unsigned int max_merge_width;
|
||||
|
||||
// The algorithm used to stop picking files into a single compaction run
|
||||
// Default: kCompactionStopStyleTotalSize
|
||||
CompactionStopStyle stop_style;
|
||||
|
||||
// Default set of parameters
|
||||
CompactionOptionsUniversal() :
|
||||
size_ratio(1),
|
||||
min_merge_width(2),
|
||||
max_merge_width(UINT_MAX),
|
||||
stop_style(kCompactionStopStyleTotalSize) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
|
||||
#endif // STORAGE_ROCKSDB_UNIVERSAL_COMPACTION_OPTIONS_H
|
||||
@@ -5,10 +5,13 @@
|
||||
// Arena class defines memory allocation methods. It's used by memtable and
|
||||
// skiplist.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_ARENA_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_ARENA_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_ARENA_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_ARENA_H_
|
||||
|
||||
namespace leveldb {
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class Arena {
|
||||
public:
|
||||
@@ -33,6 +36,6 @@ class Arena {
|
||||
void operator=(const Arena&);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_ARENA_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_ARENA_H_
|
||||
@@ -37,8 +37,8 @@
|
||||
(5) All of the pointer arguments must be non-NULL.
|
||||
*/
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_C_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_C_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_C_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_C_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -278,4 +278,4 @@ extern void leveldb_env_destroy(leveldb_env_t*);
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* STORAGE_LEVELDB_INCLUDE_C_H_ */
|
||||
#endif /* STORAGE_ROCKSDB_INCLUDE_C_H_ */
|
||||
@@ -15,23 +15,35 @@
|
||||
// they want something more sophisticated (like scan-resistance, a
|
||||
// custom eviction policy, variable cache sizing, etc.)
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_CACHE_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_CACHE_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_CACHE_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_CACHE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include "leveldb/slice.h"
|
||||
#include "rocksdb/slice.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
using std::shared_ptr;
|
||||
|
||||
class Cache;
|
||||
|
||||
// Create a new cache with a fixed size capacity. This implementation
|
||||
// of Cache uses a least-recently-used eviction policy.
|
||||
// Create a new cache with a fixed size capacity. The cache is sharded
|
||||
// to 2^numShardBits shards, by hash of the key. The total capacity
|
||||
// is divided and evenly assigned to each shard. Inside each shard,
|
||||
// the eviction is done in two passes: first try to free spaces by
|
||||
// evicting entries that are among the most least used removeScanCountLimit
|
||||
// entries and do not have reference other than by the cache itself, in
|
||||
// the least-used order. If not enough space is freed, further free the
|
||||
// entries in least used order.
|
||||
//
|
||||
// The functions without parameter numShardBits and/or removeScanCountLimit
|
||||
// use default values. removeScanCountLimit's default value is 0, which
|
||||
// means a strict LRU order inside each shard.
|
||||
extern shared_ptr<Cache> NewLRUCache(size_t capacity);
|
||||
extern shared_ptr<Cache> NewLRUCache(size_t capacity, int numShardBits);
|
||||
extern shared_ptr<Cache> NewLRUCache(size_t capacity, int numShardBits,
|
||||
int removeScanCountLimit);
|
||||
|
||||
class Cache {
|
||||
public:
|
||||
@@ -101,6 +113,6 @@ class Cache {
|
||||
void operator=(const Cache&);
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_UTIL_CACHE_H_
|
||||
#endif // STORAGE_ROCKSDB_UTIL_CACHE_H_
|
||||
@@ -2,12 +2,12 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_COMPACTION_FILTER_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_COMPACTION_FILTER_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_COMPACTION_FILTER_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_COMPACTION_FILTER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Slice;
|
||||
|
||||
@@ -66,6 +66,6 @@ class DefaultCompactionFilterFactory : public CompactionFilterFactory {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_COMPACTION_FILTER_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_COMPACTION_FILTER_H_
|
||||
@@ -2,18 +2,18 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_COMPARATOR_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_COMPARATOR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Slice;
|
||||
|
||||
// A Comparator object provides a total order across slices that are
|
||||
// used as keys in an sstable or a database. A Comparator implementation
|
||||
// must be thread-safe since leveldb may invoke its methods concurrently
|
||||
// must be thread-safe since rocksdb may invoke its methods concurrently
|
||||
// from multiple threads.
|
||||
class Comparator {
|
||||
public:
|
||||
@@ -33,7 +33,7 @@ class Comparator {
|
||||
// the comparator implementation changes in a way that will cause
|
||||
// the relative ordering of any two keys to change.
|
||||
//
|
||||
// Names starting with "leveldb." are reserved and should not be used
|
||||
// Names starting with "rocksdb." are reserved and should not be used
|
||||
// by any clients of this package.
|
||||
virtual const char* Name() const = 0;
|
||||
|
||||
@@ -58,6 +58,6 @@ class Comparator {
|
||||
// must not be deleted.
|
||||
extern const Comparator* BytewiseComparator();
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_COMPARATOR_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_COMPARATOR_H_
|
||||
@@ -2,19 +2,19 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_DB_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_DB_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_DB_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_DB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "leveldb/iterator.h"
|
||||
#include "leveldb/options.h"
|
||||
#include "leveldb/types.h"
|
||||
#include "leveldb/transaction_log.h"
|
||||
#include "rocksdb/iterator.h"
|
||||
#include "rocksdb/options.h"
|
||||
#include "rocksdb/types.h"
|
||||
#include "rocksdb/transaction_log.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
using std::unique_ptr;
|
||||
|
||||
@@ -28,6 +28,17 @@ struct WriteOptions;
|
||||
struct FlushOptions;
|
||||
class WriteBatch;
|
||||
|
||||
// Metadata associated with each SST file.
|
||||
struct LiveFileMetaData {
|
||||
std::string name; // Name of the file
|
||||
int level; // Level at which this file resides.
|
||||
size_t size; // File size in bytes.
|
||||
std::string smallestkey; // Smallest user defined key in the file.
|
||||
std::string largestkey; // Largest user defined key in the file.
|
||||
SequenceNumber smallest_seqno; // smallest seqno in file
|
||||
SequenceNumber largest_seqno; // largest seqno in file
|
||||
};
|
||||
|
||||
// Abstract handle to particular state of a DB.
|
||||
// A Snapshot is an immutable object and can therefore be safely
|
||||
// accessed from multiple threads without any external synchronization.
|
||||
@@ -164,11 +175,11 @@ class DB {
|
||||
//
|
||||
// Valid property names include:
|
||||
//
|
||||
// "leveldb.num-files-at-level<N>" - return the number of files at level <N>,
|
||||
// "rocksdb.num-files-at-level<N>" - return the number of files at level <N>,
|
||||
// where <N> is an ASCII representation of a level number (e.g. "0").
|
||||
// "leveldb.stats" - returns a multi-line string that describes statistics
|
||||
// "rocksdb.stats" - returns a multi-line string that describes statistics
|
||||
// about the internal operation of the DB.
|
||||
// "leveldb.sstables" - returns a multi-line string that describes all
|
||||
// "rocksdb.sstables" - returns a multi-line string that describes all
|
||||
// of the sstables that make up the db contents.
|
||||
virtual bool GetProperty(const Slice& property, std::string* value) = 0;
|
||||
|
||||
@@ -198,9 +209,10 @@ class DB {
|
||||
// after compaction is reduced, that level might not be appropriate for
|
||||
// hosting all the files. In this case, client could set reduce_level
|
||||
// to true, to move the files back to the minimum level capable of holding
|
||||
// the data set.
|
||||
// the data set or a given level (specified by non-negative target_level).
|
||||
virtual void CompactRange(const Slice* begin, const Slice* end,
|
||||
bool reduce_level = false) = 0;
|
||||
bool reduce_level = false,
|
||||
int target_level = -1) = 0;
|
||||
|
||||
// Number of levels used for this DB.
|
||||
virtual int NumberLevels() = 0;
|
||||
@@ -223,21 +235,30 @@ class DB {
|
||||
// Allow compactions to delete obselete files.
|
||||
virtual Status EnableFileDeletions() = 0;
|
||||
|
||||
// GetLiveFiles followed by GetSortedWalFiles can generate a lossless backup
|
||||
|
||||
// THIS METHOD IS DEPRECATED. Use the GetTableMetaData to get more
|
||||
// detailed information on the live files.
|
||||
// Retrieve the list of all files in the database. The files are
|
||||
// relative to the dbname and are not absolute paths. This list
|
||||
// can be used to generate a backup. The valid size of the manifest
|
||||
// file is returned in manifest_file_size. The manifest file is
|
||||
// an ever growing file, but only the portion specified
|
||||
// by manifest_file_size is valid for this snapshot.
|
||||
// relative to the dbname and are not absolute paths. The valid size of the
|
||||
// manifest file is returned in manifest_file_size. The manifest file is an
|
||||
// ever growing file, but only the portion specified by manifest_file_size is
|
||||
// valid for this snapshot.
|
||||
// Setting flush_memtable to true does Flush before recording the live files.
|
||||
// Setting flush_memtable to false is useful when we don't want to wait for
|
||||
// flush which may have to wait for compaction to complete taking an
|
||||
// indeterminate time. But this will have to use GetSortedWalFiles after
|
||||
// GetLiveFiles to compensate for memtables missed in this snapshot due to the
|
||||
// absence of Flush, by WAL files to recover the database consistently later
|
||||
virtual Status GetLiveFiles(std::vector<std::string>&,
|
||||
uint64_t* manifest_file_size) = 0;
|
||||
uint64_t* manifest_file_size,
|
||||
bool flush_memtable = true) = 0;
|
||||
|
||||
// Retrieve the sorted list of all wal files with earliest file first
|
||||
virtual Status GetSortedWalFiles(VectorLogPtr& files) = 0;
|
||||
|
||||
// Delete wal files in files. These can be either live or archived.
|
||||
// Returns Status::OK if all files could be deleted, otherwise Status::IOError
|
||||
// which contains information about files that could not be deleted.
|
||||
virtual Status DeleteWalFiles(const VectorLogPtr& files) = 0;
|
||||
|
||||
// The sequence number of the most recent transaction.
|
||||
@@ -256,6 +277,19 @@ class DB {
|
||||
// an update is read.
|
||||
virtual Status GetUpdatesSince(SequenceNumber seq_number,
|
||||
unique_ptr<TransactionLogIterator>* iter) = 0;
|
||||
|
||||
// Delete the file name from the db directory and update the internal
|
||||
// state to reflect that.
|
||||
virtual Status DeleteFile(std::string name) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
// Returns a list of all table files with their level, start key
|
||||
// and end key
|
||||
virtual void GetLiveFilesMetaData(
|
||||
std::vector<LiveFileMetaData> *metadata) {
|
||||
}
|
||||
|
||||
private:
|
||||
// No copying allowed
|
||||
DB(const DB&);
|
||||
@@ -272,6 +306,6 @@ Status DestroyDB(const std::string& name, const Options& options);
|
||||
// on a database that contains important information.
|
||||
Status RepairDB(const std::string& dbname, const Options& options);
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_DB_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_DB_H_
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// An Env is an interface used by the leveldb implementation to access
|
||||
// An Env is an interface used by the rocksdb implementation to access
|
||||
// operating system functionality like the filesystem etc. Callers
|
||||
// may wish to provide a custom Env object when opening a database to
|
||||
// get fine gain control; e.g., to rate limit file system operations.
|
||||
@@ -10,17 +10,17 @@
|
||||
// All Env implementations are safe for concurrent access from
|
||||
// multiple threads without any external synchronization.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_ENV_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_ENV_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_ENV_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_ENV_H_
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class FileLock;
|
||||
class Logger;
|
||||
@@ -28,6 +28,7 @@ class RandomAccessFile;
|
||||
class SequentialFile;
|
||||
class Slice;
|
||||
class WritableFile;
|
||||
class RandomRWFile;
|
||||
class Options;
|
||||
|
||||
using std::unique_ptr;
|
||||
@@ -41,7 +42,7 @@ struct EnvOptions {
|
||||
EnvOptions();
|
||||
|
||||
// construct from Options
|
||||
EnvOptions(const Options& options);
|
||||
explicit EnvOptions(const Options& options);
|
||||
|
||||
// If true, then allow caching of data in environment buffers
|
||||
bool use_os_buffer;
|
||||
@@ -72,7 +73,7 @@ class Env {
|
||||
// system. Sophisticated users may wish to provide their own Env
|
||||
// implementation instead of relying on this default environment.
|
||||
//
|
||||
// The result of Default() belongs to leveldb and must never be deleted.
|
||||
// The result of Default() belongs to rocksdb and must never be deleted.
|
||||
static Env* Default();
|
||||
|
||||
// Create a brand new sequentially-readable file with the specified name.
|
||||
@@ -109,6 +110,15 @@ class Env {
|
||||
unique_ptr<WritableFile>* result,
|
||||
const EnvOptions& options) = 0;
|
||||
|
||||
// Create an object that both reads and writes to a file on
|
||||
// specified offsets (random access). If file already exists,
|
||||
// does not overwrite it. On success, stores a pointer to the
|
||||
// new file in *result and returns OK. On failure stores nullptr
|
||||
// in *result and returns non-OK.
|
||||
virtual Status NewRandomRWFile(const std::string& fname,
|
||||
unique_ptr<RandomRWFile>* result,
|
||||
const EnvOptions& options) = 0;
|
||||
|
||||
// Returns true iff the named file exists.
|
||||
virtual bool FileExists(const std::string& fname) = 0;
|
||||
|
||||
@@ -162,15 +172,20 @@ class Env {
|
||||
// REQUIRES: lock has not already been unlocked.
|
||||
virtual Status UnlockFile(FileLock* lock) = 0;
|
||||
|
||||
// Arrange to run "(*function)(arg)" once in a background thread.
|
||||
//
|
||||
enum Priority { LOW, HIGH, TOTAL };
|
||||
|
||||
// Arrange to run "(*function)(arg)" once in a background thread, in
|
||||
// the thread pool specified by pri. By default, jobs go to the 'LOW'
|
||||
// priority thread pool.
|
||||
|
||||
// "function" may run in an unspecified thread. Multiple functions
|
||||
// added to the same Env may run concurrently in different threads.
|
||||
// I.e., the caller may not assume that background work items are
|
||||
// serialized.
|
||||
virtual void Schedule(
|
||||
void (*function)(void* arg),
|
||||
void* arg) = 0;
|
||||
void* arg,
|
||||
Priority pri = LOW) = 0;
|
||||
|
||||
// Start a new thread, invoking "function(arg)" within the new thread.
|
||||
// When "function(arg)" returns, the thread will be destroyed.
|
||||
@@ -190,6 +205,13 @@ class Env {
|
||||
// useful for computing deltas of time.
|
||||
virtual uint64_t NowMicros() = 0;
|
||||
|
||||
// Returns the number of nano-seconds since some fixed point in time. Only
|
||||
// useful for computing deltas of time in one run.
|
||||
// Default implementation simply relies on NowMicros
|
||||
virtual uint64_t NowNanos() {
|
||||
return NowMicros() * 1000;
|
||||
}
|
||||
|
||||
// Sleep/delay the thread for the perscribed number of micro-seconds.
|
||||
virtual void SleepForMicroseconds(int micros) = 0;
|
||||
|
||||
@@ -203,13 +225,17 @@ class Env {
|
||||
virtual Status GetAbsolutePath(const std::string& db_path,
|
||||
std::string* output_path) = 0;
|
||||
|
||||
// The number of background worker threads for this environment.
|
||||
// default: 1
|
||||
virtual void SetBackgroundThreads(int number) = 0;
|
||||
// The number of background worker threads of a specific thread pool
|
||||
// for this environment. 'LOW' is the default pool.
|
||||
// default number: 1
|
||||
virtual void SetBackgroundThreads(int number, Priority pri = LOW) = 0;
|
||||
|
||||
// Converts seconds-since-Jan-01-1970 to a printable string
|
||||
virtual std::string TimeToString(uint64_t time) = 0;
|
||||
|
||||
// Generates a unique id that can be used to identify a db
|
||||
virtual std::string GenerateUniqueId();
|
||||
|
||||
private:
|
||||
// No copying allowed
|
||||
Env(const Env&);
|
||||
@@ -240,6 +266,13 @@ class SequentialFile {
|
||||
//
|
||||
// REQUIRES: External synchronization
|
||||
virtual Status Skip(uint64_t n) = 0;
|
||||
|
||||
// Remove any kind of caching of data from the offset to offset+length
|
||||
// of this file. If the length is 0, then it refers to the end of file.
|
||||
// If the system is not caching the file contents, then this is a noop.
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) {
|
||||
return Status::NotSupported("InvalidateCache not supported.");
|
||||
}
|
||||
};
|
||||
|
||||
// A file abstraction for randomly reading the contents of a file.
|
||||
@@ -285,6 +318,12 @@ class RandomAccessFile {
|
||||
|
||||
virtual void Hint(AccessPattern pattern) {}
|
||||
|
||||
// Remove any kind of caching of data from the offset to offset+length
|
||||
// of this file. If the length is 0, then it refers to the end of file.
|
||||
// If the system is not caching the file contents, then this is a noop.
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) {
|
||||
return Status::NotSupported("InvalidateCache not supported.");
|
||||
}
|
||||
};
|
||||
|
||||
// A file abstraction for sequential writing. The implementation
|
||||
@@ -303,7 +342,7 @@ class WritableFile {
|
||||
|
||||
/*
|
||||
* Sync data and/or metadata as well.
|
||||
* By default, sync only metadata.
|
||||
* By default, sync only data.
|
||||
* Override this method for environments where we need to sync
|
||||
* metadata as well.
|
||||
*/
|
||||
@@ -334,6 +373,14 @@ class WritableFile {
|
||||
*block_size = preallocation_block_size_;
|
||||
}
|
||||
|
||||
// Remove any kind of caching of data from the offset to offset+length
|
||||
// of this file. If the length is 0, then it refers to the end of file.
|
||||
// If the system is not caching the file contents, then this is a noop.
|
||||
// This call has no effect on dirty pages in the cache.
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) {
|
||||
return Status::NotSupported("InvalidateCache not supported.");
|
||||
}
|
||||
|
||||
protected:
|
||||
// PrepareWrite performs any necessary preparation for a write
|
||||
// before the write actually occurs. This allows for pre-allocation
|
||||
@@ -384,6 +431,55 @@ class WritableFile {
|
||||
void operator=(const WritableFile&);
|
||||
};
|
||||
|
||||
// A file abstraction for random reading and writing.
|
||||
class RandomRWFile {
|
||||
public:
|
||||
RandomRWFile() {}
|
||||
virtual ~RandomRWFile() {}
|
||||
|
||||
// Write data from Slice data to file starting from offset
|
||||
// Returns IOError on failure, but does not guarantee
|
||||
// atomicity of a write. Returns OK status on success.
|
||||
//
|
||||
// Safe for concurrent use.
|
||||
virtual Status Write(uint64_t offset, const Slice& data) = 0;
|
||||
// Read up to "n" bytes from the file starting at "offset".
|
||||
// "scratch[0..n-1]" may be written by this routine. Sets "*result"
|
||||
// to the data that was read (including if fewer than "n" bytes were
|
||||
// successfully read). May set "*result" to point at data in
|
||||
// "scratch[0..n-1]", so "scratch[0..n-1]" must be live when
|
||||
// "*result" is used. If an error was encountered, returns a non-OK
|
||||
// status.
|
||||
//
|
||||
// Safe for concurrent use by multiple threads.
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const = 0;
|
||||
virtual Status Close() = 0; // closes the file
|
||||
virtual Status Sync() = 0; // sync data
|
||||
|
||||
/*
|
||||
* Sync data and/or metadata as well.
|
||||
* By default, sync only data.
|
||||
* Override this method for environments where we need to sync
|
||||
* metadata as well.
|
||||
*/
|
||||
virtual Status Fsync() {
|
||||
return Sync();
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre-allocate space for a file.
|
||||
*/
|
||||
virtual Status Allocate(off_t offset, off_t len) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
private:
|
||||
// No copying allowed
|
||||
RandomRWFile(const RandomRWFile&);
|
||||
void operator=(const RandomRWFile&);
|
||||
};
|
||||
|
||||
// An interface for writing log messages.
|
||||
class Logger {
|
||||
public:
|
||||
@@ -463,6 +559,10 @@ class EnvWrapper : public Env {
|
||||
const EnvOptions& options) {
|
||||
return target_->NewWritableFile(f, r, options);
|
||||
}
|
||||
Status NewRandomRWFile(const std::string& f, unique_ptr<RandomRWFile>* r,
|
||||
const EnvOptions& options) {
|
||||
return target_->NewRandomRWFile(f, r, options);
|
||||
}
|
||||
bool FileExists(const std::string& f) { return target_->FileExists(f); }
|
||||
Status GetChildren(const std::string& dir, std::vector<std::string>* r) {
|
||||
return target_->GetChildren(dir, r);
|
||||
@@ -489,8 +589,8 @@ class EnvWrapper : public Env {
|
||||
return target_->LockFile(f, l);
|
||||
}
|
||||
Status UnlockFile(FileLock* l) { return target_->UnlockFile(l); }
|
||||
void Schedule(void (*f)(void*), void* a) {
|
||||
return target_->Schedule(f, a);
|
||||
void Schedule(void (*f)(void*), void* a, Priority pri) {
|
||||
return target_->Schedule(f, a, pri);
|
||||
}
|
||||
void StartThread(void (*f)(void*), void* a) {
|
||||
return target_->StartThread(f, a);
|
||||
@@ -518,8 +618,8 @@ class EnvWrapper : public Env {
|
||||
std::string* output_path) {
|
||||
return target_->GetAbsolutePath(db_path, output_path);
|
||||
}
|
||||
void SetBackgroundThreads(int num) {
|
||||
return target_->SetBackgroundThreads(num);
|
||||
void SetBackgroundThreads(int num, Priority pri) {
|
||||
return target_->SetBackgroundThreads(num, pri);
|
||||
}
|
||||
std::string TimeToString(uint64_t time) {
|
||||
return target_->TimeToString(time);
|
||||
@@ -529,6 +629,6 @@ class EnvWrapper : public Env {
|
||||
Env* target_;
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_ENV_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_ENV_H_
|
||||
@@ -4,8 +4,8 @@
|
||||
//
|
||||
// A database can be configured with a custom FilterPolicy object.
|
||||
// This object is responsible for creating a small filter from a set
|
||||
// of keys. These filters are stored in leveldb and are consulted
|
||||
// automatically by leveldb to decide whether or not to read some
|
||||
// of keys. These filters are stored in rocksdb and are consulted
|
||||
// automatically by rocksdb to decide whether or not to read some
|
||||
// information from disk. In many cases, a filter can cut down the
|
||||
// number of disk seeks form a handful to a single disk seek per
|
||||
// DB::Get() call.
|
||||
@@ -13,12 +13,12 @@
|
||||
// Most people will want to use the builtin bloom filter support (see
|
||||
// NewBloomFilterPolicy() below).
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_FILTER_POLICY_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_FILTER_POLICY_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Slice;
|
||||
|
||||
@@ -67,4 +67,4 @@ extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key);
|
||||
|
||||
}
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_FILTER_POLICY_H_
|
||||
@@ -12,13 +12,13 @@
|
||||
// non-const method, all threads accessing the same Iterator must use
|
||||
// external synchronization.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_ITERATOR_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_ITERATOR_H_
|
||||
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/status.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/status.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
@@ -65,6 +65,8 @@ class Iterator {
|
||||
virtual Slice value() const = 0;
|
||||
|
||||
// If an error has occurred, return it. Else return an ok status.
|
||||
// If non-blocking IO is requested and this operation cannot be
|
||||
// satisfied without doing some IO, then this returns Status::Incomplete().
|
||||
virtual Status status() const = 0;
|
||||
|
||||
// Clients are allowed to register function/arg1/arg2 triples that
|
||||
@@ -95,6 +97,6 @@ extern Iterator* NewEmptyIterator();
|
||||
// Return an empty iterator with the specified status.
|
||||
extern Iterator* NewErrorIterator(const Status& status);
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_ITERATOR_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_ITERATOR_H_
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2008-present Facebook. All Rights Reserved.
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_LDB_TOOL_H
|
||||
#define STORAGE_ROCKSDB_INCLUDE_LDB_TOOL_H
|
||||
#include "rocksdb/options.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class LDBTool {
|
||||
public:
|
||||
void Run(int argc, char** argv, Options = Options());
|
||||
};
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_LDB_TOOL_H
|
||||
@@ -0,0 +1,259 @@
|
||||
// This file contains the interface that must be implemented by any collection
|
||||
// to be used as the backing store for a MemTable. Such a collection must
|
||||
// satisfy the following properties:
|
||||
// (1) It does not store duplicate items.
|
||||
// (2) It uses MemTableRep::KeyComparator to compare items for iteration and
|
||||
// equality.
|
||||
// (3) It can be accessed concurrently by multiple readers and can support
|
||||
// during reads. However, it needn't support multiple concurrent writes.
|
||||
// (4) Items are never deleted.
|
||||
// The liberal use of assertions is encouraged to enforce (1).
|
||||
//
|
||||
// The factory will be passed an Arena object when a new MemTableRep is
|
||||
// requested. The API for this object is in rocksdb/arena.h.
|
||||
//
|
||||
// Users can implement their own memtable representations. We include four
|
||||
// types built in:
|
||||
// - SkipListRep: This is the default; it is backed by a skip list.
|
||||
// - TransformRep: This is backed by an std::unordered_map<Slice,
|
||||
// std::set>. On construction, they are given a SliceTransform object. This
|
||||
// object is applied to the user key of stored items which indexes into the
|
||||
// unordered map to yield a set containing all records that share the same user
|
||||
// key under the transform function.
|
||||
// - UnsortedRep: A subclass of TransformRep where the transform function is
|
||||
// the identity function. Optimized for point lookups.
|
||||
// - PrefixHashRep: A subclass of TransformRep where the transform function is
|
||||
// a fixed-size prefix extractor. If you use PrefixHashRepFactory, the transform
|
||||
// must be identical to options.prefix_extractor, otherwise it will be discarded
|
||||
// and the default will be used. It is optimized for ranged scans over a
|
||||
// prefix.
|
||||
// - VectorRep: This is backed by an unordered std::vector. On iteration, the
|
||||
// vector is sorted. It is intelligent about sorting; once the MarkReadOnly()
|
||||
// has been called, the vector will only be sorted once. It is optimized for
|
||||
// random-write-heavy workloads.
|
||||
//
|
||||
// The last four implementations are designed for situations in which
|
||||
// iteration over the entire collection is rare since doing so requires all the
|
||||
// keys to be copied into a sorted data structure.
|
||||
|
||||
#ifndef STORAGE_ROCKSDB_DB_MEMTABLEREP_H_
|
||||
#define STORAGE_ROCKSDB_DB_MEMTABLEREP_H_
|
||||
|
||||
#include <memory>
|
||||
#include "rocksdb/arena.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/slice_transform.h"
|
||||
|
||||
namespace rocksdb {
|
||||
|
||||
class MemTableRep {
|
||||
public:
|
||||
// KeyComparator provides a means to compare keys, which are internal keys
|
||||
// concatenated with values.
|
||||
class KeyComparator {
|
||||
public:
|
||||
// Compare a and b. Return a negative value if a is less than b, 0 if they
|
||||
// are equal, and a positive value if a is greater than b
|
||||
virtual int operator()(const char* a, const char* b) const = 0;
|
||||
|
||||
virtual ~KeyComparator() { }
|
||||
};
|
||||
|
||||
// Insert key into the collection. (The caller will pack key and value into a
|
||||
// single buffer and pass that in as the parameter to Insert)
|
||||
// REQUIRES: nothing that compares equal to key is currently in the
|
||||
// collection.
|
||||
virtual void Insert(const char* key) = 0;
|
||||
|
||||
// Returns true iff an entry that compares equal to key is in the collection.
|
||||
virtual bool Contains(const char* key) const = 0;
|
||||
|
||||
// Notify this table rep that it will no longer be added to. By default, does
|
||||
// nothing.
|
||||
virtual void MarkReadOnly() { }
|
||||
|
||||
// Report an approximation of how much memory has been used other than memory
|
||||
// that was allocated through the arena.
|
||||
virtual size_t ApproximateMemoryUsage() = 0;
|
||||
|
||||
virtual ~MemTableRep() { }
|
||||
|
||||
// Iteration over the contents of a skip collection
|
||||
class Iterator {
|
||||
public:
|
||||
// Initialize an iterator over the specified collection.
|
||||
// The returned iterator is not valid.
|
||||
// explicit Iterator(const MemTableRep* collection);
|
||||
virtual ~Iterator() { };
|
||||
|
||||
// Returns true iff the iterator is positioned at a valid node.
|
||||
virtual bool Valid() const = 0;
|
||||
|
||||
// Returns the key at the current position.
|
||||
// REQUIRES: Valid()
|
||||
virtual const char* key() const = 0;
|
||||
|
||||
// Advances to the next position.
|
||||
// REQUIRES: Valid()
|
||||
virtual void Next() = 0;
|
||||
|
||||
// Advances to the previous position.
|
||||
// REQUIRES: Valid()
|
||||
virtual void Prev() = 0;
|
||||
|
||||
// Advance to the first entry with a key >= target
|
||||
virtual void Seek(const char* target) = 0;
|
||||
|
||||
// Position at the first entry in collection.
|
||||
// Final state of iterator is Valid() iff collection is not empty.
|
||||
virtual void SeekToFirst() = 0;
|
||||
|
||||
// Position at the last entry in collection.
|
||||
// Final state of iterator is Valid() iff collection is not empty.
|
||||
virtual void SeekToLast() = 0;
|
||||
};
|
||||
|
||||
// Return an iterator over the keys in this representation.
|
||||
virtual std::shared_ptr<Iterator> GetIterator() = 0;
|
||||
|
||||
// Return an iterator over at least the keys with the specified user key. The
|
||||
// iterator may also allow access to other keys, but doesn't have to. Default:
|
||||
// GetIterator().
|
||||
virtual std::shared_ptr<Iterator> GetIterator(const Slice& user_key) {
|
||||
return GetIterator();
|
||||
}
|
||||
|
||||
// Return an iterator over at least the keys with the specified prefix. The
|
||||
// iterator may also allow access to other keys, but doesn't have to. Default:
|
||||
// GetIterator().
|
||||
virtual std::shared_ptr<Iterator> GetPrefixIterator(const Slice& prefix) {
|
||||
return GetIterator();
|
||||
}
|
||||
|
||||
protected:
|
||||
// When *key is an internal key concatenated with the value, returns the
|
||||
// user key.
|
||||
virtual Slice UserKey(const char* key) const;
|
||||
};
|
||||
|
||||
// This is the base class for all factories that are used by RocksDB to create
|
||||
// new MemTableRep objects
|
||||
class MemTableRepFactory {
|
||||
public:
|
||||
virtual ~MemTableRepFactory() { };
|
||||
virtual std::shared_ptr<MemTableRep> CreateMemTableRep(
|
||||
MemTableRep::KeyComparator&, Arena*) = 0;
|
||||
virtual const char* Name() const = 0;
|
||||
};
|
||||
|
||||
// This creates MemTableReps that are backed by an std::vector. On iteration,
|
||||
// the vector is sorted. This is useful for workloads where iteration is very
|
||||
// rare and writes are generally not issued after reads begin.
|
||||
//
|
||||
// Parameters:
|
||||
// count: Passed to the constructor of the underlying std::vector of each
|
||||
// VectorRep. On initialization, the underlying array will be at least count
|
||||
// bytes reserved for usage.
|
||||
class VectorRepFactory : public MemTableRepFactory {
|
||||
const size_t count_;
|
||||
public:
|
||||
explicit VectorRepFactory(size_t count = 0) : count_(count) { }
|
||||
virtual std::shared_ptr<MemTableRep> CreateMemTableRep(
|
||||
MemTableRep::KeyComparator&, Arena*) override;
|
||||
virtual const char* Name() const override {
|
||||
return "VectorRepFactory";
|
||||
}
|
||||
};
|
||||
|
||||
// This uses a skip list to store keys. It is the default.
|
||||
class SkipListFactory : public MemTableRepFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<MemTableRep> CreateMemTableRep(
|
||||
MemTableRep::KeyComparator&, Arena*) override;
|
||||
virtual const char* Name() const override {
|
||||
return "SkipListFactory";
|
||||
}
|
||||
};
|
||||
|
||||
// TransformReps are backed by an unordered map of buffers to buckets. When
|
||||
// looking up a key, the user key is extracted and a user-supplied transform
|
||||
// function (see rocksdb/slice_transform.h) is applied to get the key into the
|
||||
// unordered map. This allows the user to bin user keys based on arbitrary
|
||||
// criteria. Two example implementations are UnsortedRepFactory and
|
||||
// PrefixHashRepFactory.
|
||||
//
|
||||
// Iteration over the entire collection is implemented by dumping all the keys
|
||||
// into an std::set. Thus, these data structures are best used when iteration
|
||||
// over the entire collection is rare.
|
||||
//
|
||||
// Parameters:
|
||||
// transform: The SliceTransform to bucket user keys on. TransformRepFactory
|
||||
// owns the pointer.
|
||||
// bucket_count: Passed to the constructor of the underlying
|
||||
// std::unordered_map of each TransformRep. On initialization, the
|
||||
// underlying array will be at least bucket_count size.
|
||||
// num_locks: Number of read-write locks to have for the rep. Each bucket is
|
||||
// hashed onto a read-write lock which controls access to that lock. More
|
||||
// locks means finer-grained concurrency but more memory overhead.
|
||||
class TransformRepFactory : public MemTableRepFactory {
|
||||
public:
|
||||
explicit TransformRepFactory(const SliceTransform* transform,
|
||||
size_t bucket_count, size_t num_locks = 1000)
|
||||
: transform_(transform),
|
||||
bucket_count_(bucket_count),
|
||||
num_locks_(num_locks) { }
|
||||
|
||||
virtual ~TransformRepFactory() { delete transform_; }
|
||||
|
||||
virtual std::shared_ptr<MemTableRep> CreateMemTableRep(
|
||||
MemTableRep::KeyComparator&, Arena*) override;
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "TransformRepFactory";
|
||||
}
|
||||
|
||||
const SliceTransform* GetTransform() { return transform_; }
|
||||
|
||||
protected:
|
||||
const SliceTransform* transform_;
|
||||
const size_t bucket_count_;
|
||||
const size_t num_locks_;
|
||||
};
|
||||
|
||||
// UnsortedReps bin user keys based on an identity function transform -- that
|
||||
// is, transform(key) = key. This optimizes for point look-ups.
|
||||
//
|
||||
// Parameters: See TransformRepFactory.
|
||||
class UnsortedRepFactory : public TransformRepFactory {
|
||||
public:
|
||||
explicit UnsortedRepFactory(size_t bucket_count = 0, size_t num_locks = 1000)
|
||||
: TransformRepFactory(NewNoopTransform(),
|
||||
bucket_count,
|
||||
num_locks) { }
|
||||
virtual const char* Name() const override {
|
||||
return "UnsortedRepFactory";
|
||||
}
|
||||
};
|
||||
|
||||
// PrefixHashReps bin user keys based on a fixed-size prefix. This optimizes for
|
||||
// short ranged scans over a given prefix.
|
||||
//
|
||||
// Parameters: See TransformRepFactory.
|
||||
class PrefixHashRepFactory : public TransformRepFactory {
|
||||
public:
|
||||
explicit PrefixHashRepFactory(const SliceTransform* prefix_extractor,
|
||||
size_t bucket_count = 0, size_t num_locks = 1000)
|
||||
: TransformRepFactory(prefix_extractor, bucket_count, num_locks)
|
||||
{ }
|
||||
|
||||
virtual std::shared_ptr<MemTableRep> CreateMemTableRep(
|
||||
MemTableRep::KeyComparator&, Arena*) override;
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "PrefixHashRepFactory";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // STORAGE_ROCKSDB_DB_MEMTABLEREP_H_
|
||||
@@ -2,14 +2,14 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_MERGE_OPERATOR_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_MERGE_OPERATOR_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_MERGE_OPERATOR_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_MERGE_OPERATOR_H_
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include "leveldb/slice.h" // TODO: Remove this when migration is done;
|
||||
#include "rocksdb/slice.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Slice;
|
||||
class Logger;
|
||||
@@ -142,6 +142,6 @@ class AssociativeMergeOperator : public MergeOperator {
|
||||
Logger* logger) const override;
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_MERGE_OPERATOR_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_MERGE_OPERATOR_H_
|
||||
@@ -2,22 +2,21 @@
|
||||
// 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.
|
||||
|
||||
#ifndef STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
|
||||
#define STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
|
||||
#ifndef STORAGE_ROCKSDB_INCLUDE_OPTIONS_H_
|
||||
#define STORAGE_ROCKSDB_INCLUDE_OPTIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include "leveldb/slice.h"
|
||||
#include "leveldb/statistics.h"
|
||||
#include "leveldb/universal_compaction.h"
|
||||
#include "leveldb/memtablerep.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/statistics.h"
|
||||
#include "rocksdb/universal_compaction.h"
|
||||
#include "rocksdb/memtablerep.h"
|
||||
#include "rocksdb/slice_transform.h"
|
||||
|
||||
#include "leveldb/slice_transform.h"
|
||||
|
||||
namespace leveldb {
|
||||
namespace rocksdb {
|
||||
|
||||
class Cache;
|
||||
class Comparator;
|
||||
@@ -166,7 +165,7 @@ struct Options {
|
||||
// a block is the unit of reading from disk).
|
||||
|
||||
// If non-NULL use the specified cache for blocks.
|
||||
// If NULL, leveldb will automatically create and use an 8MB internal cache.
|
||||
// If NULL, rocksdb will automatically create and use an 8MB internal cache.
|
||||
// Default: nullptr
|
||||
shared_ptr<Cache> block_cache;
|
||||
|
||||
@@ -352,13 +351,21 @@ struct Options {
|
||||
// Default value is 1800 (half an hour).
|
||||
int db_stats_log_interval;
|
||||
|
||||
// This specifies the log dir.
|
||||
// This specifies the info LOG dir.
|
||||
// If it is empty, the log files will be in the same dir as data.
|
||||
// If it is non empty, the log files will be in the specified dir,
|
||||
// and the db data dir's absolute path will be used as the log file
|
||||
// name's prefix.
|
||||
std::string db_log_dir;
|
||||
|
||||
// This specifies the absolute dir path for write-ahead logs (WAL).
|
||||
// If it is empty, the log files will be in the same dir as data,
|
||||
// dbname is used as the data dir by default
|
||||
// If it is non empty, the log files will be in kept the specified dir.
|
||||
// When destroying the db,
|
||||
// all log files in wal_dir and the dir itself is deleted
|
||||
std::string wal_dir;
|
||||
|
||||
// Disable compaction triggered by seek.
|
||||
// With bloomfilter and fast storage, a miss on one level
|
||||
// is very cheap if the file handle is cached in table cache
|
||||
@@ -370,10 +377,23 @@ struct Options {
|
||||
// every compaction run.
|
||||
uint64_t delete_obsolete_files_period_micros;
|
||||
|
||||
// Maximum number of concurrent background compactions.
|
||||
// Maximum number of concurrent background jobs, submitted to
|
||||
// the default LOW priority thread pool
|
||||
// Default: 1
|
||||
int max_background_compactions;
|
||||
|
||||
// Maximum number of concurrent background memtable flush jobs, submitted to
|
||||
// the HIGH priority thread pool.
|
||||
// By default, all background jobs (major compaction and memtable flush) go
|
||||
// to the LOW priority pool. If this option is set to a positive number,
|
||||
// memtable flush jobs will be submitted to the HIGH priority pool.
|
||||
// It is important when the same Env is shared by multiple db instances.
|
||||
// Without a separate pool, long running major compaction jobs could
|
||||
// potentially block memtable flush jobs of other db instances, leading to
|
||||
// unnecessary Put stalls.
|
||||
// Default: 0
|
||||
int max_background_flushes;
|
||||
|
||||
// Specify the maximal size of the info log file. If the log file
|
||||
// is larger than `max_log_file_size`, a new info log file will
|
||||
// be created.
|
||||
@@ -422,6 +442,15 @@ struct Options {
|
||||
// Number of shards used for table cache.
|
||||
int table_cache_numshardbits;
|
||||
|
||||
// During data eviction of table's LRU cache, it would be inefficient
|
||||
// to strictly follow LRU because this piece of memory will not really
|
||||
// be released unless its refcount falls to zero. Instead, make two
|
||||
// passes: the first pass will release items with refcount = 1,
|
||||
// and if not enough space releases after scanning the number of
|
||||
// elements specified by this parameter, we will remove items in LRU
|
||||
// order.
|
||||
int table_cache_remove_scan_count_limit;
|
||||
|
||||
// size of one block in arena memory allocation.
|
||||
// If <= 0, a proper value is automatically calculated (usually 1/10 of
|
||||
// writer_buffer_size).
|
||||
@@ -449,7 +478,7 @@ struct Options {
|
||||
|
||||
// The number of seconds a WAL(write ahead log) should be kept after it has
|
||||
// been marked as Not Live. If the value is set. The WAL files are moved to
|
||||
// the archive direcotory and deleted after the given TTL.
|
||||
// the archive directory and deleted after the given TTL.
|
||||
// If set to 0, WAL files are deleted as soon as they are not required by
|
||||
// the database.
|
||||
// If set to std::numeric_limits<uint64_t>::max() the WAL files will never be
|
||||
@@ -485,7 +514,7 @@ struct Options {
|
||||
// Default: false
|
||||
bool skip_log_error_on_recovery;
|
||||
|
||||
// if not zero, dump leveldb.stats to LOG every stats_dump_period_sec
|
||||
// if not zero, dump rocksdb.stats to LOG every stats_dump_period_sec
|
||||
// Default: 3600 (1 hour)
|
||||
unsigned int stats_dump_period_sec;
|
||||
|
||||
@@ -533,6 +562,13 @@ struct Options {
|
||||
// Default: false
|
||||
bool filter_deletes;
|
||||
|
||||
// An iteration->Next() sequentially skips over keys with the same
|
||||
// user-key unless this option is set. This number specifies the number
|
||||
// of keys (with the same userkey) that will be sequentially
|
||||
// skipped before a reseek is issued.
|
||||
// Default: 8
|
||||
uint64_t max_sequential_skip_in_iterations;
|
||||
|
||||
// This is a factory that provides MemTableRep objects.
|
||||
// Default: a factory that provides a skip-list-based implementation of
|
||||
// MemTableRep.
|
||||
@@ -542,6 +578,23 @@ struct Options {
|
||||
// an application to modify/delete a key-value during background compaction.
|
||||
// Default: a factory that doesn't provide any object
|
||||
std::shared_ptr<CompactionFilterFactory> compaction_filter_factory;
|
||||
|
||||
// Remove the log file immediately after the corresponding memtable is flushed
|
||||
// to data file.
|
||||
// Default: true
|
||||
bool purge_log_after_memtable_flush;
|
||||
};
|
||||
|
||||
//
|
||||
// An application can issue a read request (via Get/Iterators) and specify
|
||||
// if that read should process data that ALREADY resides on a specified cache
|
||||
// level. For example, if an application specifies kBlockCacheTier then the
|
||||
// Get call will process data that is already processed in the memtable or
|
||||
// the block cache. It will not page in data from the OS cache or data that
|
||||
// resides in storage.
|
||||
enum ReadTier {
|
||||
kReadAllTier = 0x0, // data in memtable, block cache, OS cache or storage
|
||||
kBlockCacheTier = 0x1 // data in memtable or block cache
|
||||
};
|
||||
|
||||
// Options that control read operations
|
||||
@@ -576,15 +629,23 @@ struct ReadOptions {
|
||||
// Default: nullptr
|
||||
const Slice* prefix;
|
||||
|
||||
// Specify if this read request should process data that ALREADY
|
||||
// resides on a particular cache. If the required data is not
|
||||
// found at the specified cache, then Status::Incomplete is returned.
|
||||
// Default: kReadAllTier
|
||||
ReadTier read_tier;
|
||||
|
||||
ReadOptions()
|
||||
: verify_checksums(false),
|
||||
fill_cache(true),
|
||||
snapshot(nullptr),
|
||||
prefix(nullptr) {
|
||||
prefix(nullptr),
|
||||
read_tier(kReadAllTier) {
|
||||
}
|
||||
ReadOptions(bool cksum, bool cache) :
|
||||
verify_checksums(cksum), fill_cache(cache),
|
||||
snapshot(nullptr), prefix(nullptr) {
|
||||
snapshot(nullptr), prefix(nullptr),
|
||||
read_tier(kReadAllTier) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -629,6 +690,6 @@ struct FlushOptions {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace leveldb
|
||||
} // namespace rocksdb
|
||||
|
||||
#endif // STORAGE_LEVELDB_INCLUDE_OPTIONS_H_
|
||||
#endif // STORAGE_ROCKSDB_INCLUDE_OPTIONS_H_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user