Compare commits

...

146 Commits

Author SHA1 Message Date
sdong 046ba7d47c Fix calculation of max_total_wal_size in db_options_.max_total_wal_size == 0 case
Summary: This is a regression bug introduced by https://reviews.facebook.net/D24729 . max_total_wal_size would be off the target it should be more and more in the case that the a user holds the current super version after flush or compaction. This patch fixes it

Test Plan: make all check

Reviewers: yhchiang, rven, igor

Reviewed By: igor

Subscribers: ljin, yoshinorim, MarkCallaghan, hermanlee4, dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29961
2014-12-08 15:26:35 -08:00
Yueh-Hsuan Chiang 1b7fbb9e82 Update HISTORY.md for release 3.9 2014-12-08 15:19:48 -08:00
Leonidas Galanis 635c61fd3b Fix problem with create_if_missing option when wal_dir is used
Summary: When wal_dir is used, DestroyDB is not passed the wal_dir option and so we get a Corruption exception.

Test Plan:
Verified manually that the following command line works now:
./db_bench --db=/mnt/db/rocksdb ... --disable_wal=0 --wal_dir=/data/users/rocksdb/WAL... --benchmarks=filluniquerandom --use_existing_db=0...

Reviewers: sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29859
2014-12-08 12:53:24 -08:00
Yueh-Hsuan Chiang 2871bc7bc8 Merge pull request #422 from fyrz/RocksJava-Quality-Improvements
Rocks java quality improvements
2014-12-05 21:38:05 -08:00
Yueh-Hsuan Chiang 8c5781666e Add -fno-exceptions flag to ROCKSDB_LITE.
Summary: Add -fno-exceptions flag to ROCKSDB_LITE.

Test Plan: make OPT=-DROCKSDB_LITE shared_lib -j32

Reviewers: sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29901
2014-12-05 21:34:20 -08:00
sdong 1f04066cab Add DBProperty to return number of snapshots and time for oldest snapshot
Summary:
Add a counter in SnapshotList to show number of snapshots. Also a unix timestamp in every snapshot.
Add two DB Properties to return number of snapshots and timestamp of the oldest one.

Test Plan: Add unit test checking

Reviewers: yhchiang, rven, igor

Reviewed By: igor

Subscribers: leveldb, dhruba, MarkCallaghan

Differential Revision: https://reviews.facebook.net/D29919
2014-12-05 17:07:49 -08:00
Venkatesh Radhakrishnan 6436ba6b06 Provide mechanism to restart tests from previous error
Summary:
While running rocksdb tests, we sometimes encounter errors and
the test run stops. We now provide a new make target call check_some
which restarts the test run from a specific test and continues from
there depending on the value of the environment variable ROCKSDBTESTS_START

Test Plan:
Run make check_some with different values of
ROCKSDBTESTS_START.

Reviewers: igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29913
2014-12-05 16:16:56 -08:00
Yueh-Hsuan Chiang d84b2badeb Replace exception by abort() in dummy HdfsEnv implementation.
Summary: Replace exception by abort() in dummy HdfsEnv implementation.

Test Plan: make dbg -j32

Reviewers: sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29895
2014-12-05 13:30:57 -08:00
Igor Canadi 9260e1ad74 Bump version to 3.9 2014-12-05 11:05:24 -08:00
Yueh-Hsuan Chiang 8f4e1c1c9a Remove the compability check on log2 OS_ANDROID as it's already blocked by ROCKSDB_LITE
Summary:
Remove the compability check on log2 OS_ANDROID as it's already blocked by ROCKSDB_LITE

Test Plan:
make OPT="-DROCKSDB_LITE -DOS_ANDROID" shared_lib -j32
make shared_lib -j32
2014-12-04 13:56:14 -08:00
Yueh-Hsuan Chiang c4a7423c1d Replace runtime_error exception by abort() in thread_local
Summary: Replace runtime_error exception by abort() in thread_local

Test Plan: make dbg -j32

Reviewers: sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29853
2014-12-04 13:35:31 -08:00
Yueh-Hsuan Chiang a94d54aa47 Remove the use of exception in WriteBatch::Handler
Summary:
Remove the use of exception in WriteBatch::Handler.  Now the default
implementations of Put, Merge, and Delete in WriteBatch::Handler are no-op.

Test Plan:
Add three test cases in write_batch_test
./write_batch_test

Reviewers: sdong, igor

Reviewed By: sdong, igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29835
2014-12-04 12:01:55 -08:00
Yueh-Hsuan Chiang a5d4fc0a25 Fix compile warning in db_stress
Summary:
Fix compile warning in db_stress

Test Plan:
make db_stress
2014-12-04 11:59:29 -08:00
Yueh-Hsuan Chiang 1a8f4821a7 Replace exception by assertion in autovector
Summary: Replace exception by assertion in autovector

Test Plan: autovector_test

Reviewers: sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29847
2014-12-04 11:41:56 -08:00
Yueh-Hsuan Chiang 97c1940882 Fix compile warning in db_stress.cc on Mac
Summary:
Fix the following compile warning in db_stress.cc on Mac
tools/db_stress.cc:1688:52: error: format specifies type 'unsigned long' but the argument has type '::google::uint64' (aka 'unsigned long long') [-Werror,-Wformat]
    fprintf(stdout, "DB-write-buffer-size: %lu\n", FLAGS_db_write_buffer_size);
                                           ~~~     ^~~~~~~~~~~~~~~~~~~~~~~~~~
                                           %llu

Test Plan:
make
2014-12-04 11:19:12 -08:00
Yueh-Hsuan Chiang 5f719d7202 Replace exception by setting valid_ = false in DBIter::MergeValuesNewToOld()
Summary: Replace exception by setting valid_ = false in DBIter::MergeValuesNewToOld().

Test Plan:
Not sure if I am right at this, but it seems we currently don't have a good
way to test that code path as it requires dynamically set merge_operator = nullptr
at the time while Merge() is calling.

Reviewers: igor, sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29811
2014-12-04 11:11:11 -08:00
Mark Callaghan c0dee851c3 Improve formatting, add missing newlines
Summary:
Improve formatting

Task ID: #

Blame Rev:

Test Plan:
make

Revert Plan:

Database Impact:

Memcache Impact:

Other Notes:

EImportant:

- begin *PUBLIC* platform impact section -
Bugzilla: #
- end platform impact -

Reviewers: igor

Reviewed By: igor

Subscribers: dhruba

Differential Revision: https://reviews.facebook.net/D29829
2014-12-04 10:34:06 -08:00
Igor Canadi 815f638cd0 Fix java build 2014-12-03 19:06:57 -08:00
Mark Callaghan 32a0a03844 Add Moved(GB) to Compaction IO stats
Summary:
Adds counter for bytes moved (files pushed down a level rather than compacted) to compaction
IO stats as Moved(GB). From the output removed these infrequently used columns: RW-Amp, Rn(cnt), Rnp1(cnt),
Wnp1(cnt), Wnew(cnt).
Example old output:
Level   Files   Size(MB) Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) Wnew(GB) RW-Amp W-Amp Rd(MB/s) Wr(MB/s)  Rn(cnt) Rnp1(cnt) Wnp1(cnt) Wnew(cnt)  Comp(sec) Comp(cnt) Avg(sec) Stall(sec) Stall(cnt) Avg(ms) RecordIn RecordDrop
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  L0     0/0          0   0.0      0.0     0.0      0.0    2130.8   2130.8    0.0   0.0      0.0    109.1        0         0         0         0      20002     25068    0.798      28.75     182059    0.16       0          0
  L1   142/0        509   1.0   4618.5  2036.5   2582.0    4602.1   2020.2    4.5   2.3     88.5     88.1    24220    701246   1215528    514282      53466      4229   12.643       0.00          0    0.002032745988  300688729

Example new output:
Level   Files   Size(MB) Score Read(GB)  Rn(GB) Rnp1(GB) Write(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) Comp(sec) Comp(cnt) Avg(sec) Stall(sec) Stall(cnt) Avg(ms)     RecordIn   RecordDrop
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  L0     7/0         13   1.8      0.0     0.0      0.0       0.6      0.6       0.0   0.0      0.0     14.7        44       353    0.124       0.03        626    0.05            0            0
  L1     9/0         16   1.6      0.0     0.0      0.0       0.0      0.0       0.6   0.0      0.0      0.0         0         0    0.000       0.00          0    0.00            0            0

Task ID: #

Blame Rev:

Test Plan:
make check, run db_bench --fillseq --stats_per_interval --stats_interval and look at output

Revert Plan:

Database Impact:

Memcache Impact:

Other Notes:

EImportant:

- begin *PUBLIC* platform impact section -
Bugzilla: #
- end platform impact -

Reviewers: igor

Reviewed By: igor

Subscribers: dhruba

Differential Revision: https://reviews.facebook.net/D29787
2014-12-03 18:28:39 -08:00
Jonah Cohen a14b7873ee Enforce write buffer memory limit across column families
Summary:
Introduces a new class for managing write buffer memory across column
families.  We supplement ColumnFamilyOptions::write_buffer_size with
ColumnFamilyOptions::write_buffer, a shared pointer to a WriteBuffer
instance that enforces memory limits before flushing out to disk.

Test Plan: Added SharedWriteBuffer unit test to db_test.cc

Reviewers: sdong, rven, ljin, igor

Reviewed By: igor

Subscribers: tnovak, yhchiang, dhruba, xjin, MarkCallaghan, yoshinorim

Differential Revision: https://reviews.facebook.net/D22581
2014-12-02 12:09:20 -08:00
fyrz 3e684aa685 Integrated changes from D29571 2014-12-02 19:56:45 +01:00
Igor Canadi 37d73d597e Fix linters
Summary:
Two fixes:
1. if cpplint is not present on the system, don't return a confusing error in the linter
2. Add include_alpha, which means our includes should be sorted lexicographically

Test Plan: Tried unsorting our includes, lint complained

Reviewers: rven, ljin, yhchiang, sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28845
2014-12-02 13:53:39 -05:00
fyrz a15169f2e9 Fixed a Lint problem 2014-12-02 09:58:20 +01:00
fyrz b7f9e644cc [RocksJava] Quality improvements
Summary:
- Addressed some FindBugs issues.
- Remove obsolete dbFolder cleanup
- Comparator tests for CF
 - Added AbstractComparatorTest.
 - Fixed a bug in the JNI Part about Java comparators
- Minor test improvements

Test Plan:
make rocksdbjava
make jtest
mvn -f rocksjni.pom package

Reviewers: adamretter, yhchiang, ankgup87

Subscribers: dhruba

Differential Revision: https://reviews.facebook.net/D29571
2014-12-02 09:58:19 +01:00
fyrz e002a6122f [RocksJava] Comparator tests for CF
- Added AbstractComparatorTest.
- Fixed a bug in the JNI Part about Java comparators
2014-12-02 09:58:19 +01:00
fyrz 335e6ad5cd [RocksJava] Remove obsolete dbFolder cleanup 2014-12-02 09:58:18 +01:00
fyrz b036804ac1 RocksJava - FindBugs issues
Addressed some FindBugs issues.
2014-12-02 09:58:17 +01:00
Igor Canadi 9a632b4a92 Merge pull request #429 from fyrz/RocksJava-MacOSX-strip-fix
[RocksJava] MacOSX strip support
2014-12-01 13:13:02 -05:00
fyrz b426675061 [RocksJava] MacOSX strip support 2014-12-01 19:01:29 +01:00
Igor Canadi e463cb0bcf Merge pull request #424 from eile/master
Tweak Makefile for building on BG/Q
2014-12-01 10:20:12 -05:00
Stefan Eilemann 91d8981639 Tweak Makefile for building on BG/Q 2014-12-01 09:01:54 +01:00
Igor Canadi 703ef66a86 Merge pull request #426 from fyrz/RocksJava-Restore-PrecisionFix
[RocksJava] Fixed MacOS build of RocksJava
2014-11-27 20:39:39 -05:00
Yueh-Hsuan Chiang bcf9086899 Block Universal and FIFO compactions in ROCKSDB_LITE
Summary: Block Universal and FIFO compactions in ROCKSDB_LITE

Test Plan:
make shared_lib -j32
make OPT=-DROCKSDB_LITE shared_lib

Reviewers: ljin, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29589
2014-11-26 15:45:11 -08:00
fyrz 67cb7ca758 [RocksJava] Fixed MacOS build of RocksJava
There were still some precision loss problems
remainging in RocksJava. This pull request resolve
these.
2014-11-26 20:53:23 +01:00
Yueh-Hsuan Chiang b8136a7d27 Merge pull request #398 from fyrz/RocksJava-CreateCheckPoint
[RocksJava] Support for stored snapshots
2014-11-26 11:40:41 -08:00
Yueh-Hsuan Chiang 533592a27d Merge pull request #401 from fyrz/RocksJava-Sigsegv-MergeOperatorName
[RocksJava] Fixes in MergeOperatorByName
2014-11-26 11:40:13 -08:00
Yueh-Hsuan Chiang 73d72ed5c7 Block ReadOnlyDB in ROCKSDB_LITE
Summary:
db_imp_readonly.o is one of the big obj file.  If it's not a necessary
feature, we should probably block it in ROCKSDB_LITE.

    1322704 Nov 24 16:55 db/db_impl_readonly.o

Test Plan:
make shared_lib -j32
make ROCKSDB_LITE shared_lib -j32

Reviewers: ljin, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29583
2014-11-26 11:37:59 -08:00
Igor Canadi e47f0fa9ed Merge pull request #425 from adamretter/macosx-clean-fix
Mac OS X jclean fix
2014-11-26 13:40:32 -05:00
Adam Retter ff0cb90d1c Do not delete Java Fatal Error Log, developers may still want these for
reference
2014-11-26 18:18:04 +00:00
Adam Retter 2a792cd300 There will also be a librocksdbjni-osx.jnilib.dSYM folder on MacOSX
builds to be deleted
2014-11-26 18:17:54 +00:00
Yueh-Hsuan Chiang beb74c14ca Fix travis-build error
Summary:
Fix travis-build error
2014-11-26 09:42:13 -08:00
Igor Canadi a486352e07 Merge pull request #423 from zerebubuth/c_iterate_upper_bound
C iterate upper bound
2014-11-26 10:14:16 -05:00
Matt Amos 26109d487a Store upper bound Slice with the same lifetime as the ReadOptions so that we can provide a pointer to it. 2014-11-26 11:29:13 +00:00
Yueh-Hsuan Chiang a97314219e Fix compile error in ROCKSDB_LITE 2014-11-25 23:39:52 -08:00
Yueh-Hsuan Chiang 9d5019327b Replace log2 by implementing Log2 in options_builder
Summary:
log2 function is only used in options_builder, and this function
is not available under certain platform such as android.
This patch implements Log2 by log(n) / log(2).

Test Plan:
make
2014-11-25 23:28:36 -08:00
Matt Amos 805bac6d25 Add test for upper bounds on iterators using C interface. 2014-11-25 23:07:40 +00:00
fyrz f193deea31 [RocksJava] Addressed comments in D28971 2014-11-25 23:33:42 +01:00
fyrz 94f70a86b9 [RocksJava] Incoroporated changes for D29013 2014-11-25 22:26:03 +01:00
fyrz a280af2a57 [RocksJava] Sigsegv fix for MergerOperatorByName 2014-11-25 22:26:02 +01:00
fyrz fcc2dfd9f9 [RocksJava] Support for stored snapshots
Summary:
RocksDB supports two ways of saving snapshots. In
memory and on disk. The later was added with this
pull request to RocksJava.

Test Plan:

Reviewers:

Subscribers:
2014-11-25 22:25:22 +01:00
Yueh-Hsuan Chiang 274ba62707 Block internal_stats in ROCKSDB_LITE
Summary: Block internal_stats in ROCKSDB_LITE.

Test Plan: make OPT=-DROCKSDB_LITE shared_lib

Reviewers: ljin, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29541
2014-11-25 12:01:27 -08:00
Igor Canadi 4f2e8bab5f Merge pull request #421 from fyrz/RocksJava-PrecisionFix
[RocksJava] Fix precision problem in rocksjni
2014-11-25 14:32:44 -05:00
fyrz c4765dc10b [RocksJava] Fix precision problem in rocksjni 2014-11-25 20:29:52 +01:00
Igor Canadi 14788e1811 Merge pull request #420 from rdallman/add-wal
c api: add max wal total to opts
2014-11-25 09:34:15 -05:00
Reed Allman 88dd8d889b c api: add max wal total to opts 2014-11-24 22:00:29 -08:00
Yueh-Hsuan Chiang 7e608e2fe3 Block plain_table_index.cc in ROCKSDB_LITE
Summary: Block plain_table_index.cc in ROCKSDB_LITE

Test Plan:
make clean
make OPT=-DROCKSDB_LITE shared_lib -j32
make clean
make shared_lib -j32

Reviewers: ljin, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29535
2014-11-24 20:47:27 -08:00
Yueh-Hsuan Chiang 13de000f07 Add rocksdb::ToString() to address cases where std::to_string is not available.
Summary:
In some environment such as android, the c++ library does not have
std::to_string.  This path adds rocksdb::ToString(), which wraps std::to_string
when std::to_string is not available, and implements std::to_string
in the other case.

Test Plan:
make dbg -j32
./db_test
make clean
make dbg OPT=-DOS_ANDROID -j32
./db_test

Reviewers: ljin, sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29181
2014-11-24 20:44:49 -08:00
Yueh-Hsuan Chiang 90ee85f8e1 Improve listener_test to avoid possible false alarm
Summary:
Improve listener_test to avoid possible false alarm

Test Plan:
./listener_test
2014-11-24 18:28:06 -08:00
Lei Jin 2946e37a08 remove unreliable test in db/cuckoo_table_db_test.cc
Summary:
This compaction trigger does not seem to test any thing specific to
cuckoo table. Remove it.

Test Plan: make all check

Reviewers: igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29523
2014-11-24 15:18:09 -08:00
Lei Jin 9c7ca65d21 free builders in VersionSet::DumpManifest
Summary:
Reported by bootcamper
This causes ldb tool to fail the assertion in ~ColumnFamilyData()

Test Plan:
./ldb --db=/tmp/test_db1 --create_if_missing put a1 b1
./ldb manifest_dump --path=/tmp/test_db1/MANIFEST-000001

Reviewers: sdong, yhchiang, rven, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29517
2014-11-24 15:03:08 -08:00
Igor Canadi 7530c75ab0 Merge pull request #413 from saghmrossi/master
first rdb commit
2014-11-24 16:54:44 -05:00
Igor Canadi d699d70343 Make RocksDB compile without gflags
Summary: We want to make sure people without gflags can compile RocksDB.

Test Plan: remove gflags, make all

Reviewers: sdong, rven, yhchiang, ljin

Reviewed By: ljin

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29469
2014-11-24 15:53:23 -05:00
Venkatesh Radhakrishnan 3257221499 Fixes valgrind error in GetSnapshotLink. Free checkpoint now.
Summary: Free checkpoint after its directory is removed.

Test Plan: Run valgrind with GetSnapshotLink.

Reviewers: igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29493
2014-11-24 10:20:50 -08:00
Igor Canadi ada3d78734 Merge pull request #415 from fyrz/RocksJava-Makefile
[RocksJava] Makefile correction
2014-11-22 22:53:01 -05:00
Yueh-Hsuan Chiang 569853ed10 Fix leak when create_missing_column_families=true on ThreadStatus
Summary:
An entry of ConstantColumnFamilyInfo is created when:
1. DB::Open
2. CreateColumnFamily.

However, there are cases that DB::Open could also call CreateColumnFamily
when create_missing_column_families=true.  As a result, it will create
duplicate ConstantColumnFamilyInfo and one of them would be leaked.

Test Plan: ./deletefile_test

Reviewers: igor, sdong, ljin

Reviewed By: ljin

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29307
2014-11-22 00:04:41 -08:00
fyrz c4b65f70fb [RocksJava] Makefile correction
Prevent non exist error message while executing
clean twice.
2014-11-21 23:49:31 +01:00
Shaohua Li 1410180167 Make arena use hugepage if possible
Summary:
arena doesn't use huge page by default. This change will make it happen
if possible. A new paramerter is added for Arena(). If it's set, Arena
will use huge page always. If huge page allocation fails, Arena
allocation will fallback to malloc().

Test Plan:
Change util/arena_test to support huge page allocation.
Run below tests:
1. normal regression test:
  make check
2. Check if huge page allocation works
  echo 50 > /proc/sys/vm/nr_hugepages
  make check

Reviewers: sdong

Reviewed By: sdong

Subscribers: dhruba

Differential Revision: https://reviews.facebook.net/D28647
2014-11-21 14:11:40 -08:00
sdong 3a40c427b9 Fix db_bench on CLANG mode
Summary: "build all" breaks in Clang mode with db_bench. Fix it.

Test Plan: USE_CLANG=1 make all

Reviewers: ljin, rven, yhchiang, igor

Reviewed By: igor

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D29379
2014-11-21 11:30:22 -08:00
Yueh-Hsuan Chiang 9222a2d024 Fixed iOS build caused by GetThreadList feature.
Summary:
Fixed iOS build caused by GetThreadList feature.
2014-11-21 11:00:42 -08:00
Yueh-Hsuan Chiang aa31fc5068 Improve listener_test by ensuring flushes are completed before assert.
Summary: Improve listener_test by ensuring flushes are completed before assert.

Test Plan: listener_test

Reviewers: ljin, sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29319
2014-11-21 10:22:05 -08:00
Igor Canadi 7ec71f101c Provide default implementation of LinkFile, don't break the build
Summary: By providing default implementation of LinkFile, we don't break other implementations of Env.

Test Plan: none

Reviewers: rven, dhruba

Reviewed By: dhruba

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29355
2014-11-21 11:05:48 -05:00
Igor Canadi cd278584c9 Clean up StringSplit
Summary: stringSplit is not how we name our functions. Also, we had two StringSplit's in the codebase

Test Plan: make check

Reviewers: yhchiang, dhruba

Reviewed By: dhruba

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29361
2014-11-21 11:05:28 -05:00
Igor Canadi d84069995c Fix mac compile 2014-11-21 09:42:45 -05:00
Yueh-Hsuan Chiang 4f882924dd Merge pull request #404 from fyrz/RocksJava-Backup-Restore-3.8
[RocksJava] Update BackupableDB and RestoreBackupableDB to 3.8.0.
2014-11-21 00:07:13 -08:00
Yueh-Hsuan Chiang 4b63fcbff3 Add enable_thread_tracking to DBOptions
Summary:
Add enable_thread_tracking to DBOptions to allow
tracking thread status related to the DB.  Default is off.

Test Plan:
export ROCKSDB_TESTS=ThreadList
./db_test

Reviewers: ljin, sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29289
2014-11-20 21:13:18 -08:00
Saghm Rossi bafce61979 first rdb commit
Summary: First commit for rdb shell

Test Plan: unit_test.js does simple assertions on most of the main functionality; will update with rest of tests

Reviewers: igor, rven, lijn, yhciang, sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28749
2014-11-20 23:33:00 -05:00
Bryan Rosario 9e285d4238 Added CompatibleOptions for compatibility with LevelDB Options
Summary: Created a CompatibleOptions object that can be used as a LevelDB Options object and then converted to a RocksDB Options object using the ConvertOptions() method.

Test Plan: Unit test included in diff.

Reviewers: ljin

Reviewed By: ljin

Subscribers: sdong, dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28893
2014-11-20 19:24:39 -08:00
Yueh-Hsuan Chiang 353307758b Add IOS_CROSS_COMPILE to macro guard for GetThreadList feature. 2014-11-20 16:13:20 -08:00
Yueh-Hsuan Chiang eecdebe65b Fixed the destruction order of static variables in ThreadStatusImpl. 2014-11-20 16:02:03 -08:00
Venkatesh Radhakrishnan 004f416b77 Moved checkpoint to utilities
Summary:
Moved checkpoint to utilities.
Addressed comments by Igor, Siying, Dhruba

Test Plan: db_test/SnapshotLink

Reviewers: dhruba, igor, sdong

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29079
2014-11-20 15:54:47 -08:00
Yueh-Hsuan Chiang beabc6879c Fixed ~ThreadStatusImpl(). 2014-11-20 15:45:56 -08:00
fyrz faa8d32be0 [RocksJava] Integrated changes from D29019. 2014-11-20 23:34:07 +01:00
fyrz 3d78c7a8cf [RocksJava] Lint adjustments 2014-11-20 22:51:31 +01:00
fyrz d7529b2de9 [RocksJava] Cleanup Backupable implementations
- Correct usage of isInitialized()
- Adjusted JavaDoc
2014-11-20 22:51:30 +01:00
fyrz fa703efb28 [RocksJava] Improved BackupableDBTest
- Splitted methods to meaningful tests
- Added tests for additional functionality
- Covered missing parts
2014-11-20 22:51:30 +01:00
fyrz 24fdc47416 [RocksJava] Backupable/Restorable DB update 3.8.0
- GarbageCollectMethod() available.
- GetCorruptedBackups() available.
2014-11-20 22:51:29 +01:00
fyrz 9972f969ee [RocksJava] BackupableDBOptions alginment + 3.8
- Updated the BackupableDBOptions functionality to 3.8.0.
- Aligned Options implementation with remaining source code.
- Invented test-case.
2014-11-20 22:51:29 +01:00
Yueh-Hsuan Chiang fbc42a0933 Fixed -Werror=unused-but-set-variable in thread_status_impl
Summary:
Fixed -Werror=unused-but-set-variable in thread_status_impl
2014-11-20 13:46:04 -08:00
Yueh-Hsuan Chiang a564be715d Fix asan error in thread_status_impl.cc 2014-11-20 11:47:18 -08:00
Yueh-Hsuan Chiang 7165d18869 Fix clang compile error 2014-11-20 11:00:21 -08:00
Yueh-Hsuan Chiang d0c5f28a5c Introduce GetThreadList API
Summary:
Add GetThreadList API, which allows developer to track the
status of each process.  Currently, calling GetThreadList will
only get the list of background threads in RocksDB with their
thread-id and thread-type (priority) set.  Will add more support
on this in the later diffs.

ThreadStatus currently has the following properties:

  // An unique ID for the thread.
  const uint64_t thread_id;

  // The type of the thread, it could be ROCKSDB_HIGH_PRIORITY,
  // ROCKSDB_LOW_PRIORITY, and USER_THREAD
  const ThreadType thread_type;

  // The name of the DB instance where the thread is currently
  // involved with.  It would be set to empty string if the thread
  // does not involve in any DB operation.
  const std::string db_name;

  // The name of the column family where the thread is currently
  // It would be set to empty string if the thread does not involve
  // in any column family.
  const std::string cf_name;

  // The event that the current thread is involved.
  // It would be set to empty string if the information about event
  // is not currently available.

Test Plan:
./thread_list_test
export ROCKSDB_TESTS=GetThreadList
./db_test

Reviewers: rven, igor, sdong, ljin

Reviewed By: ljin

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D25047
2014-11-20 10:49:32 -08:00
Yueh-Hsuan Chiang 1fd1aecb39 Merge pull request #409 from fyrz/RocksJava-Make-cleanup
[RocksJava] Build improvements
2014-11-20 00:01:48 -08:00
fyrz 91c8dcefc3 [RocksJava] Strip library in publish
Currently maven publishing uses the library with debug symbols. What
leads to unnecessary big library sizes. Included strip to remove
unnecessary stuff. 40M -> 2.7M
2014-11-20 07:28:59 +01:00
fyrz e7fcaa4d92 [RocksJava] JavaDoc is executed too often
Previous to this commit too much targets got dependencies
on javadocs target.

Introduced one additional target "javalib" which resolves
that situation. JavaDoc will now be generated once while
executing a task with prefix "rocksdbjava".
2014-11-20 07:28:16 +01:00
fyrz 2cd1794e4f [RocksJava] Make cleanup - Clean Target
- Remove JNI includes on clean
- Remove target folder generated by Maven
- Remove shared object
- Remove jar
2014-11-20 07:21:30 +01:00
Lei Jin be005e17bb fix clang compilation
Summary:
as title
2014-11-18 20:42:32 -08:00
Yueh-Hsuan Chiang 5e69f19c4c Merge pull request #405 from fyrz/RocksJava-Convenient-Options
[RocksJava] Convenience methods for Options
2014-11-18 20:39:51 -08:00
Igor Canadi 55a344872d Merge pull request #408 from fyrz/Missing-include
Missing header in build on CentOS 6.5, GCC4.7
2014-11-18 17:35:34 -08:00
fyrz 9e9a83baf7 Missing header in build on CentOS
While building RocksJava the build fails on
CentOS because of the missing stdexcept header.
2014-11-18 22:21:02 +01:00
fyrz 91ccc8ebef [RocksJava] Integrated changes in D29025
Addressed review comments.
2014-11-18 21:45:12 +01:00
fyrz 5249d0db50 [RocksJava] Convenience methods for Options
RocksDB introduced in 3.7.0 convenience methods
for getting ColumnFamilyOptions and DBOptions
instances from predefined configuration structures.

There is now also a method in RocksJava to load DBOptions
as well as ColumnFamilyOptions from a predefined Properties
based configuration.
2014-11-18 21:43:20 +01:00
Lei Jin 8d3f8f9696 remove all remaining references to cfd->options()
Summary:
The very last reference happens in DBImpl::GetOptions()
I built with both DBImpl::GetOptions() and ColumnFamilyData::options() commented out

Test Plan: make all check

Reviewers: sdong, yhchiang, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29073
2014-11-18 10:20:10 -08:00
Lei Jin 1e4a45aac8 remove cfd->options() in DBImpl::NotifyOnFlushCompleted
Summary: We should not reference cfd->options() directly!

Test Plan: make release

Reviewers: sdong, rven, igor, yhchiang

Reviewed By: igor, yhchiang

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D29061
2014-11-18 10:19:48 -08:00
Jonah Cohen 517c28994d Options helper supports k, m, g, and t unit suffixes
Summary:
Add unit support in options helper so we can specify, e.g., 10m for
10 megabytes.

Test Plan: Updated options_test

Reviewers: sdong, igor, ljin

Reviewed By: ljin

Subscribers: dhruba

Differential Revision: https://reviews.facebook.net/D28977
2014-11-17 13:47:51 -08:00
Yueh-Hsuan Chiang c46c2be8d6 Merge pull request #397 from fyrz/RocksJava-GetIntProperty
[RocksJava] GetIntProperty in RocksDB
2014-11-17 12:53:44 -08:00
fyrz 8efd4bb424 [RocksJava] Improved comments in RocksDB class
Improved comments in RocksDB getLongProperty methods,
to describe the behavior more detailed.
2014-11-17 21:32:00 +01:00
fyrz 5529c1ad1b [RocksJava] GetIntProperty in RocksDB
Expose GetIntProperty methods to RocksJava. As the integer(64-Bit)
value is no integer in Java the method is aligned with the return
type which is long.
2014-11-17 21:32:00 +01:00
Igor Canadi db59eeb613 Merge pull request #406 from fyrz/Build-Fix
[RocksJava] JavaDoc corrections - Java8
2014-11-17 10:30:18 -08:00
fyrz e97f014b91 [RocksJava] JavaDoc corrections - Java8
This commit solves build problems in Java8 due
to wrong JavaDoc.
2014-11-17 19:27:52 +01:00
Yueh-Hsuan Chiang 98e59f9813 Fixed a bug which could hide non-ok status in CompactionJob::Run()
Summary: Fixed a bug which could hide non-ok status in CompactionJob::Run()

Test Plan: make

Reviewers: sdong, igor

Reviewed By: igor

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28995
2014-11-16 21:52:23 -08:00
Yueh-Hsuan Chiang ec24bd4e6a Merge pull request #402 from adamretter/bugfix-native-library-loader
Use correct classloader in Java NativeLibraryLoader
2014-11-16 16:42:59 -08:00
Yueh-Hsuan Chiang d3c4a0f4ae Improve the comment in InfoLogLevelTest.java
Summary:
Improve the comment in InfoLogLevelTest.java

Test Plan:
make rocksdbjava
2014-11-15 17:05:52 -08:00
Yueh-Hsuan Chiang a77e97c536 Merge pull request #396 from fyrz/RocksJava-LogLevel
[RocksJava] LogLevel support in Options
2014-11-15 17:03:14 -08:00
Adam Retter 585c759cf3 Make sure to use the correct Java classloader for loading the RocksDB
Native Library
2014-11-15 23:42:07 +00:00
Adam Retter c3915abbae Minor tidyup and use Java 7 for file copying 2014-11-15 23:42:07 +00:00
Igor Canadi a122a42bbd Merge pull request #399 from fyrz/RocksJava-Version-to-3.8
[RocksJava] Bump version to 3.8.0 in rocksjni.pom
2014-11-15 12:52:51 -08:00
fyrz b8d5e3f08e [RocksJava] MVN Build reads version from version.h 2014-11-15 20:12:04 +01:00
Igor Canadi 23295b74b6 Clean job_context 2014-11-14 16:57:17 -08:00
Igor Canadi 0ce38fe983 Fix signed/unsigned compile 2014-11-14 16:33:41 -08:00
Igor Canadi e7960c03ac Don't parallelize the build in travis 2014-11-14 16:23:56 -08:00
Igor Canadi 84af2ff8d3 Clean job context in DeleteFile 2014-11-14 16:20:24 -08:00
fyrz 8a1bcc39c5 [RocksJava] Bump version to 3.8 in rocksjni.pom 2014-11-15 01:09:54 +01:00
Igor Canadi 5c04acda08 Explicitly clean JobContext
Summary: This way we can gurantee that old MemTables get destructed before DBImpl gets destructed, which might be useful if we want to make them depend on state from DBImpl.

Test Plan: make check with asserts in JobContext's destructor

Reviewers: ljin, sdong, yhchiang, rven, jonahcohen

Reviewed By: jonahcohen

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28959
2014-11-14 15:43:10 -08:00
fyrz 4947a0674f [RocksJava] Incorporated review comments D28947 2014-11-15 00:14:36 +01:00
fyrz 07cd3c42a2 [RocksJava] LogLevel support in Options
It's now possible to set a LogLevel in Options and
DBOptions to control LOG verbosity.
2014-11-14 23:40:20 +01:00
Igor Canadi 26dc5da96c Fix compaction_job_test 2014-11-14 13:42:13 -08:00
Igor Canadi 5f583d2a9c Merge pull request #394 from lalinsky/cuckoo-c
Cuckoo table options missing in the C interface
2014-11-14 13:23:06 -08:00
Yueh-Hsuan Chiang 353303a765 Merge pull request #380 from fyrz/RocksJava-Junit-Framework
[RocksJava] Test framework support
2014-11-14 12:47:07 -08:00
fyrz 3f9c95a519 [RocksJava] Minor lint correction 2014-11-14 21:34:24 +01:00
fyrz e46450da6d [RocksJava] Rebased + integrated CF tests 2014-11-14 20:59:38 +01:00
fyrz cd82beb0cb [RocksJava] Merged in latest changes. 2014-11-14 20:59:38 +01:00
fyrz b6abab8b77 [RocksJava] Merged & rebased to HEAD 2014-11-14 20:59:38 +01:00
fyrz 74057d6d2d [RocksJava] Improved tests within RocksJava 2014-11-14 20:59:36 +01:00
fyrz 628e39e97d [RocksJava] Integrated review comments from D28209 2014-11-14 20:59:36 +01:00
fyrz a4b28c1ae7 [RocksJava] Extended Testcases 2014-11-14 20:59:36 +01:00
fyrz 36f3a0bb8e [RocksJava] Integrated review comments from adamretter in D28209 2014-11-14 20:59:36 +01:00
fyrz b092686959 [RocksJava] Extended testcases
+ 7% coverage + 3% branch coverage
2014-11-14 20:59:36 +01:00
fyrz 9bec23c413 [RocksJava] Test-framework integration
Summary:
As we had the discussion some weeks ago. Java needs a test framework and should support code coverage analysis. This pull request includes:

    Move Tests from main method functionality to Junit4
    Move WriteBatchTest to test package
    Adjust the Makefile to run Junit4
    Download dependencies from Make (once if not-present)
    Adjustment of the rocksjni.pom to run coverage analysis using jacoco
    Javadoc excludes now tests
    Two bugfixes regarding GC cleanup which came up within the test runs

Make can be used as beforehand to build and run RocksJava. make test runs tests using the command-line version of Junit4.

Maven can be used to retrieve code coverage reports using mvn -f rocksjni.pom package. Code coverage reports can then be found as usual in the site folder.

Testing libraries available within Java

    Junit4 (incl. hamcrest-core dependency)
    AssertJ (providing fluent syntax for assertions, cglib dependency)
    Mockito to provide mocktests

Libraries as said before are not statically within this commit or filesystem instead they are downloaded using curl. Make checks if files are present, if so it will perform tests without downloading the libraries again.

Note: Libraries are only necessary to compile & run tests.

Next steps after merge:

    Get the maven build into travis-ci and coveralls.io
    Filling up the missing test spots (based on coverage data)

Test Plan:
make rocksdbjava
make jtest

Reviewers: yhchiang, ankgup87, adamretter

Subscribers: dhruba

Differential Revision: https://reviews.facebook.net/D28209
2014-11-14 20:59:36 +01:00
fyrz f617135d5f [RocksJava] Testcase improvements 2014-11-14 20:59:36 +01:00
fyrz 1fe7a4c62f [RocksJava] Test-framework integration 2014-11-14 20:59:36 +01:00
Igor Canadi 04ca7481d2 Fix build 2014-11-14 11:52:17 -08:00
Venkatesh Radhakrishnan 6c1b040cc9 Provide openable snapshots
Summary: Store links to live files in directory on same disk

Test Plan:
Take snapshot and open it. Added a test GetSnapshotLink in
db_test.

Reviewers: sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28713
2014-11-14 11:38:26 -08:00
Igor Canadi 9be338cf9d CompactionJobTest
Summary:
This is just a simple test that passes two files though a compaction. It shows the framework so that people can continue building new compaction *unit* tests.
In the future we might want to move some Compaction* tests from DBTest here. For example, CompactBetweenSnapshot seems a good candidate.

Hopefully this test can be simpler when we mock out VersionSet.

Test Plan: this is a test

Reviewers: ljin, rven, yhchiang, sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D28449
2014-11-14 11:35:48 -08:00
Lukáš Lalinský c9fd03ec51 Update docs for NewAdaptiveTableFactory 2014-11-14 11:34:32 -08:00
Lukáš Lalinský e6c3cc6574 Add very basic tests to make sure the C cuckoo table options compile and run 2014-11-14 11:31:52 -08:00
Lukáš Lalinský c44a292781 Add cuckoo table options to the C interface 2014-11-14 11:00:39 -08:00
211 changed files with 12050 additions and 2428 deletions
+1 -1
View File
@@ -14,6 +14,6 @@ before_install:
- sudo dpkg -i libgflags-dev_2.0-1_amd64.deb
# Lousy hack to disable use and testing of fallocate, which doesn't behave quite
# as EnvPosixTest::AllocateTest expects within the Travis OpenVZ environment.
script: OPT=-DTRAVIS make unity && make clean && OPT=-DTRAVIS make check -j8
script: OPT=-DTRAVIS make unity && make clean && OPT=-DTRAVIS make check
notifications:
email: false
+17
View File
@@ -1,5 +1,22 @@
# Rocksdb Change Log
### 3.9.0 (12/8/2014)
### New Features
* Add rocksdb::GetThreadList(), which in the future will return the current status of all
rocksdb-related threads. We will have more code instruments in the following RocksDB
releases.
### Public API changes
* New API to create a checkpoint added. Given a directory name, creates a new
database which is an image of the existing database.
*New API LinkFile added to Env. If you implement your own Env class, an
implementation of the API LinkFile will have to be provided.
* MemTableRep takes MemTableAllocator instead of Arena
### Improvements
* RocksDBLite library now becomes smaller and will be compiled with -fno-exceptions flag.
## 3.8.0 (11/14/2014)
### Public API changes
+32 -4
View File
@@ -6,8 +6,16 @@
#-----------------------------------------------
CFLAGS += ${EXTRA_CFLAGS}
CXXFLAGS += ${EXTRA_CXXFLAGS}
LDFLAGS += $(EXTRA_LDFLAGS)
MACHINE ?= $(shell uname -m)
ifneq ($(MAKECMDGOALS),dbg)
OPT += -O2 -fno-omit-frame-pointer -momit-leaf-frame-pointer
OPT += -O2 -fno-omit-frame-pointer
ifneq ($(MACHINE),ppc64) # ppc64 doesn't support -momit-leaf-frame-pointer
OPT += -momit-leaf-frame-pointer
endif
else
# intentionally left blank
endif
@@ -35,6 +43,12 @@ else
OPT += -DNDEBUG
endif
ifneq ($(filter -DROCKSDB_LITE,$(OPT)),)
# found
CFLAGS += -fno-exceptions
CXXFLAGS += -fno-exceptions
endif
# ASAN doesn't work well with jemalloc. If we're compiling with ASAN, we should use regular malloc.
ifdef COMPILE_WITH_ASAN
# ASAN compile flags
@@ -150,7 +164,10 @@ TESTS = \
flush_job_test \
wal_manager_test \
listener_test \
write_batch_with_index_test
compaction_job_test \
thread_list_test
SUBSET := $(shell echo $(TESTS) |sed s/^.*$(ROCKSDBTESTS_START)/$(ROCKSDBTESTS_START)/)
TOOLS = \
sst_dump \
@@ -238,6 +255,10 @@ check: $(TESTS) ldb
for t in $(TESTS); do echo "***** Running $$t"; ./$$t || exit 1; done
python tools/ldb_test.py
check_some: $(SUBSET) ldb
for t in $(SUBSET); do echo "***** Running $$t"; ./$$t || exit 1; done
python tools/ldb_test.py
ldb_tests: ldb
python tools/ldb_test.py
@@ -425,6 +446,9 @@ write_batch_with_index_test: utilities/write_batch_with_index/write_batch_with_i
flush_job_test: db/flush_job_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) db/flush_job_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
compaction_job_test: db/compaction_job_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) db/compaction_job_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
wal_manager_test: db/wal_manager_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) db/wal_manager_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
@@ -506,6 +530,9 @@ cuckoo_table_db_test: db/cuckoo_table_db_test.o $(LIBOBJECTS) $(TESTHARNESS)
listener_test: db/listener_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) db/listener_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
thread_list_test: util/thread_list_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) util/thread_list_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
compactor_test: utilities/compaction/compactor_test.o $(LIBOBJECTS) $(TESTHARNESS)
$(CXX) utilities/compaction/compactor_test.o $(LIBOBJECTS) $(TESTHARNESS) $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS)
@@ -591,9 +618,10 @@ libsnappy.a:
rocksdbjavastatic: libz.a libbz2.a libsnappy.a
OPT="-fPIC -DNDEBUG -O2" $(MAKE) $(LIBRARY) -j
cd java;$(MAKE) java;
cd java;$(MAKE) javalib;
rm -f ./java/$(ROCKSDBJNILIB)
$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC -o ./java/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) $(LIBOBJECTS) $(COVERAGEFLAGS) libz.a libbz2.a libsnappy.a
cd java;strip -S -x $(ROCKSDBJNILIB)
cd java;jar -cf $(ROCKSDB_JAR) org/rocksdb/*.class org/rocksdb/util/*.class HISTORY*.md $(ROCKSDBJNILIB)
cd java/javadoc;jar -cf ../$(ROCKSDB_JAVADOCS_JAR) *
cd java;jar -cf $(ROCKSDB_SOURCES_JAR) org
@@ -612,7 +640,7 @@ rocksdbjavastaticpublish: rocksdbjavastaticrelease
rocksdbjava:
OPT="-fPIC -DNDEBUG -O2" $(MAKE) $(LIBRARY) -j32
cd java;$(MAKE) java;
cd java;$(MAKE) javalib;
rm -f ./java/$(ROCKSDBJNILIB)
$(CXX) $(CXXFLAGS) -I./java/. $(JAVA_INCLUDE) -shared -fPIC -o ./java/$(ROCKSDBJNILIB) $(JNI_NATIVE_SOURCES) $(LIBOBJECTS) $(JAVA_LDFLAGS) $(COVERAGEFLAGS)
cd java;jar -cf $(ROCKSDB_JAR) org/rocksdb/*.class org/rocksdb/util/*.class HISTORY*.md $(ROCKSDBJNILIB)
+68 -3
View File
@@ -56,6 +56,7 @@ using rocksdb::NewBloomFilterPolicy;
using rocksdb::NewLRUCache;
using rocksdb::Options;
using rocksdb::BlockBasedTableOptions;
using rocksdb::CuckooTableOptions;
using rocksdb::RandomAccessFile;
using rocksdb::Range;
using rocksdb::ReadOptions;
@@ -79,10 +80,14 @@ struct rocksdb_writebatch_t { WriteBatch rep; };
struct rocksdb_snapshot_t { const Snapshot* rep; };
struct rocksdb_flushoptions_t { FlushOptions rep; };
struct rocksdb_fifo_compaction_options_t { CompactionOptionsFIFO rep; };
struct rocksdb_readoptions_t { ReadOptions rep; };
struct rocksdb_readoptions_t {
ReadOptions rep;
Slice upper_bound; // stack variable to set pointer to in ReadOptions
};
struct rocksdb_writeoptions_t { WriteOptions rep; };
struct rocksdb_options_t { Options rep; };
struct rocksdb_block_based_table_options_t { BlockBasedTableOptions rep; };
struct rocksdb_cuckoo_table_options_t { CuckooTableOptions rep; };
struct rocksdb_seqfile_t { SequentialFile* rep; };
struct rocksdb_randomfile_t { RandomAccessFile* rep; };
struct rocksdb_writablefile_t { WritableFile* rep; };
@@ -1121,6 +1126,51 @@ void rocksdb_options_set_block_based_table_factory(
}
rocksdb_cuckoo_table_options_t*
rocksdb_cuckoo_options_create() {
return new rocksdb_cuckoo_table_options_t;
}
void rocksdb_cuckoo_options_destroy(
rocksdb_cuckoo_table_options_t* options) {
delete options;
}
void rocksdb_cuckoo_options_set_hash_ratio(
rocksdb_cuckoo_table_options_t* options, double v) {
options->rep.hash_table_ratio = v;
}
void rocksdb_cuckoo_options_set_max_search_depth(
rocksdb_cuckoo_table_options_t* options, uint32_t v) {
options->rep.max_search_depth = v;
}
void rocksdb_cuckoo_options_set_cuckoo_block_size(
rocksdb_cuckoo_table_options_t* options, uint32_t v) {
options->rep.cuckoo_block_size = v;
}
void rocksdb_cuckoo_options_set_identity_as_first_hash(
rocksdb_cuckoo_table_options_t* options, unsigned char v) {
options->rep.identity_as_first_hash = v;
}
void rocksdb_cuckoo_options_set_use_module_hash(
rocksdb_cuckoo_table_options_t* options, unsigned char v) {
options->rep.use_module_hash = v;
}
void rocksdb_options_set_cuckoo_table_factory(
rocksdb_options_t *opt,
rocksdb_cuckoo_table_options_t* table_options) {
if (table_options) {
opt->rep.table_factory.reset(
rocksdb::NewCuckooTableFactory(table_options->rep));
}
}
rocksdb_options_t* rocksdb_options_create() {
return new rocksdb_options_t;
}
@@ -1214,6 +1264,11 @@ void rocksdb_options_set_info_log_level(
opt->rep.info_log_level = static_cast<InfoLogLevel>(v);
}
void rocksdb_options_set_db_write_buffer_size(rocksdb_options_t* opt,
size_t s) {
opt->rep.db_write_buffer_size = s;
}
void rocksdb_options_set_write_buffer_size(rocksdb_options_t* opt, size_t s) {
opt->rep.write_buffer_size = s;
}
@@ -1222,6 +1277,10 @@ void rocksdb_options_set_max_open_files(rocksdb_options_t* opt, int n) {
opt->rep.max_open_files = n;
}
void rocksdb_options_set_max_total_wal_size(rocksdb_options_t* opt, uint64_t n) {
opt->rep.max_total_wal_size = n;
}
void rocksdb_options_set_target_file_size_base(
rocksdb_options_t* opt, uint64_t n) {
opt->rep.target_file_size_base = n;
@@ -1840,8 +1899,14 @@ void rocksdb_readoptions_set_snapshot(
void rocksdb_readoptions_set_iterate_upper_bound(
rocksdb_readoptions_t* opt,
const char* key, size_t keylen) {
Slice prefix = Slice(key, keylen);
opt->rep.iterate_upper_bound = &prefix;
if (key == nullptr) {
opt->upper_bound = Slice();
opt->rep.iterate_upper_bound = nullptr;
} else {
opt->upper_bound = Slice(key, keylen);
opt->rep.iterate_upper_bound = &opt->upper_bound;
}
}
void rocksdb_readoptions_set_read_tier(
+79
View File
@@ -801,8 +801,87 @@ int main(int argc, char** argv) {
rocksdb_iter_get_error(iter, &err);
CheckNoError(err);
rocksdb_iter_destroy(iter);
rocksdb_close(db);
rocksdb_destroy_db(options, dbname, &err);
}
StartPhase("cuckoo_options");
{
rocksdb_cuckoo_table_options_t* cuckoo_options;
cuckoo_options = rocksdb_cuckoo_options_create();
rocksdb_cuckoo_options_set_hash_ratio(cuckoo_options, 0.5);
rocksdb_cuckoo_options_set_max_search_depth(cuckoo_options, 200);
rocksdb_cuckoo_options_set_cuckoo_block_size(cuckoo_options, 10);
rocksdb_cuckoo_options_set_identity_as_first_hash(cuckoo_options, 1);
rocksdb_cuckoo_options_set_use_module_hash(cuckoo_options, 0);
rocksdb_options_set_cuckoo_table_factory(options, cuckoo_options);
db = rocksdb_open(options, dbname, &err);
CheckNoError(err);
rocksdb_cuckoo_options_destroy(cuckoo_options);
}
StartPhase("iterate_upper_bound");
{
// Create new empty database
rocksdb_close(db);
rocksdb_destroy_db(options, dbname, &err);
CheckNoError(err);
rocksdb_options_set_prefix_extractor(options, NULL);
db = rocksdb_open(options, dbname, &err);
CheckNoError(err);
rocksdb_put(db, woptions, "a", 1, "0", 1, &err); CheckNoError(err);
rocksdb_put(db, woptions, "foo", 3, "bar", 3, &err); CheckNoError(err);
rocksdb_put(db, woptions, "foo1", 4, "bar1", 4, &err); CheckNoError(err);
rocksdb_put(db, woptions, "g1", 2, "0", 1, &err); CheckNoError(err);
// testing basic case with no iterate_upper_bound and no prefix_extractor
{
rocksdb_readoptions_set_iterate_upper_bound(roptions, NULL, 0);
rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
rocksdb_iter_seek(iter, "foo", 3);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "foo", "bar");
rocksdb_iter_next(iter);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "foo1", "bar1");
rocksdb_iter_next(iter);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "g1", "0");
rocksdb_iter_destroy(iter);
}
// testing iterate_upper_bound and forward iterator
// to make sure it stops at bound
{
// iterate_upper_bound points beyond the last expected entry
rocksdb_readoptions_set_iterate_upper_bound(roptions, "foo2", 4);
rocksdb_iterator_t* iter = rocksdb_create_iterator(db, roptions);
rocksdb_iter_seek(iter, "foo", 3);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "foo", "bar");
rocksdb_iter_next(iter);
CheckCondition(rocksdb_iter_valid(iter));
CheckIter(iter, "foo1", "bar1");
rocksdb_iter_next(iter);
// should stop here...
CheckCondition(!rocksdb_iter_valid(iter));
rocksdb_iter_destroy(iter);
}
}
StartPhase("cleanup");
rocksdb_close(db);
+26 -15
View File
@@ -19,12 +19,15 @@
#include <algorithm>
#include <limits>
#include "db/compaction_picker.h"
#include "db/db_impl.h"
#include "db/job_context.h"
#include "db/version_set.h"
#include "db/writebuffer.h"
#include "db/internal_stats.h"
#include "db/compaction_picker.h"
#include "db/job_context.h"
#include "db/table_properties_collector.h"
#include "db/version_set.h"
#include "db/write_controller.h"
#include "util/autovector.h"
#include "util/hash_skiplist_rep.h"
@@ -223,6 +226,7 @@ void SuperVersionUnrefHandle(void* ptr) {
ColumnFamilyData::ColumnFamilyData(uint32_t id, const std::string& name,
Version* _dummy_versions,
Cache* _table_cache,
WriteBuffer* write_buffer,
const ColumnFamilyOptions& cf_options,
const DBOptions* db_options,
const EnvOptions& env_options,
@@ -237,6 +241,7 @@ ColumnFamilyData::ColumnFamilyData(uint32_t id, const std::string& name,
options_(*db_options, SanitizeOptions(&internal_comparator_, cf_options)),
ioptions_(options_),
mutable_cf_options_(options_, ioptions_),
write_buffer_(write_buffer),
mem_(nullptr),
imm_(options_.min_write_buffer_number_to_merge),
super_version_(nullptr),
@@ -253,12 +258,13 @@ ColumnFamilyData::ColumnFamilyData(uint32_t id, const std::string& name,
internal_stats_.reset(
new InternalStats(ioptions_.num_levels, db_options->env, this));
table_cache_.reset(new TableCache(ioptions_, env_options, _table_cache));
if (ioptions_.compaction_style == kCompactionStyleUniversal) {
compaction_picker_.reset(
new UniversalCompactionPicker(ioptions_, &internal_comparator_));
} else if (ioptions_.compaction_style == kCompactionStyleLevel) {
if (ioptions_.compaction_style == kCompactionStyleLevel) {
compaction_picker_.reset(
new LevelCompactionPicker(ioptions_, &internal_comparator_));
#ifndef ROCKSDB_LITE
} else if (ioptions_.compaction_style == kCompactionStyleUniversal) {
compaction_picker_.reset(
new UniversalCompactionPicker(ioptions_, &internal_comparator_));
} else if (ioptions_.compaction_style == kCompactionStyleFIFO) {
compaction_picker_.reset(
new FIFOCompactionPicker(ioptions_, &internal_comparator_));
@@ -269,6 +275,7 @@ ColumnFamilyData::ColumnFamilyData(uint32_t id, const std::string& name,
"Column family %s does not use any background compaction. "
"Compactions can only be done via CompactFiles\n",
GetName().c_str());
#endif // !ROCKSDB_LITE
} else {
Log(InfoLogLevel::ERROR_LEVEL, ioptions_.info_log,
"Unable to recognize the specified compaction style %d. "
@@ -411,13 +418,19 @@ void ColumnFamilyData::SetCurrent(Version* current_version) {
current_ = current_version;
}
void ColumnFamilyData::CreateNewMemtable(
MemTable* ColumnFamilyData::ConstructNewMemtable(
const MutableCFOptions& mutable_cf_options) {
assert(current_ != nullptr);
return new MemTable(internal_comparator_, ioptions_,
mutable_cf_options, write_buffer_);
}
void ColumnFamilyData::CreateNewMemtable(
const MutableCFOptions& mutable_cf_options) {
if (mem_ != nullptr) {
delete mem_->Unref();
}
mem_ = new MemTable(internal_comparator_, ioptions_, mutable_cf_options);
SetMemtable(ConstructNewMemtable(mutable_cf_options));
mem_->Ref();
}
@@ -598,9 +611,10 @@ ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
const DBOptions* db_options,
const EnvOptions& env_options,
Cache* table_cache,
WriteBuffer* write_buffer,
WriteController* write_controller)
: max_column_family_(0),
dummy_cfd_(new ColumnFamilyData(0, "", nullptr, nullptr,
dummy_cfd_(new ColumnFamilyData(0, "", nullptr, nullptr, nullptr,
ColumnFamilyOptions(), db_options,
env_options, nullptr)),
default_cfd_cache_(nullptr),
@@ -608,6 +622,7 @@ ColumnFamilySet::ColumnFamilySet(const std::string& dbname,
db_options_(db_options),
env_options_(env_options),
table_cache_(table_cache),
write_buffer_(write_buffer),
write_controller_(write_controller),
spin_lock_(ATOMIC_FLAG_INIT) {
// initialize linked list
@@ -672,8 +687,9 @@ ColumnFamilyData* ColumnFamilySet::CreateColumnFamily(
const ColumnFamilyOptions& options) {
assert(column_families_.find(name) == column_families_.end());
ColumnFamilyData* new_cfd =
new ColumnFamilyData(id, name, dummy_versions, table_cache_, options,
db_options_, env_options_, this);
new ColumnFamilyData(id, name, dummy_versions, table_cache_,
write_buffer_, options, db_options_,
env_options_, this);
Lock();
column_families_.insert({name, id});
column_family_data_.insert({id, new_cfd});
@@ -752,11 +768,6 @@ MemTable* ColumnFamilyMemTablesImpl::GetMemTable() const {
return current_->mem();
}
const Options* ColumnFamilyMemTablesImpl::GetOptions() const {
assert(current_ != nullptr);
return current_->options();
}
ColumnFamilyHandle* ColumnFamilyMemTablesImpl::GetColumnFamilyHandle() {
assert(current_ != nullptr);
return &handle_;
+10 -7
View File
@@ -172,8 +172,10 @@ class ColumnFamilyData {
void SetLogNumber(uint64_t log_number) { log_number_ = log_number; }
uint64_t GetLogNumber() const { return log_number_; }
// thread-safe
// !!! To be deprecated! Please don't not use this function anymore!
const Options* options() const { return &options_; }
// thread-safe
const EnvOptions* soptions() const;
const ImmutableCFOptions* ioptions() const { return &ioptions_; }
// REQUIRES: DB mutex held
@@ -199,8 +201,9 @@ class ColumnFamilyData {
MemTable* mem() { return mem_; }
Version* current() { return current_; }
Version* dummy_versions() { return dummy_versions_; }
void SetMemtable(MemTable* new_mem) { mem_ = new_mem; }
void SetCurrent(Version* current);
MemTable* ConstructNewMemtable(const MutableCFOptions& mutable_cf_options);
void SetMemtable(MemTable* new_mem) { mem_ = new_mem; }
void CreateNewMemtable(const MutableCFOptions& mutable_cf_options);
TableCache* table_cache() const { return table_cache_.get(); }
@@ -262,6 +265,7 @@ class ColumnFamilyData {
friend class ColumnFamilySet;
ColumnFamilyData(uint32_t id, const std::string& name,
Version* dummy_versions, Cache* table_cache,
WriteBuffer* write_buffer,
const ColumnFamilyOptions& options,
const DBOptions* db_options, const EnvOptions& env_options,
ColumnFamilySet* column_family_set);
@@ -292,6 +296,8 @@ class ColumnFamilyData {
std::unique_ptr<InternalStats> internal_stats_;
WriteBuffer* write_buffer_;
MemTable* mem_;
MemTableList imm_;
SuperVersion* super_version_;
@@ -364,7 +370,7 @@ class ColumnFamilySet {
ColumnFamilySet(const std::string& dbname, const DBOptions* db_options,
const EnvOptions& env_options, Cache* table_cache,
WriteController* write_controller);
WriteBuffer* write_buffer, WriteController* write_controller);
~ColumnFamilySet();
ColumnFamilyData* GetDefault() const;
@@ -419,6 +425,7 @@ class ColumnFamilySet {
const DBOptions* const db_options_;
const EnvOptions env_options_;
Cache* table_cache_;
WriteBuffer* write_buffer_;
WriteController* write_controller_;
std::atomic_flag spin_lock_;
};
@@ -443,10 +450,6 @@ class ColumnFamilyMemTablesImpl : public ColumnFamilyMemTables {
// REQUIRES: Seek() called first
virtual MemTable* GetMemTable() const override;
// Returns options for selected column family
// REQUIRES: Seek() called first
virtual const Options* GetOptions() const override;
// Returns column family handle for the selected column family
virtual ColumnFamilyHandle* GetColumnFamilyHandle() override;
+26 -6
View File
@@ -218,7 +218,7 @@ class ColumnFamilyTest {
int NumTableFilesAtLevel(int level, int cf) {
return GetProperty(cf,
"rocksdb.num-files-at-level" + std::to_string(level));
"rocksdb.num-files-at-level" + ToString(level));
}
// Return spread of files per level
@@ -387,7 +387,7 @@ TEST(ColumnFamilyTest, DropTest) {
Open({"default"});
CreateColumnFamiliesAndReopen({"pikachu"});
for (int i = 0; i < 100; ++i) {
ASSERT_OK(Put(1, std::to_string(i), "bar" + std::to_string(i)));
ASSERT_OK(Put(1, ToString(i), "bar" + ToString(i)));
}
ASSERT_OK(Flush(1));
@@ -529,8 +529,28 @@ TEST(ColumnFamilyTest, FlushTest) {
ASSERT_OK(Put(1, "mirko", "v3"));
ASSERT_OK(Put(0, "foo", "v2"));
ASSERT_OK(Put(2, "fodor", "v5"));
for (int i = 0; i < 3; ++i) {
Flush(i);
for (int j = 0; j < 2; j++) {
ReadOptions ro;
std::vector<Iterator*> iterators;
// Hold super version.
if (j == 0) {
ASSERT_OK(db_->NewIterators(ro, handles_, &iterators));
}
for (int i = 0; i < 3; ++i) {
uint64_t max_total_in_memory_state =
dbfull()->TEST_max_total_in_memory_state();
Flush(i);
ASSERT_EQ(dbfull()->TEST_max_total_in_memory_state(),
max_total_in_memory_state);
}
ASSERT_OK(Put(1, "foofoo", "bar"));
ASSERT_OK(Put(0, "foofoo", "bar"));
for (auto* it : iterators) {
delete it;
}
}
Reopen();
@@ -774,14 +794,14 @@ TEST(ColumnFamilyTest, DifferentCompactionStyles) {
for (int i = 0; i < one.level0_file_num_compaction_trigger - 1; ++i) {
PutRandomData(1, 11, 10000);
WaitForFlush(1);
ASSERT_EQ(std::to_string(i + 1), FilesPerLevel(1));
ASSERT_EQ(ToString(i + 1), FilesPerLevel(1));
}
// SETUP column family "two" -- level style with 4 levels
for (int i = 0; i < two.level0_file_num_compaction_trigger - 1; ++i) {
PutRandomData(2, 15, 10000);
WaitForFlush(2);
ASSERT_EQ(std::to_string(i + 1), FilesPerLevel(2));
ASSERT_EQ(ToString(i + 1), FilesPerLevel(2));
}
// TRIGGER compaction "one"
+11
View File
@@ -328,4 +328,15 @@ uint64_t Compaction::OutputFilePreallocationSize(
return preallocation_size * 1.1;
}
Compaction* Compaction::TEST_NewCompaction(
int num_levels, int start_level, int out_level, uint64_t target_file_size,
uint64_t max_grandparent_overlap_bytes, uint32_t output_path_id,
CompressionType output_compression, bool seek_compaction,
bool deletion_compaction) {
return new Compaction(num_levels, start_level, out_level, target_file_size,
max_grandparent_overlap_bytes, output_path_id,
output_compression, seek_compaction,
deletion_compaction);
}
} // namespace rocksdb
+10
View File
@@ -183,6 +183,16 @@ class Compaction {
void SetupBottomMostLevel(VersionStorageInfo* vstorage, bool is_manual,
bool level0_only);
static Compaction* TEST_NewCompaction(
int num_levels, int start_level, int out_level, uint64_t target_file_size,
uint64_t max_grandparent_overlap_bytes, uint32_t output_path_id,
CompressionType output_compression, bool seek_compaction = false,
bool deletion_compaction = false);
CompactionInputFiles* TEST_GetInputFiles(int l) {
return &inputs_[l];
}
private:
friend class CompactionPicker;
friend class UniversalCompactionPicker;
+11 -4
View File
@@ -231,6 +231,7 @@ void CompactionJob::Prepare() {
// Generate file_levels_ for compaction berfore making Iterator
compact_->compaction->GenerateFileLevels();
ColumnFamilyData* cfd = compact_->compaction->column_family_data();
assert(cfd != nullptr);
LogToBuffer(
log_buffer_, "[%s] Compacting %d@%d + %d@%d files, score %.2f",
cfd->GetName().c_str(), compact_->compaction->num_input_files(0),
@@ -384,17 +385,22 @@ Status CompactionJob::Run() {
compact_->MergeKeyValueSliceBuffer(&cfd->internal_comparator());
status = ProcessKeyValueCompaction(&imm_micros, input.get(), true);
if (!status.ok()) {
break;
}
compact_->CleanupBatchBuffer();
compact_->CleanupMergedBuffer();
}
} // done processing all prefix batches
// finish the last batch
if (compact_->key_str_buf_.size() > 0) {
CallCompactionFilterV2(compaction_filter_v2);
if (status.ok()) {
if (compact_->key_str_buf_.size() > 0) {
CallCompactionFilterV2(compaction_filter_v2);
}
compact_->MergeKeyValueSliceBuffer(&cfd->internal_comparator());
status = ProcessKeyValueCompaction(&imm_micros, input.get(), true);
}
compact_->MergeKeyValueSliceBuffer(&cfd->internal_comparator());
status = ProcessKeyValueCompaction(&imm_micros, input.get(), true);
} // checking for compaction filter v2
if (status.ok() &&
@@ -990,6 +996,7 @@ Status CompactionJob::InstallCompactionResults(port::Mutex* db_mutex) {
inline SequenceNumber CompactionJob::findEarliestVisibleSnapshot(
SequenceNumber in, const std::vector<SequenceNumber>& snapshots,
SequenceNumber* prev_snapshot) {
assert(snapshots.size());
SequenceNumber prev __attribute__((unused)) = 0;
for (const auto cur : snapshots) {
assert(prev <= cur);
+182
View File
@@ -0,0 +1,182 @@
// 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 <map>
#include <string>
#include "db/compaction_job.h"
#include "db/column_family.h"
#include "db/version_set.h"
#include "db/writebuffer.h"
#include "rocksdb/cache.h"
#include "rocksdb/options.h"
#include "rocksdb/db.h"
#include "util/testharness.h"
#include "util/testutil.h"
#include "table/mock_table.h"
namespace rocksdb {
// TODO(icanadi) Make it simpler once we mock out VersionSet
class CompactionJobTest {
public:
CompactionJobTest()
: env_(Env::Default()),
dbname_(test::TmpDir() + "/compaction_job_test"),
mutable_cf_options_(Options(), ImmutableCFOptions(Options())),
table_cache_(NewLRUCache(50000, 16, 8)),
write_buffer_(db_options_.db_write_buffer_size),
versions_(new VersionSet(dbname_, &db_options_, env_options_,
table_cache_.get(), &write_buffer_,
&write_controller_)),
shutting_down_(false),
mock_table_factory_(new mock::MockTableFactory()) {
ASSERT_OK(env_->CreateDirIfMissing(dbname_));
db_options_.db_paths.emplace_back(dbname_,
std::numeric_limits<uint64_t>::max());
NewDB();
std::vector<ColumnFamilyDescriptor> column_families;
cf_options_.table_factory = mock_table_factory_;
column_families.emplace_back(kDefaultColumnFamilyName, cf_options_);
ASSERT_OK(versions_->Recover(column_families, false));
}
std::string GenerateFileName(uint64_t file_number) {
FileMetaData meta;
std::vector<DbPath> db_paths;
db_paths.emplace_back(dbname_, std::numeric_limits<uint64_t>::max());
meta.fd = FileDescriptor(file_number, 0, 0);
return TableFileName(db_paths, meta.fd.GetNumber(), meta.fd.GetPathId());
}
// returns expected result after compaction
mock::MockFileContents CreateTwoFiles() {
mock::MockFileContents expected_results;
const int kKeysPerFile = 10000;
SequenceNumber sequence_number = 0;
for (int i = 0; i < 2; ++i) {
mock::MockFileContents contents;
SequenceNumber smallest_seqno = 0, largest_seqno = 0;
InternalKey smallest, largest;
for (int k = 0; k < kKeysPerFile; ++k) {
auto key = ToString(i * (kKeysPerFile / 2) + k);
auto value = ToString(i * kKeysPerFile + k);
InternalKey internal_key(key, ++sequence_number, kTypeValue);
if (k == 0) {
smallest = internal_key;
smallest_seqno = sequence_number;
} else if (k == kKeysPerFile - 1) {
largest = internal_key;
largest_seqno = sequence_number;
}
std::pair<std::string, std::string> key_value(
{internal_key.Encode().ToString(), value});
contents.insert(key_value);
if (i == 1 || k < kKeysPerFile / 2) {
expected_results.insert(key_value);
}
}
uint64_t file_number = versions_->NewFileNumber();
ASSERT_OK(mock_table_factory_->CreateMockTable(
env_, GenerateFileName(file_number), std::move(contents)));
VersionEdit edit;
edit.AddFile(0, file_number, 0, 10, smallest, largest, smallest_seqno,
largest_seqno);
mutex_.Lock();
versions_->LogAndApply(versions_->GetColumnFamilySet()->GetDefault(),
mutable_cf_options_, &edit, &mutex_);
mutex_.Unlock();
}
versions_->SetLastSequence(sequence_number);
return expected_results;
}
void NewDB() {
VersionEdit new_db;
new_db.SetLogNumber(0);
new_db.SetNextFile(2);
new_db.SetLastSequence(0);
const std::string manifest = DescriptorFileName(dbname_, 1);
unique_ptr<WritableFile> file;
Status s = env_->NewWritableFile(
manifest, &file, env_->OptimizeForManifestWrite(env_options_));
ASSERT_OK(s);
{
log::Writer log(std::move(file));
std::string record;
new_db.EncodeTo(&record);
s = log.AddRecord(record);
}
ASSERT_OK(s);
// Make "CURRENT" file that points to the new manifest file.
s = SetCurrentFile(env_, dbname_, 1, nullptr);
}
Env* env_;
std::string dbname_;
EnvOptions env_options_;
MutableCFOptions mutable_cf_options_;
std::shared_ptr<Cache> table_cache_;
WriteController write_controller_;
DBOptions db_options_;
ColumnFamilyOptions cf_options_;
WriteBuffer write_buffer_;
std::unique_ptr<VersionSet> versions_;
port::Mutex mutex_;
std::atomic<bool> shutting_down_;
std::shared_ptr<mock::MockTableFactory> mock_table_factory_;
};
TEST(CompactionJobTest, Simple) {
auto cfd = versions_->GetColumnFamilySet()->GetDefault();
auto expected_results = CreateTwoFiles();
auto files = cfd->current()->storage_info()->LevelFiles(0);
ASSERT_EQ(2U, files.size());
std::unique_ptr<Compaction> compaction(Compaction::TEST_NewCompaction(
7, 0, 1, 1024 * 1024, 10, 0, kNoCompression));
compaction->SetInputVersion(cfd->current());
auto compaction_input_files = compaction->TEST_GetInputFiles(0);
compaction_input_files->level = 0;
compaction_input_files->files.push_back(files[0]);
compaction_input_files->files.push_back(files[1]);
SnapshotList snapshots;
int yield_callback_called = 0;
std::function<uint64_t()> yield_callback = [&]() {
yield_callback_called++;
return 0;
};
LogBuffer log_buffer(InfoLogLevel::INFO_LEVEL, db_options_.info_log.get());
mutex_.Lock();
CompactionJob compaction_job(
compaction.get(), db_options_, *cfd->GetLatestMutableCFOptions(),
env_options_, versions_.get(), &shutting_down_, &log_buffer, nullptr,
nullptr, &snapshots, true, table_cache_, std::move(yield_callback));
compaction_job.Prepare();
mutex_.Unlock();
ASSERT_OK(compaction_job.Run());
mutex_.Lock();
Status s;
compaction_job.Install(&s, &mutex_);
ASSERT_OK(s);
mutex_.Unlock();
mock_table_factory_->AssertLatestFile(expected_results);
ASSERT_EQ(yield_callback_called, 20000);
}
} // namespace rocksdb
int main(int argc, char** argv) { return rocksdb::test::RunAllTests(); }
+9 -4
View File
@@ -19,6 +19,7 @@
#include "db/filename.h"
#include "util/log_buffer.h"
#include "util/statistics.h"
#include "util/string_util.h"
namespace rocksdb {
@@ -262,7 +263,7 @@ Status CompactionPicker::GetCompactionInputsFromFileNumbers(
"Cannot find matched SST files for the following file numbers:");
for (auto fn : *input_set) {
message += " ";
message += std::to_string(fn);
message += ToString(fn);
}
return Status::InvalidArgument(message);
}
@@ -386,6 +387,7 @@ Compaction* CompactionPicker::CompactRange(
begin = nullptr;
end = nullptr;
}
vstorage->GetOverlappingInputs(input_level, begin, end, &inputs);
if (inputs.empty()) {
return nullptr;
@@ -616,7 +618,7 @@ Status CompactionPicker::SanitizeCompactionInputFiles(
return Status::InvalidArgument(
"Output level for column family " + cf_meta.name +
" must between [0, " +
std::to_string(cf_meta.levels[cf_meta.levels.size() - 1].level) +
ToString(cf_meta.levels[cf_meta.levels.size() - 1].level) +
"].");
}
@@ -624,7 +626,7 @@ Status CompactionPicker::SanitizeCompactionInputFiles(
return Status::InvalidArgument(
"Exceed the maximum output level defined by "
"the current compaction algorithm --- " +
std::to_string(MaxOutputLevel()));
ToString(MaxOutputLevel()));
}
if (output_level < 0) {
@@ -675,7 +677,7 @@ Status CompactionPicker::SanitizeCompactionInputFiles(
return Status::OK();
}
#endif // ROCKSDB_LITE
#endif // !ROCKSDB_LITE
bool LevelCompactionPicker::NeedsCompaction(const VersionStorageInfo* vstorage)
const {
@@ -841,6 +843,7 @@ Compaction* LevelCompactionPicker::PickCompactionBySize(
return c;
}
#ifndef ROCKSDB_LITE
bool UniversalCompactionPicker::NeedsCompaction(
const VersionStorageInfo* vstorage) const {
const int kLevel0 = 0;
@@ -1324,4 +1327,6 @@ Compaction* FIFOCompactionPicker::CompactRange(
return c;
}
#endif // !ROCKSDB_LITE
} // namespace rocksdb
+31 -29
View File
@@ -169,6 +169,36 @@ class CompactionPicker {
const InternalKeyComparator* const icmp_;
};
class LevelCompactionPicker : public CompactionPicker {
public:
LevelCompactionPicker(const ImmutableCFOptions& ioptions,
const InternalKeyComparator* icmp)
: CompactionPicker(ioptions, icmp) {}
virtual Compaction* PickCompaction(const std::string& cf_name,
const MutableCFOptions& mutable_cf_options,
VersionStorageInfo* vstorage,
LogBuffer* log_buffer) override;
// Returns current_num_levels - 2, meaning the last level cannot be
// compaction input level.
virtual int MaxInputLevel(int current_num_levels) const override {
return current_num_levels - 2;
}
virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const
override;
private:
// For the specfied level, pick a compaction.
// Returns nullptr if there is no compaction to be done.
// If level is 0 and there is already a compaction on that level, this
// function will return nullptr.
Compaction* PickCompactionBySize(const MutableCFOptions& mutable_cf_options,
VersionStorageInfo* vstorage, int level,
double score);
};
#ifndef ROCKSDB_LITE
class UniversalCompactionPicker : public CompactionPicker {
public:
UniversalCompactionPicker(const ImmutableCFOptions& ioptions,
@@ -210,35 +240,6 @@ class UniversalCompactionPicker : public CompactionPicker {
uint64_t file_size);
};
class LevelCompactionPicker : public CompactionPicker {
public:
LevelCompactionPicker(const ImmutableCFOptions& ioptions,
const InternalKeyComparator* icmp)
: CompactionPicker(ioptions, icmp) {}
virtual Compaction* PickCompaction(const std::string& cf_name,
const MutableCFOptions& mutable_cf_options,
VersionStorageInfo* vstorage,
LogBuffer* log_buffer) override;
// Returns current_num_levels - 2, meaning the last level cannot be
// compaction input level.
virtual int MaxInputLevel(int current_num_levels) const override {
return current_num_levels - 2;
}
virtual bool NeedsCompaction(const VersionStorageInfo* vstorage) const
override;
private:
// For the specfied level, pick a compaction.
// Returns nullptr if there is no compaction to be done.
// If level is 0 and there is already a compaction on that level, this
// function will return nullptr.
Compaction* PickCompactionBySize(const MutableCFOptions& mutable_cf_options,
VersionStorageInfo* vstorage, int level,
double score);
};
class FIFOCompactionPicker : public CompactionPicker {
public:
FIFOCompactionPicker(const ImmutableCFOptions& ioptions,
@@ -306,6 +307,7 @@ class NullCompactionPicker : public CompactionPicker {
return false;
}
};
#endif // !ROCKSDB_LITE
// Utility function
extern uint64_t TotalCompensatedFileSize(const std::vector<FileMetaData*>& files);
+6 -6
View File
@@ -192,8 +192,8 @@ TEST(CompactionPickerTest, NeedsCompactionLevel) {
// start a brand new version in each test.
NewVersionStorage(kLevels, kCompactionStyleLevel);
for (int i = 0; i < file_count; ++i) {
Add(level, i, std::to_string((i + 100) * 1000).c_str(),
std::to_string((i + 100) * 1000 + 999).c_str(),
Add(level, i, ToString((i + 100) * 1000).c_str(),
ToString((i + 100) * 1000 + 999).c_str(),
file_size, 0, i * 100, i * 100 + 99);
}
UpdateVersionStorageInfo();
@@ -217,8 +217,8 @@ TEST(CompactionPickerTest, NeedsCompactionUniversal) {
// verify the trigger given different number of L0 files.
for (int i = 1;
i <= mutable_cf_options_.level0_file_num_compaction_trigger * 2; ++i) {
Add(0, i, std::to_string((i + 100) * 1000).c_str(),
std::to_string((i + 100) * 1000 + 999).c_str(), 1000000, 0, i * 100,
Add(0, i, ToString((i + 100) * 1000).c_str(),
ToString((i + 100) * 1000 + 999).c_str(), 1000000, 0, i * 100,
i * 100 + 99);
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
vstorage_->CompactionScore(0) >= 1);
@@ -243,8 +243,8 @@ TEST(CompactionPickerTest, NeedsCompactionFIFO) {
// size of L0 files.
uint64_t current_size = 0;
for (int i = 1; i <= kFileCount; ++i) {
Add(0, i, std::to_string((i + 100) * 1000).c_str(),
std::to_string((i + 100) * 1000 + 999).c_str(),
Add(0, i, ToString((i + 100) * 1000).c_str(),
ToString((i + 100) * 1000 + 999).c_str(),
kFileSize, 0, i * 100, i * 100 + 99);
current_size += kFileSize;
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
+1 -1
View File
@@ -377,7 +377,7 @@ TEST(ComparatorDBTest, DoubleComparator) {
for (uint32_t j = 0; j < divide_order; j++) {
to_divide *= 10.0;
}
source_strings.push_back(std::to_string(r / to_divide));
source_strings.push_back(ToString(r / to_divide));
}
DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 200, 1000, 66);
-27
View File
@@ -228,33 +228,6 @@ TEST(CuckooTableDBTest, Uint64Comparator) {
ASSERT_EQ("v4", Get(Uint64Key(4)));
}
TEST(CuckooTableDBTest, CompactionTrigger) {
Options options = CurrentOptions();
options.write_buffer_size = 100 << 10; // 100KB
options.level0_file_num_compaction_trigger = 2;
Reopen(&options);
// Write 11 values, each 10016 B
for (int idx = 0; idx < 11; ++idx) {
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + idx)));
}
dbfull()->TEST_WaitForFlushMemTable();
ASSERT_EQ("1", FilesPerLevel());
// Generate one more file in level-0, and should trigger level-0 compaction
for (int idx = 11; idx < 22; ++idx) {
ASSERT_OK(Put(Key(idx), std::string(10000, 'a' + idx)));
}
dbfull()->TEST_WaitForFlushMemTable();
ASSERT_EQ("2", FilesPerLevel());
dbfull()->TEST_CompactRange(0, nullptr, nullptr);
ASSERT_EQ("0,2", FilesPerLevel());
for (int idx = 0; idx < 22; ++idx) {
ASSERT_EQ(std::string(10000, 'a' + idx), Get(Key(idx)));
}
}
TEST(CuckooTableDBTest, CompactionIntoMultipleFiles) {
// Create a big L0 file and check it compacts into multiple files in L1.
Options options = CurrentOptions();
+18 -10
View File
@@ -198,6 +198,9 @@ DEFINE_bool(enable_numa, false,
"CPU and memory of same node. Use \"$numactl --hardware\" command "
"to see NUMA memory architecture.");
DEFINE_int64(db_write_buffer_size, rocksdb::Options().db_write_buffer_size,
"Number of bytes to buffer in all memtables before compacting");
DEFINE_int64(write_buffer_size, rocksdb::Options().write_buffer_size,
"Number of bytes to buffer in memtable before compacting");
@@ -1193,7 +1196,7 @@ class Benchmark {
while (start < s.size() && isspace(s[start])) {
start++;
}
unsigned int limit = s.size();
unsigned int limit = static_cast<unsigned int>(s.size());
while (limit > start && isspace(s[limit-1])) {
limit--;
}
@@ -1350,7 +1353,7 @@ class Benchmark {
}
std::string GetDbNameForMultiple(std::string base_name, size_t id) {
return base_name + std::to_string(id);
return base_name + ToString(id);
}
std::string ColumnFamilyName(int i) {
@@ -1364,11 +1367,13 @@ class Benchmark {
}
void Run() {
Options open_options; // keep options around to properly destroy db later
if (!SanityCheck()) {
exit(1);
}
PrintHeader();
Open();
Open(&open_options);
const char* benchmarks = FLAGS_benchmarks.c_str();
while (benchmarks != nullptr) {
const char* sep = strchr(benchmarks, ',');
@@ -1529,15 +1534,15 @@ class Benchmark {
delete db_.db;
db_.db = nullptr;
db_.cfh.clear();
DestroyDB(FLAGS_db, Options());
DestroyDB(FLAGS_db, open_options);
}
for (size_t i = 0; i < multi_dbs_.size(); i++) {
delete multi_dbs_[i].db;
DestroyDB(GetDbNameForMultiple(FLAGS_db, i), Options());
DestroyDB(GetDbNameForMultiple(FLAGS_db, i), open_options);
}
multi_dbs_.clear();
}
Open();
Open(&open_options); // use open_options for the last accessed
}
if (method != nullptr) {
@@ -1829,11 +1834,14 @@ class Benchmark {
}
}
void Open() {
void Open(Options* opts) {
Options& options = *opts;
assert(db_.db == nullptr);
Options options;
options.create_if_missing = !FLAGS_use_existing_db;
options.create_missing_column_families = FLAGS_num_column_families > 1;
options.db_write_buffer_size = FLAGS_db_write_buffer_size;
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 =
@@ -3058,8 +3066,8 @@ int main(int argc, char** argv) {
dbstats = rocksdb::CreateDBStatistics();
}
std::vector<std::string> fanout =
rocksdb::stringSplit(FLAGS_max_bytes_for_level_multiplier_additional, ',');
std::vector<std::string> fanout = rocksdb::StringSplit(
FLAGS_max_bytes_for_level_multiplier_additional, ',');
for (unsigned int j= 0; j < fanout.size(); j++) {
FLAGS_max_bytes_for_level_multiplier_additional_v.push_back(
std::stoi(fanout[j]));
+4
View File
@@ -19,12 +19,14 @@
#include <stdint.h>
#include "db/db_impl.h"
#include "db/filename.h"
#include "db/job_context.h"
#include "db/version_set.h"
#include "rocksdb/db.h"
#include "rocksdb/env.h"
#include "port/port.h"
#include "util/mutexlock.h"
#include "util/sync_point.h"
#include "util/file_util.h"
namespace rocksdb {
@@ -67,6 +69,7 @@ Status DBImpl::EnableFileDeletions(bool force) {
if (should_purge_files) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
LogFlush(db_options_.info_log);
return Status::OK();
}
@@ -134,6 +137,7 @@ Status DBImpl::GetLiveFiles(std::vector<std::string>& ret,
Status DBImpl::GetSortedWalFiles(VectorLogPtr& files) {
return wal_manager_.GetSortedWalFiles(files);
}
}
#endif // ROCKSDB_LITE
+144 -56
View File
@@ -32,6 +32,7 @@
#include "db/db_iter.h"
#include "db/dbformat.h"
#include "db/filename.h"
#include "db/job_context.h"
#include "db/log_reader.h"
#include "db/log_writer.h"
#include "db/memtable.h"
@@ -43,6 +44,7 @@
#include "db/forward_iterator.h"
#include "db/transaction_log_impl.h"
#include "db/version_set.h"
#include "db/writebuffer.h"
#include "db/write_batch_internal.h"
#include "port/port.h"
#include "rocksdb/cache.h"
@@ -74,6 +76,8 @@
#include "util/iostats_context_imp.h"
#include "util/stop_watch.h"
#include "util/sync_point.h"
#include "util/string_util.h"
#include "util/thread_status_impl.h"
namespace rocksdb {
@@ -198,6 +202,7 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname)
default_cf_handle_(nullptr),
total_log_size_(0),
max_total_in_memory_state_(0),
write_buffer_(options.db_write_buffer_size),
tmp_batch_(),
bg_schedule_needed_(false),
bg_compaction_scheduled_(0),
@@ -228,7 +233,8 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname)
db_options_.table_cache_remove_scan_count_limit);
versions_.reset(new VersionSet(dbname_, &db_options_, env_options_,
table_cache_.get(), &write_controller_));
table_cache_.get(), &write_buffer_,
&write_controller_));
column_family_memtables_.reset(new ColumnFamilyMemTablesImpl(
versions_->GetColumnFamilySet(), &flush_scheduler_));
@@ -240,6 +246,7 @@ DBImpl::DBImpl(const DBOptions& options, const std::string& dbname)
}
DBImpl::~DBImpl() {
EraseThreadStatusDbInfo();
mutex_.Lock();
if (flush_on_destroy_) {
@@ -287,6 +294,7 @@ DBImpl::~DBImpl() {
if (job_context.HaveSomethingToDelete()) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
}
// versions need to be destroyed before table_cache since it can hold
@@ -666,6 +674,7 @@ void DBImpl::DeleteObsoleteFiles() {
if (job_context.HaveSomethingToDelete()) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
}
Status DBImpl::Recover(
@@ -1092,24 +1101,25 @@ Status DBImpl::FlushMemTableToOutputFile(
#ifndef ROCKSDB_LITE
if (s.ok()) {
// may temporarily unlock and lock the mutex.
NotifyOnFlushCompleted(cfd, file_number);
NotifyOnFlushCompleted(cfd, file_number, mutable_cf_options);
}
#endif // ROCKSDB_LITE
return s;
}
void DBImpl::NotifyOnFlushCompleted(
ColumnFamilyData* cfd, uint64_t file_number) {
ColumnFamilyData* cfd, uint64_t file_number,
const MutableCFOptions& mutable_cf_options) {
mutex_.AssertHeld();
if (shutting_down_.load(std::memory_order_acquire)) {
return;
}
bool triggered_flush_slowdown =
(cfd->current()->storage_info()->NumLevelFiles(0) >=
cfd->options()->level0_slowdown_writes_trigger);
mutable_cf_options.level0_slowdown_writes_trigger);
bool triggered_flush_stop =
(cfd->current()->storage_info()->NumLevelFiles(0) >=
cfd->options()->level0_stop_writes_trigger);
mutable_cf_options.level0_stop_writes_trigger);
notifying_events_++;
// release lock while notifying events
mutex_.Unlock();
@@ -1343,6 +1353,7 @@ Status DBImpl::CompactFilesImpl(
if (job_context.HaveSomethingToDelete()) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
mutex_.Lock();
}
@@ -1808,6 +1819,7 @@ void DBImpl::BackgroundCallFlush() {
if (job_context.HaveSomethingToDelete()) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
mutex_.Lock();
}
@@ -1884,6 +1896,7 @@ void DBImpl::BackgroundCallCompaction() {
if (job_context.HaveSomethingToDelete()) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
mutex_.Lock();
}
@@ -2057,6 +2070,8 @@ Status DBImpl::BackgroundCompaction(bool* madeProgress, JobContext* job_context,
*c->mutable_cf_options());
VersionStorageInfo::LevelSummaryStorage tmp;
c->column_family_data()->internal_stats()->IncBytesMoved(
c->level() + 1, f->fd.GetFileSize());
LogToBuffer(log_buffer, "[%s] Moved #%" PRIu64 " to level-%d %" PRIu64
" bytes %s: %s\n",
c->column_family_data()->GetName().c_str(), f->fd.GetNumber(),
@@ -2190,6 +2205,7 @@ static void CleanupIteratorState(void* arg1, void* arg2) {
if (job_context.HaveSomethingToDelete()) {
state->db->PurgeObsoleteFiles(job_context);
}
job_context.Clean();
}
delete state;
@@ -2256,6 +2272,15 @@ SuperVersion* DBImpl::InstallSuperVersion(
ColumnFamilyData* cfd, SuperVersion* new_sv,
const MutableCFOptions& mutable_cf_options) {
mutex_.AssertHeld();
// Update max_total_in_memory_state_
size_t old_memtable_size = 0;
auto* old_sv = cfd->GetSuperVersion();
if (old_sv) {
old_memtable_size = old_sv->mutable_cf_options.write_buffer_size *
old_sv->mutable_cf_options.max_write_buffer_number;
}
auto* old = cfd->InstallSuperVersion(
new_sv ? new_sv : new SuperVersion(), &mutex_, mutable_cf_options);
@@ -2265,11 +2290,6 @@ SuperVersion* DBImpl::InstallSuperVersion(
MaybeScheduleFlushOrCompaction();
// Update max_total_in_memory_state_
size_t old_memtable_size = 0;
if (old) {
old_memtable_size = old->mutable_cf_options.write_buffer_size *
old->mutable_cf_options.max_write_buffer_number;
}
max_total_in_memory_state_ =
max_total_in_memory_state_ - old_memtable_size +
mutable_cf_options.write_buffer_size *
@@ -2445,40 +2465,50 @@ std::vector<Status> DBImpl::MultiGet(
Status DBImpl::CreateColumnFamily(const ColumnFamilyOptions& cf_options,
const std::string& column_family_name,
ColumnFamilyHandle** handle) {
Status s;
*handle = nullptr;
MutexLock l(&mutex_);
{
MutexLock l(&mutex_);
if (versions_->GetColumnFamilySet()->GetColumnFamily(column_family_name) !=
nullptr) {
return Status::InvalidArgument("Column family already exists");
}
VersionEdit edit;
edit.AddColumnFamily(column_family_name);
uint32_t new_id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID();
edit.SetColumnFamily(new_id);
edit.SetLogNumber(logfile_number_);
edit.SetComparatorName(cf_options.comparator->Name());
if (versions_->GetColumnFamilySet()->GetColumnFamily(column_family_name) !=
nullptr) {
return Status::InvalidArgument("Column family already exists");
}
VersionEdit edit;
edit.AddColumnFamily(column_family_name);
uint32_t new_id = versions_->GetColumnFamilySet()->GetNextColumnFamilyID();
edit.SetColumnFamily(new_id);
edit.SetLogNumber(logfile_number_);
edit.SetComparatorName(cf_options.comparator->Name());
// LogAndApply will both write the creation in MANIFEST and create
// ColumnFamilyData object
Options opt(db_options_, cf_options);
Status s = versions_->LogAndApply(nullptr,
MutableCFOptions(opt, ImmutableCFOptions(opt)),
&edit, &mutex_, db_directory_.get(), false, &cf_options);
// LogAndApply will both write the creation in MANIFEST and create
// ColumnFamilyData object
Options opt(db_options_, cf_options);
s = versions_->LogAndApply(nullptr,
MutableCFOptions(opt, ImmutableCFOptions(opt)),
&edit, &mutex_, db_directory_.get(), false, &cf_options);
if (s.ok()) {
single_column_family_mode_ = false;
auto* cfd =
versions_->GetColumnFamilySet()->GetColumnFamily(column_family_name);
assert(cfd != nullptr);
delete InstallSuperVersion(
cfd, nullptr, *cfd->GetLatestMutableCFOptions());
*handle = new ColumnFamilyHandleImpl(cfd, this, &mutex_);
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
"Created column family [%s] (ID %u)",
column_family_name.c_str(), (unsigned)cfd->GetID());
} else {
Log(InfoLogLevel::ERROR_LEVEL, db_options_.info_log,
"Creating column family [%s] FAILED -- %s",
column_family_name.c_str(), s.ToString().c_str());
}
} // MutexLock l(&mutex_)
// this is outside the mutex
if (s.ok()) {
single_column_family_mode_ = false;
auto cfd =
versions_->GetColumnFamilySet()->GetColumnFamily(column_family_name);
assert(cfd != nullptr);
delete InstallSuperVersion(cfd, nullptr, *cfd->GetLatestMutableCFOptions());
*handle = new ColumnFamilyHandleImpl(cfd, this, &mutex_);
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
"Created column family [%s] (ID %u)",
column_family_name.c_str(), (unsigned)cfd->GetID());
} else {
Log(InfoLogLevel::ERROR_LEVEL, db_options_.info_log,
"Creating column family [%s] FAILED -- %s",
column_family_name.c_str(), s.ToString().c_str());
NewThreadStatusCfInfo(
reinterpret_cast<ColumnFamilyHandleImpl*>(*handle)->cfd());
}
return s;
}
@@ -2512,6 +2542,10 @@ Status DBImpl::DropColumnFamily(ColumnFamilyHandle* column_family) {
}
if (s.ok()) {
// Note that here we erase the associated cf_info of the to-be-dropped
// cfd before its ref-count goes to zero to avoid having to erase cf_info
// later inside db_mutex.
EraseThreadStatusCfInfo(cfd);
assert(cfd->IsDropped());
auto* mutable_cf_options = cfd->GetLatestMutableCFOptions();
max_total_in_memory_state_ -= mutable_cf_options->write_buffer_size *
@@ -2688,10 +2722,13 @@ bool DBImpl::IsSnapshotSupported() const {
}
const Snapshot* DBImpl::GetSnapshot() {
int64_t unix_time = 0;
env_->GetCurrentTime(&unix_time); // Ignore error
MutexLock l(&mutex_);
// returns null if the underlying memtable does not support snapshot.
if (!IsSnapshotSupported()) return nullptr;
return snapshots_.New(versions_->LastSequence());
return snapshots_.New(versions_->LastSequence(), unix_time);
}
void DBImpl::ReleaseSnapshot(const Snapshot* s) {
@@ -2798,6 +2835,23 @@ Status DBImpl::Write(const WriteOptions& write_options, WriteBatch* my_batch) {
}
}
MaybeScheduleFlushOrCompaction();
} else if (UNLIKELY(write_buffer_.ShouldFlush())) {
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
"Flushing all column families. Write buffer is using %" PRIu64
" bytes out of a total of %" PRIu64 ".",
write_buffer_.memory_usage(), write_buffer_.buffer_size());
// no need to refcount because drop is happening in write thread, so can't
// happen while we're in the write thread
for (auto cfd : *versions_->GetColumnFamilySet()) {
if (!cfd->mem()->IsEmpty()) {
status = SetNewMemtableAndNewLogFile(cfd, &context);
if (!status.ok()) {
break;
}
cfd->imm()->FlushRequested();
}
}
MaybeScheduleFlushOrCompaction();
}
if (UNLIKELY(status.ok() && !bg_error_.ok())) {
@@ -3005,8 +3059,7 @@ Status DBImpl::SetNewMemtableAndNewLogFile(ColumnFamilyData* cfd,
}
if (s.ok()) {
new_mem = new MemTable(cfd->internal_comparator(), *cfd->ioptions(),
mutable_cf_options);
new_mem = cfd->ConstructNewMemtable(mutable_cf_options);
new_superversion = new SuperVersion();
}
}
@@ -3097,7 +3150,7 @@ bool DBImpl::GetProperty(ColumnFamilyHandle* column_family,
bool ret_value = GetIntPropertyInternal(column_family, property_type,
need_out_of_mutex, &int_value);
if (ret_value) {
*value = std::to_string(int_value);
*value = ToString(int_value);
}
return ret_value;
} else {
@@ -3261,6 +3314,7 @@ Status DBImpl::DeleteFile(std::string name) {
if (!status.ok()) {
Log(InfoLogLevel::WARN_LEVEL, db_options_.info_log,
"DeleteFile %s failed. File not found\n", name.c_str());
job_context.Clean();
return Status::InvalidArgument("File not found");
}
assert(level < cfd->NumberLevels());
@@ -3269,6 +3323,7 @@ Status DBImpl::DeleteFile(std::string name) {
if (metadata->being_compacted) {
Log(InfoLogLevel::INFO_LEVEL, db_options_.info_log,
"DeleteFile %s Skipped. File about to be compacted\n", name.c_str());
job_context.Clean();
return Status::OK();
}
@@ -3280,6 +3335,7 @@ Status DBImpl::DeleteFile(std::string name) {
if (vstoreage->NumLevelFiles(i) != 0) {
Log(InfoLogLevel::WARN_LEVEL, db_options_.info_log,
"DeleteFile %s FAILED. File not in last level\n", name.c_str());
job_context.Clean();
return Status::InvalidArgument("File not in last level");
}
}
@@ -3289,6 +3345,7 @@ Status DBImpl::DeleteFile(std::string name) {
Log(InfoLogLevel::WARN_LEVEL, db_options_.info_log,
"DeleteFile %s failed ---"
" target file in level 0 must be the oldest.", name.c_str());
job_context.Clean();
return Status::InvalidArgument("File in level 0, but not oldest");
}
edit.SetColumnFamily(cfd->GetID());
@@ -3306,6 +3363,7 @@ Status DBImpl::DeleteFile(std::string name) {
if (job_context.HaveSomethingToDelete()) {
PurgeObsoleteFiles(job_context);
}
job_context.Clean();
{
MutexLock l(&mutex_);
// schedule flush if file deletion means we freed the space for flushes to
@@ -3349,8 +3407,8 @@ Status DBImpl::CheckConsistency() {
} else if (fsize != md.size) {
corruption_messages += "Sst file size mismatch: " + file_path +
". Size recorded in manifest " +
std::to_string(md.size) + ", actual size " +
std::to_string(fsize) + "\n";
ToString(md.size) + ", actual size " +
ToString(fsize) + "\n";
}
}
if (corruption_messages.size() == 0) {
@@ -3516,6 +3574,7 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
if (cfd != nullptr) {
handles->push_back(
new ColumnFamilyHandleImpl(cfd, impl, &impl->mutex_));
impl->NewThreadStatusCfInfo(cfd);
} else {
if (db_options.create_missing_column_families) {
// missing column family, create it
@@ -3580,17 +3639,8 @@ Status DB::Open(const DBOptions& db_options, const std::string& dbname,
if (s.ok()) {
impl->opened_successfully_ = true;
*dbptr = impl;
// TODO(yhchiang): Add NotifyOnDatabaseOpen() here.
// Since the column-family handles are only available after DB::Open(),
// typically developers will need to pass the returned ColumnFamilyHandles
// to their EventListeners in order to maintain the mapping between
// column-family-name to ColumnFamilyHandle. However, some database
// events might happen before the user passing those ColumnFamilyHandle to
// their Listeners. To address this, we should have NotifyOnDatabaseOpen()
// here which passes the created ColumnFamilyHandle to the Listeners
// as the first event after DB::Open().
} else {
for (auto h : *handles) {
for (auto* h : *handles) {
delete h;
}
handles->clear();
@@ -3689,6 +3739,44 @@ Status DestroyDB(const std::string& dbname, const Options& options) {
return result;
}
#if ROCKSDB_USING_THREAD_STATUS
void DBImpl::NewThreadStatusCfInfo(
ColumnFamilyData* cfd) const {
if (db_options_.enable_thread_tracking) {
ThreadStatusImpl::NewColumnFamilyInfo(
this, GetName(), cfd, cfd->GetName());
}
}
void DBImpl::EraseThreadStatusCfInfo(
ColumnFamilyData* cfd) const {
if (db_options_.enable_thread_tracking) {
ThreadStatusImpl::EraseColumnFamilyInfo(cfd);
}
}
void DBImpl::EraseThreadStatusDbInfo() const {
if (db_options_.enable_thread_tracking) {
ThreadStatusImpl::EraseDatabaseInfo(this);
}
}
Status GetThreadList(std::vector<ThreadStatus>* thread_list) {
return thread_local_status.GetThreadList(thread_list);
}
#else
void DBImpl::NewThreadStatusCfInfo(
ColumnFamilyData* cfd) const {
}
void DBImpl::EraseThreadStatusCfInfo(
ColumnFamilyData* cfd) const {
}
void DBImpl::EraseThreadStatusDbInfo() const {
}
#endif // ROCKSDB_USING_THREAD_STATUS
//
// A global method that can dump out the build version
void DumpRocksDBBuildVersion(Logger * log) {
+19 -2
View File
@@ -24,6 +24,7 @@
#include "db/column_family.h"
#include "db/version_edit.h"
#include "db/wal_manager.h"
#include "db/writebuffer.h"
#include "memtable_list.h"
#include "port/port.h"
#include "rocksdb/db.h"
@@ -34,11 +35,11 @@
#include "util/stop_watch.h"
#include "util/thread_local.h"
#include "util/scoped_arena_iterator.h"
#include "util/hash.h"
#include "db/internal_stats.h"
#include "db/write_controller.h"
#include "db/flush_scheduler.h"
#include "db/write_thread.h"
#include "db/job_context.h"
namespace rocksdb {
@@ -49,6 +50,7 @@ class VersionEdit;
class VersionSet;
class CompactionFilterV2;
class Arena;
struct JobContext;
class DBImpl : public DB {
public:
@@ -228,6 +230,10 @@ class DBImpl : public DB {
// REQUIRES: mutex locked
// pass the pointer that you got from TEST_BeginWrite()
void TEST_EndWrite(void* w);
uint64_t TEST_max_total_in_memory_state() {
return max_total_in_memory_state_;
}
#endif // ROCKSDB_LITE
// Returns the list of live files in 'live' and the list
@@ -246,6 +252,8 @@ class DBImpl : public DB {
ColumnFamilyHandle* DefaultColumnFamily() const;
const SnapshotList& snapshots() const { return snapshots_; }
protected:
Env* const env_;
const std::string dbname_;
@@ -256,7 +264,14 @@ class DBImpl : public DB {
Iterator* NewInternalIterator(const ReadOptions&, ColumnFamilyData* cfd,
SuperVersion* super_version, Arena* arena);
void NotifyOnFlushCompleted(ColumnFamilyData* cfd, uint64_t file_number);
void NotifyOnFlushCompleted(ColumnFamilyData* cfd, uint64_t file_number,
const MutableCFOptions& mutable_cf_options);
void NewThreadStatusCfInfo(ColumnFamilyData* cfd) const;
void EraseThreadStatusCfInfo(ColumnFamilyData* cfd) const;
void EraseThreadStatusDbInfo() const;
private:
friend class DB;
@@ -428,6 +443,8 @@ class DBImpl : public DB {
std::unique_ptr<Directory> db_directory_;
WriteBuffer write_buffer_;
WriteThread write_thread_;
WriteBatch tmp_batch_;
+2 -2
View File
@@ -81,8 +81,8 @@ Status DBImpl::TEST_CompactRange(int level, const Slice* begin,
cfd = cfh->cfd();
}
int output_level =
(cfd->options()->compaction_style == kCompactionStyleUniversal ||
cfd->options()->compaction_style == kCompactionStyleFIFO)
(cfd->ioptions()->compaction_style == kCompactionStyleUniversal ||
cfd->ioptions()->compaction_style == kCompactionStyleFIFO)
? level
: level + 1;
return RunManualCompaction(cfd, level, output_level, 0, begin, end);
+23 -2
View File
@@ -3,15 +3,19 @@
// 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/db_impl_readonly.h"
#include "utilities/compacted_db/compacted_db_impl.h"
#include "db/db_impl.h"
#include "db/merge_context.h"
#include "db/db_iter.h"
#include "util/perf_context_imp.h"
#include "util/thread_status_impl.h"
namespace rocksdb {
#ifndef ROCKSDB_LITE
DBImplReadOnly::DBImplReadOnly(const DBOptions& db_options,
const std::string& dbname)
: DBImpl(db_options, dbname) {
@@ -96,12 +100,10 @@ Status DB::OpenForReadOnly(const Options& options, const std::string& dbname,
// Try to first open DB as fully compacted DB
Status s;
#ifndef ROCKSDB_LITE
s = CompactedDBImpl::Open(options, dbname, dbptr);
if (s.ok()) {
return s;
}
#endif
DBOptions db_options(options);
ColumnFamilyOptions cf_options(options);
@@ -152,6 +154,10 @@ Status DB::OpenForReadOnly(
impl->mutex_.Unlock();
if (s.ok()) {
*dbptr = impl;
for (auto* h : *handles) {
impl->NewThreadStatusCfInfo(
reinterpret_cast<ColumnFamilyHandleImpl*>(h)->cfd());
}
} else {
for (auto h : *handles) {
delete h;
@@ -162,5 +168,20 @@ Status DB::OpenForReadOnly(
return s;
}
#else // !ROCKSDB_LITE
Status DB::OpenForReadOnly(const Options& options, const std::string& dbname,
DB** dbptr, bool error_if_log_file_exist) {
return Status::NotSupported("Not supported in ROCKSDB_LITE.");
}
Status DB::OpenForReadOnly(
const DBOptions& db_options, const std::string& dbname,
const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr,
bool error_if_log_file_exist) {
return Status::NotSupported("Not supported in ROCKSDB_LITE.");
}
#endif // !ROCKSDB_LITE
} // namespace rocksdb
+5
View File
@@ -4,6 +4,9 @@
// of patent rights can be found in the PATENTS file in the same directory.
#pragma once
#ifndef ROCKSDB_LITE
#include "db/db_impl.h"
#include <vector>
#include <string>
@@ -100,3 +103,5 @@ class DBImplReadOnly : public DBImpl {
void operator=(const DBImplReadOnly&);
};
}
#endif // !ROCKSDB_LITE
+3 -2
View File
@@ -281,8 +281,9 @@ void DBIter::MergeValuesNewToOld() {
if (!user_merge_operator_) {
Log(InfoLogLevel::ERROR_LEVEL,
logger_, "Options::merge_operator is null.");
throw std::logic_error("DBIter::MergeValuesNewToOld() with"
" Options::merge_operator null");
status_ = Status::InvalidArgument("user_merge_operator_ must be set.");
valid_ = false;
return;
}
// Start the merge process by pushing the first operand
+7 -7
View File
@@ -366,7 +366,7 @@ TEST(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddMerge("b", "merge_1");
internal_iter->AddMerge("a", "merge_2");
for (size_t k = 0; k < 200; ++k) {
internal_iter->AddPut("c", std::to_string(k));
internal_iter->AddPut("c", ToString(k));
}
internal_iter->Finish();
@@ -379,7 +379,7 @@ TEST(DBIteratorTest, DBIteratorUseSkip) {
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
ASSERT_EQ(db_iter->value().ToString(), std::to_string(i));
ASSERT_EQ(db_iter->value().ToString(), ToString(i));
db_iter->Prev();
ASSERT_TRUE(db_iter->Valid());
@@ -513,11 +513,11 @@ TEST(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddMerge("b", "merge_1");
internal_iter->AddMerge("a", "merge_2");
for (size_t k = 0; k < 200; ++k) {
internal_iter->AddPut("d", std::to_string(k));
internal_iter->AddPut("d", ToString(k));
}
for (size_t k = 0; k < 200; ++k) {
internal_iter->AddPut("c", std::to_string(k));
internal_iter->AddPut("c", ToString(k));
}
internal_iter->Finish();
@@ -529,7 +529,7 @@ TEST(DBIteratorTest, DBIteratorUseSkip) {
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "d");
ASSERT_EQ(db_iter->value().ToString(), std::to_string(i));
ASSERT_EQ(db_iter->value().ToString(), ToString(i));
db_iter->Prev();
ASSERT_TRUE(db_iter->Valid());
@@ -552,7 +552,7 @@ TEST(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddMerge("b", "b");
internal_iter->AddMerge("a", "a");
for (size_t k = 0; k < 200; ++k) {
internal_iter->AddMerge("c", std::to_string(k));
internal_iter->AddMerge("c", ToString(k));
}
internal_iter->Finish();
@@ -566,7 +566,7 @@ TEST(DBIteratorTest, DBIteratorUseSkip) {
ASSERT_EQ(db_iter->key().ToString(), "c");
std::string merge_result = "0";
for (size_t j = 1; j <= i; ++j) {
merge_result += "," + std::to_string(j);
merge_result += "," + ToString(j);
}
ASSERT_EQ(db_iter->value().ToString(), merge_result);
+275 -26
View File
@@ -19,6 +19,7 @@
#include "db/dbformat.h"
#include "db/db_impl.h"
#include "db/filename.h"
#include "db/job_context.h"
#include "db/version_set.h"
#include "db/write_batch_internal.h"
#include "rocksdb/cache.h"
@@ -32,7 +33,9 @@
#include "rocksdb/table.h"
#include "rocksdb/options.h"
#include "rocksdb/table_properties.h"
#include "rocksdb/thread_status.h"
#include "rocksdb/utilities/write_batch_with_index.h"
#include "rocksdb/utilities/checkpoint.h"
#include "table/block_based_table_factory.h"
#include "table/plain_table_factory.h"
#include "util/hash.h"
@@ -47,6 +50,8 @@
#include "util/sync_point.h"
#include "util/testutil.h"
#include "util/mock_env.h"
#include "util/string_util.h"
#include "util/thread_status_impl.h"
namespace rocksdb {
@@ -168,7 +173,9 @@ class SpecialEnv : public EnvWrapper {
std::function<void()>* table_write_callback_;
explicit SpecialEnv(Env* base) : EnvWrapper(base), rnd_(301) {
int64_t addon_time_;
explicit SpecialEnv(Env* base) : EnvWrapper(base), rnd_(301), addon_time_(0) {
delay_sstable_sync_.store(false, std::memory_order_release);
drop_writes_.store(false, std::memory_order_release);
no_space_.store(false, std::memory_order_release);
@@ -363,6 +370,14 @@ class SpecialEnv : public EnvWrapper {
sleep_counter_.Increment();
target()->SleepForMicroseconds(micros);
}
virtual Status GetCurrentTime(int64_t* unix_time) override {
Status s = target()->GetCurrentTime(unix_time);
if (s.ok()) {
*unix_time += addon_time_;
}
return s;
}
};
class DBTest {
@@ -809,6 +824,19 @@ class DBTest {
return result;
}
uint64_t GetNumSnapshots() {
uint64_t int_num;
ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.num-snapshots", &int_num));
return int_num;
}
uint64_t GetTimeOldestSnapshots() {
uint64_t int_num;
ASSERT_TRUE(
dbfull()->GetIntProperty("rocksdb.oldest-snapshot-time", &int_num));
return int_num;
}
// Return a string that contains all key,value pairs in order,
// formatted like "(k1->v1)(k2->v2)".
std::string Contents(int cf = 0) {
@@ -1490,7 +1518,7 @@ TEST(DBTest, GetPropertiesOfAllTablesTest) {
// Create 4 tables
for (int table = 0; table < 4; ++table) {
for (int i = 0; i < 10 + table; ++i) {
db_->Put(WriteOptions(), std::to_string(table * 100 + i), "val");
db_->Put(WriteOptions(), ToString(table * 100 + i), "val");
}
db_->Flush(FlushOptions());
}
@@ -1504,7 +1532,7 @@ TEST(DBTest, GetPropertiesOfAllTablesTest) {
// fetch key from 1st and 2nd table, which will internally place that table to
// the table cache.
for (int i = 0; i < 2; ++i) {
Get(std::to_string(i * 100 + 0));
Get(ToString(i * 100 + 0));
}
VerifyTableProperties(db_, 10 + 11 + 12 + 13);
@@ -1514,7 +1542,7 @@ TEST(DBTest, GetPropertiesOfAllTablesTest) {
// fetch key from 1st and 2nd table, which will internally place that table to
// the table cache.
for (int i = 0; i < 4; ++i) {
Get(std::to_string(i * 100 + 0));
Get(ToString(i * 100 + 0));
}
VerifyTableProperties(db_, 10 + 11 + 12 + 13);
}
@@ -1606,6 +1634,63 @@ TEST(DBTest, GetSnapshot) {
} while (ChangeOptions(kSkipHashCuckoo));
}
TEST(DBTest, GetSnapshotLink) {
do {
Options options;
const std::string snapshot_name = test::TmpDir(env_) + "/snapshot";
DB* snapshotDB;
ReadOptions roptions;
std::string result;
Checkpoint* checkpoint;
options = CurrentOptions(options);
delete db_;
db_ = nullptr;
ASSERT_OK(DestroyDB(dbname_, options));
ASSERT_OK(DestroyDB(snapshot_name, options));
env_->DeleteDir(snapshot_name);
// Create a database
Status s;
options.create_if_missing = true;
ASSERT_OK(DB::Open(options, dbname_, &db_));
std::string key = std::string("foo");
ASSERT_OK(Put(key, "v1"));
// Take a snapshot
ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name));
ASSERT_OK(Put(key, "v2"));
ASSERT_EQ("v2", Get(key));
ASSERT_OK(Flush());
ASSERT_EQ("v2", Get(key));
// Open snapshot and verify contents while DB is running
options.create_if_missing = false;
ASSERT_OK(DB::Open(options, snapshot_name, &snapshotDB));
ASSERT_OK(snapshotDB->Get(roptions, key, &result));
ASSERT_EQ("v1", result);
delete snapshotDB;
snapshotDB = nullptr;
delete db_;
db_ = nullptr;
// Destroy original DB
ASSERT_OK(DestroyDB(dbname_, options));
// Open snapshot and verify contents
options.create_if_missing = false;
dbname_ = snapshot_name;
ASSERT_OK(DB::Open(options, dbname_, &db_));
ASSERT_EQ("v1", Get(key));
delete db_;
db_ = nullptr;
ASSERT_OK(DestroyDB(dbname_, options));
delete checkpoint;
// Restore DB name
dbname_ = test::TmpDir(env_) + "/db_test";
} while (ChangeOptions());
}
TEST(DBTest, GetLevel0Ordering) {
do {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
@@ -3383,7 +3468,7 @@ class ChangeFilterFactory : public CompactionFilterFactory {
// TODO(kailiu) The tests on UniversalCompaction has some issues:
// 1. A lot of magic numbers ("11" or "12").
// 2. Made assumption on the memtable flush conidtions, which may change from
// 2. Made assumption on the memtable flush conditions, which may change from
// time to time.
TEST(DBTest, UniversalCompactionTrigger) {
Options options;
@@ -3459,7 +3544,7 @@ TEST(DBTest, UniversalCompactionTrigger) {
}
dbfull()->TEST_WaitForCompact();
// Before compaction, we have 4 files at level 0, with size 4, 0.4, 1, 1.
// After comapction, we should have 2 files, with size 4, 2.4.
// After compaction, we should have 2 files, with size 4, 2.4.
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 2);
for (int i = 1; i < options.num_levels ; i++) {
ASSERT_EQ(NumTableFilesAtLevel(i, 1), 0);
@@ -3487,7 +3572,7 @@ TEST(DBTest, UniversalCompactionTrigger) {
}
dbfull()->TEST_WaitForCompact();
// Before compaction, we have 4 files at level 0, with size 4, 2.4, 1, 1.
// After comapction, we should have 3 files, with size 4, 2.4, 2.
// After compaction, we should have 3 files, with size 4, 2.4, 2.
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 3);
for (int i = 1; i < options.num_levels ; i++) {
ASSERT_EQ(NumTableFilesAtLevel(i, 1), 0);
@@ -4686,7 +4771,7 @@ TEST(DBTest, CompactionFilterDeletesAll) {
// put some data
for (int table = 0; table < 4; ++table) {
for (int i = 0; i < 10 + table; ++i) {
Put(std::to_string(table * 100 + i), "val");
Put(ToString(table * 100 + i), "val");
}
Flush();
}
@@ -5367,13 +5452,25 @@ TEST(DBTest, Snapshot) {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
Put(0, "foo", "0v1");
Put(1, "foo", "1v1");
const Snapshot* s1 = db_->GetSnapshot();
ASSERT_EQ(1U, GetNumSnapshots());
uint64_t time_snap1 = GetTimeOldestSnapshots();
ASSERT_GT(time_snap1, 0U);
Put(0, "foo", "0v2");
Put(1, "foo", "1v2");
env_->addon_time_++;
const Snapshot* s2 = db_->GetSnapshot();
ASSERT_EQ(2U, GetNumSnapshots());
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
Put(0, "foo", "0v3");
Put(1, "foo", "1v3");
const Snapshot* s3 = db_->GetSnapshot();
ASSERT_EQ(3U, GetNumSnapshots());
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
Put(0, "foo", "0v4");
Put(1, "foo", "1v4");
@@ -5387,6 +5484,8 @@ TEST(DBTest, Snapshot) {
ASSERT_EQ("1v4", Get(1, "foo"));
db_->ReleaseSnapshot(s3);
ASSERT_EQ(2U, GetNumSnapshots());
ASSERT_EQ(time_snap1, GetTimeOldestSnapshots());
ASSERT_EQ("0v1", Get(0, "foo", s1));
ASSERT_EQ("1v1", Get(1, "foo", s1));
ASSERT_EQ("0v2", Get(0, "foo", s2));
@@ -5399,8 +5498,11 @@ TEST(DBTest, Snapshot) {
ASSERT_EQ("1v2", Get(1, "foo", s2));
ASSERT_EQ("0v4", Get(0, "foo"));
ASSERT_EQ("1v4", Get(1, "foo"));
ASSERT_EQ(1U, GetNumSnapshots());
ASSERT_LT(time_snap1, GetTimeOldestSnapshots());
db_->ReleaseSnapshot(s2);
ASSERT_EQ(0U, GetNumSnapshots());
ASSERT_EQ("0v4", Get(0, "foo"));
ASSERT_EQ("1v4", Get(1, "foo"));
} while (ChangeOptions(kSkipHashCuckoo));
@@ -6740,6 +6842,86 @@ TEST(DBTest, RecoverCheckFileAmount) {
}
}
TEST(DBTest, SharedWriteBuffer) {
Options options;
options.db_write_buffer_size = 100000; // this is the real limit
options.write_buffer_size = 500000; // this is never hit
CreateAndReopenWithCF({"pikachu", "dobrynia", "nikitich"}, options);
// Trigger a flush on every CF
ASSERT_OK(Put(0, Key(1), DummyString(1)));
ASSERT_OK(Put(1, Key(1), DummyString(1)));
ASSERT_OK(Put(3, Key(1), DummyString(90000)));
ASSERT_OK(Put(2, Key(2), DummyString(20000)));
ASSERT_OK(Put(2, Key(1), DummyString(1)));
dbfull()->TEST_WaitForFlushMemTable(handles_[0]);
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
{
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
static_cast<uint64_t>(1));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
static_cast<uint64_t>(1));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
static_cast<uint64_t>(1));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
static_cast<uint64_t>(1));
}
// Flush 'dobrynia' and 'nikitich'
ASSERT_OK(Put(2, Key(2), DummyString(50000)));
ASSERT_OK(Put(3, Key(2), DummyString(40000)));
ASSERT_OK(Put(2, Key(3), DummyString(20000)));
ASSERT_OK(Put(3, Key(2), DummyString(40000)));
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
{
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
static_cast<uint64_t>(1));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
static_cast<uint64_t>(1));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
static_cast<uint64_t>(2));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
static_cast<uint64_t>(2));
}
// Make 'dobrynia' and 'nikitich' both take up 40% of space
// When 'pikachu' puts us over 100%, all 3 flush.
ASSERT_OK(Put(2, Key(2), DummyString(40000)));
ASSERT_OK(Put(1, Key(2), DummyString(20000)));
ASSERT_OK(Put(0, Key(1), DummyString(1)));
dbfull()->TEST_WaitForFlushMemTable(handles_[2]);
dbfull()->TEST_WaitForFlushMemTable(handles_[3]);
{
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
static_cast<uint64_t>(1));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
static_cast<uint64_t>(2));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
static_cast<uint64_t>(3));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
static_cast<uint64_t>(3));
}
// Some remaining writes so 'default' and 'nikitich' flush on closure.
ASSERT_OK(Put(3, Key(1), DummyString(1)));
ReopenWithColumnFamilies({"default", "pikachu", "dobrynia", "nikitich"},
options);
{
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "default"),
static_cast<uint64_t>(2));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "pikachu"),
static_cast<uint64_t>(2));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "dobrynia"),
static_cast<uint64_t>(3));
ASSERT_EQ(GetNumberOfSstFilesForColumnFamily(db_, "nikitich"),
static_cast<uint64_t>(4));
}
}
TEST(DBTest, PurgeInfoLogs) {
Options options = CurrentOptions();
options.keep_log_file_num = 5;
@@ -6933,7 +7115,7 @@ TEST(DBTest, TransactionLogIteratorCorruptedLog) {
Options options = OptionsForLogIterTest();
DestroyAndReopen(options);
for (int i = 0; i < 1024; i++) {
Put("key"+std::to_string(i), DummyString(10));
Put("key"+ToString(i), DummyString(10));
}
dbfull()->Flush(FlushOptions());
// Corrupt this log to create a gap
@@ -7001,20 +7183,20 @@ TEST(DBTest, TransactionLogIteratorBlobs) {
struct Handler : public WriteBatch::Handler {
std::string seen;
virtual Status PutCF(uint32_t cf, const Slice& key, const Slice& value) {
seen += "Put(" + std::to_string(cf) + ", " + key.ToString() + ", " +
std::to_string(value.size()) + ")";
seen += "Put(" + ToString(cf) + ", " + key.ToString() + ", " +
ToString(value.size()) + ")";
return Status::OK();
}
virtual Status MergeCF(uint32_t cf, const Slice& key, const Slice& value) {
seen += "Merge(" + std::to_string(cf) + ", " + key.ToString() + ", " +
std::to_string(value.size()) + ")";
seen += "Merge(" + ToString(cf) + ", " + key.ToString() + ", " +
ToString(value.size()) + ")";
return Status::OK();
}
virtual void LogData(const Slice& blob) {
seen += "LogData(" + blob.ToString() + ")";
}
virtual Status DeleteCF(uint32_t cf, const Slice& key) {
seen += "Delete(" + std::to_string(cf) + ", " + key.ToString() + ")";
seen += "Delete(" + ToString(cf) + ", " + key.ToString() + ")";
return Status::OK();
}
} handler;
@@ -7142,7 +7324,7 @@ TEST(DBTest, MultiThreaded) {
do {
std::vector<std::string> cfs;
for (int i = 1; i < kColumnFamilies; ++i) {
cfs.push_back(std::to_string(i));
cfs.push_back(ToString(i));
}
CreateAndReopenWithCF(cfs, CurrentOptions());
// Initialize state
@@ -7195,7 +7377,7 @@ static void GCThreadBody(void* arg) {
WriteOptions wo;
for (int i = 0; i < kGCNumKeys; ++i) {
std::string kv(std::to_string(i + id * kGCNumKeys));
std::string kv(ToString(i + id * kGCNumKeys));
ASSERT_OK(db->Put(wo, kv, kv));
}
t->done = true;
@@ -7231,7 +7413,7 @@ TEST(DBTest, GroupCommitTest) {
std::vector<std::string> expected_db;
for (int i = 0; i < kGCNumThreads * kGCNumKeys; ++i) {
expected_db.push_back(std::to_string(i));
expected_db.push_back(ToString(i));
}
sort(expected_db.begin(), expected_db.end());
@@ -8115,7 +8297,7 @@ TEST(DBTest, FIFOCompactionTest) {
Random rnd(301);
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 100; ++j) {
ASSERT_OK(Put(std::to_string(i * 100 + j), RandomString(&rnd, 1024)));
ASSERT_OK(Put(ToString(i * 100 + j), RandomString(&rnd, 1024)));
}
// flush should happen here
}
@@ -8128,7 +8310,7 @@ TEST(DBTest, FIFOCompactionTest) {
ASSERT_EQ(NumTableFilesAtLevel(0), 5);
for (int i = 0; i < 50; ++i) {
// these keys should be deleted in previous compaction
ASSERT_EQ("NOT_FOUND", Get(std::to_string(i)));
ASSERT_EQ("NOT_FOUND", Get(ToString(i)));
}
}
}
@@ -8456,7 +8638,7 @@ TEST(DBTest, CompactFilesOnLevelCompaction) {
Random rnd(301);
for (int key = 64 * kEntriesPerBuffer; key >= 0; --key) {
ASSERT_OK(Put(1, std::to_string(key), RandomString(&rnd, kTestValueSize)));
ASSERT_OK(Put(1, ToString(key), RandomString(&rnd, kTestValueSize)));
}
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
dbfull()->TEST_WaitForCompact();
@@ -8488,7 +8670,7 @@ TEST(DBTest, CompactFilesOnLevelCompaction) {
// make sure all key-values are still there.
for (int key = 64 * kEntriesPerBuffer; key >= 0; --key) {
ASSERT_NE(Get(1, std::to_string(key)), "NOT_FOUND");
ASSERT_NE(Get(1, ToString(key)), "NOT_FOUND");
}
}
@@ -8510,7 +8692,7 @@ TEST(DBTest, CompactFilesOnUniversalCompaction) {
ASSERT_EQ(options.compaction_style, kCompactionStyleUniversal);
Random rnd(301);
for (int key = 1024 * kEntriesPerBuffer; key >= 0; --key) {
ASSERT_OK(Put(1, std::to_string(key), RandomString(&rnd, kTestValueSize)));
ASSERT_OK(Put(1, ToString(key), RandomString(&rnd, kTestValueSize)));
}
dbfull()->TEST_WaitForFlushMemTable(handles_[1]);
dbfull()->TEST_WaitForCompact();
@@ -8922,6 +9104,73 @@ TEST(DBTest, DynamicMemtableOptions) {
sleeping_task_low3.WaitUntilDone();
}
#if ROCKSDB_USING_THREAD_STATUS
TEST(DBTest, GetThreadList) {
Options options;
options.env = env_;
options.enable_thread_tracking = true;
TryReopen(options);
std::vector<ThreadStatus> thread_list;
Status s = GetThreadList(&thread_list);
for (int i = 0; i < 2; ++i) {
// repeat the test with differet number of high / low priority threads
const int kTestCount = 3;
const unsigned int kHighPriCounts[kTestCount] = {3, 2, 5};
const unsigned int kLowPriCounts[kTestCount] = {10, 15, 3};
for (int test = 0; test < kTestCount; ++test) {
// Change the number of threads in high / low priority pool.
env_->SetBackgroundThreads(kHighPriCounts[test], Env::HIGH);
env_->SetBackgroundThreads(kLowPriCounts[test], Env::LOW);
// Wait to ensure the all threads has been registered
env_->SleepForMicroseconds(100000);
s = GetThreadList(&thread_list);
ASSERT_OK(s);
unsigned int thread_type_counts[ThreadStatus::ThreadType::TOTAL];
memset(thread_type_counts, 0, sizeof(thread_type_counts));
for (auto thread : thread_list) {
ASSERT_LT(thread.thread_type, ThreadStatus::ThreadType::TOTAL);
thread_type_counts[thread.thread_type]++;
}
// Verify the total number of threades
ASSERT_EQ(
thread_list.size(),
kHighPriCounts[test] + kLowPriCounts[test]);
// Verify the number of high-priority threads
ASSERT_EQ(
thread_type_counts[ThreadStatus::ThreadType::ROCKSDB_HIGH_PRIORITY],
kHighPriCounts[test]);
// Verify the number of low-priority threads
ASSERT_EQ(
thread_type_counts[ThreadStatus::ThreadType::ROCKSDB_LOW_PRIORITY],
kLowPriCounts[test]);
}
if (i == 0) {
// repeat the test with multiple column families
CreateAndReopenWithCF({"pikachu", "about-to-remove"}, options);
ThreadStatusImpl::TEST_VerifyColumnFamilyInfoMap(handles_, true);
}
}
db_->DropColumnFamily(handles_[2]);
delete handles_[2];
handles_.erase(handles_.begin() + 2);
ThreadStatusImpl::TEST_VerifyColumnFamilyInfoMap(handles_, true);
Close();
ThreadStatusImpl::TEST_VerifyColumnFamilyInfoMap(handles_, true);
}
TEST(DBTest, DisableThreadList) {
Options options;
options.env = env_;
options.enable_thread_tracking = false;
TryReopen(options);
CreateAndReopenWithCF({"pikachu", "about-to-remove"}, options);
// Verify non of the column family info exists
ThreadStatusImpl::TEST_VerifyColumnFamilyInfoMap(handles_, false);
}
#endif // ROCKSDB_USING_THREAD_STATUS
TEST(DBTest, DynamicCompactionOptions) {
// minimum write buffer size is enforced at 64KB
const uint64_t k32KB = 1 << 15;
@@ -8984,7 +9233,7 @@ TEST(DBTest, DynamicCompactionOptions) {
// result in 2 32KB L1 files.
ASSERT_OK(dbfull()->SetOptions({
{"level0_file_num_compaction_trigger", "2"},
{"target_file_size_base", std::to_string(k32KB) }
{"target_file_size_base", ToString(k32KB) }
}));
gen_l0_kb(0, 64, 1);
@@ -9005,7 +9254,7 @@ TEST(DBTest, DynamicCompactionOptions) {
// fill L1 and L2. L1 size should be around 256KB while L2 size should be
// around 256KB x 4.
ASSERT_OK(dbfull()->SetOptions({
{"max_bytes_for_level_base", std::to_string(k1MB) }
{"max_bytes_for_level_base", ToString(k1MB) }
}));
// writing 96 x 64KB => 6 * 1024KB
@@ -9027,7 +9276,7 @@ TEST(DBTest, DynamicCompactionOptions) {
// reduces to 128KB from 256KB which was asserted previously. Same for L2.
ASSERT_OK(dbfull()->SetOptions({
{"max_bytes_for_level_multiplier", "2"},
{"max_bytes_for_level_base", std::to_string(k128KB) }
{"max_bytes_for_level_base", ToString(k128KB) }
}));
// writing 20 x 64KB = 10 x 128KB
@@ -9127,7 +9376,7 @@ TEST(DBTest, DynamicCompactionOptions) {
// L1 - L3. Then thrink max_bytes_for_level_base and disable auto compaction
// at the same time, we should see some level with score greater than 2.
ASSERT_OK(dbfull()->SetOptions({
{"max_bytes_for_level_base", std::to_string(k1MB) }
{"max_bytes_for_level_base", ToString(k1MB) }
}));
// writing 40 x 64KB = 10 x 256KB
// (L1 + L2 + L3) = (1 + 2 + 4) * 256KB
+2 -1
View File
@@ -34,6 +34,7 @@ class DeleteFileTest {
DeleteFileTest() {
db_ = nullptr;
env_ = Env::Default();
options_.enable_thread_tracking = true;
options_.max_background_flushes = 0;
options_.write_buffer_size = 1024*1024*1000;
options_.target_file_size_base = 1024*1024*1000;
@@ -78,7 +79,7 @@ class DeleteFileTest {
options.sync = false;
ReadOptions roptions;
for (int i = startkey; i < (numkeys + startkey) ; i++) {
std::string temp = std::to_string(i);
std::string temp = ToString(i);
Slice key(temp);
Slice value(temp);
ASSERT_OK(db_->Put(options, key, value));
+12 -8
View File
@@ -9,6 +9,7 @@
#include "db/flush_job.h"
#include "db/column_family.h"
#include "db/version_set.h"
#include "db/writebuffer.h"
#include "rocksdb/cache.h"
#include "util/testharness.h"
#include "util/testutil.h"
@@ -25,10 +26,12 @@ class FlushJobTest {
: env_(Env::Default()),
dbname_(test::TmpDir() + "/flush_job_test"),
table_cache_(NewLRUCache(50000, 16, 8)),
write_buffer_(db_options_.db_write_buffer_size),
versions_(new VersionSet(dbname_, &db_options_, env_options_,
table_cache_.get(), &write_controller_)),
table_cache_.get(), &write_buffer_,
&write_controller_)),
shutting_down_(false),
mock_table_factory_(new MockTableFactory()) {
mock_table_factory_(new mock::MockTableFactory()) {
ASSERT_OK(env_->CreateDirIfMissing(dbname_));
db_options_.db_paths.emplace_back(dbname_,
std::numeric_limits<uint64_t>::max());
@@ -69,11 +72,12 @@ class FlushJobTest {
std::shared_ptr<Cache> table_cache_;
WriteController write_controller_;
DBOptions db_options_;
WriteBuffer write_buffer_;
ColumnFamilyOptions cf_options_;
std::unique_ptr<VersionSet> versions_;
port::Mutex mutex_;
std::atomic<bool> shutting_down_;
std::shared_ptr<MockTableFactory> mock_table_factory_;
std::shared_ptr<mock::MockTableFactory> mock_table_factory_;
};
TEST(FlushJobTest, Empty) {
@@ -85,19 +89,18 @@ TEST(FlushJobTest, Empty) {
SequenceNumber(), &job_context, nullptr, nullptr,
kNoCompression, nullptr);
ASSERT_OK(flush_job.Run());
job_context.Clean();
}
TEST(FlushJobTest, NonEmpty) {
JobContext job_context;
auto cfd = versions_->GetColumnFamilySet()->GetDefault();
auto new_mem = new MemTable(cfd->internal_comparator(), *cfd->ioptions(),
*cfd->GetLatestMutableCFOptions());
auto new_mem = cfd->ConstructNewMemtable(*cfd->GetLatestMutableCFOptions());
new_mem->Ref();
std::map<std::string, std::string> inserted_keys;
for (int i = 1; i < 10000; ++i) {
std::string key(std::to_string(i));
std::string value("value" + std::to_string(i));
std::string key(ToString(i));
std::string value("value" + ToString(i));
new_mem->Add(SequenceNumber(i), kTypeValue, key, value);
InternalKey internal_key(key, SequenceNumber(i), kTypeValue);
inserted_keys.insert({internal_key.Encode().ToString(), value});
@@ -113,6 +116,7 @@ TEST(FlushJobTest, NonEmpty) {
ASSERT_OK(flush_job.Run());
mutex_.Unlock();
mock_table_factory_->AssertSingleFile(inserted_keys);
job_context.Clean();
}
} // namespace rocksdb
+1 -1
View File
@@ -119,7 +119,7 @@ ForwardIterator::ForwardIterator(DBImpl* db, const ReadOptions& read_options,
: db_(db),
read_options_(read_options),
cfd_(cfd),
prefix_extractor_(cfd->options()->prefix_extractor.get()),
prefix_extractor_(cfd->ioptions()->prefix_extractor),
user_comparator_(cfd->user_comparator()),
immutable_min_heap_(MinIterComparator(&cfd_->internal_comparator())),
sv_(current_sv),
+38 -30
View File
@@ -15,10 +15,13 @@
#include <inttypes.h>
#include <vector>
#include "db/column_family.h"
#include "db/db_impl.h"
#include "util/string_util.h"
namespace rocksdb {
#ifndef ROCKSDB_LITE
namespace {
const double kMB = 1048576.0;
const double kGB = kMB * 1024;
@@ -28,18 +31,18 @@ void PrintLevelStatsHeader(char* buf, size_t len, const std::string& cf_name) {
buf, len,
"\n** Compaction Stats [%s] **\n"
"Level Files Size(MB) Score Read(GB) Rn(GB) Rnp1(GB) "
"Write(GB) Wnew(GB) RW-Amp W-Amp Rd(MB/s) Wr(MB/s) Rn(cnt) "
"Rnp1(cnt) Wnp1(cnt) Wnew(cnt) Comp(sec) Comp(cnt) Avg(sec) "
"Write(GB) Wnew(GB) Moved(GB) W-Amp Rd(MB/s) Wr(MB/s) "
"Comp(sec) Comp(cnt) Avg(sec) "
"Stall(sec) Stall(cnt) Avg(ms) RecordIn RecordDrop\n"
"--------------------------------------------------------------------"
"--------------------------------------------------------------------"
"--------------------------------------------------------------------\n",
"----------------------------------------------------------\n",
cf_name.c_str());
}
void PrintLevelStats(char* buf, size_t len, const std::string& name,
int num_files, int being_compacted, double total_file_size, double score,
double rw_amp, double w_amp, double stall_us, uint64_t stalls,
double w_amp, double stall_us, uint64_t stalls,
const InternalStats::CompactionStats& stats) {
uint64_t bytes_read = stats.bytes_readn + stats.bytes_readnp1;
uint64_t bytes_new = stats.bytes_written - stats.bytes_readnp1;
@@ -52,15 +55,11 @@ void PrintLevelStats(char* buf, size_t len, const std::string& name,
"%8.1f " /* Rnp1(GB) */
"%9.1f " /* Write(GB) */
"%8.1f " /* Wnew(GB) */
"%6.1f " /* RW-Amp */
"%9.1f " /* Moved(GB) */
"%5.1f " /* W-Amp */
"%8.1f " /* Rd(MB/s) */
"%8.1f " /* Wr(MB/s) */
"%8d " /* Rn(cnt) */
"%9d " /* Rnp1(cnt) */
"%9d " /* Wnp1(cnt) */
"%9d " /* Wnew(cnt) */
"%10.0f " /* Comp(sec) */
"%9.0f " /* Comp(sec) */
"%9d " /* Comp(cnt) */
"%8.3f " /* Avg(sec) */
"%10.2f " /* Stall(sec) */
@@ -73,10 +72,9 @@ void PrintLevelStats(char* buf, size_t len, const std::string& name,
name.c_str(), num_files, being_compacted, total_file_size / kMB,
score, bytes_read / kGB, stats.bytes_readn / kGB,
stats.bytes_readnp1 / kGB, stats.bytes_written / kGB,
bytes_new / kGB, rw_amp, w_amp, bytes_read / kMB / elapsed,
stats.bytes_written / kMB / elapsed, stats.files_in_leveln,
stats.files_in_levelnp1, stats.files_out_levelnp1,
stats.files_out_levelnp1 - stats.files_in_levelnp1,
bytes_new / kGB, stats.bytes_moved / kGB,
w_amp, bytes_read / kMB / elapsed,
stats.bytes_written / kMB / elapsed,
stats.micros / 1000000.0, stats.count,
stats.count == 0 ? 0 : stats.micros / 1000000.0 / stats.count,
stall_us / 1000000.0, stalls,
@@ -138,6 +136,10 @@ DBPropertyType GetPropertyType(const Slice& property, bool* is_int_property,
return kEstimatedUsageByTableReaders;
} else if (in == "is-file-deletions-enabled") {
return kIsFileDeletionEnabled;
} else if (in == "num-snapshots") {
return kNumSnapshots;
} else if (in == "oldest-snapshot-time") {
return kOldestSnapshotTime;
}
return kUnknown;
}
@@ -265,6 +267,12 @@ bool InternalStats::GetIntProperty(DBPropertyType property_type,
cfd_->imm()->current()->GetTotalNumEntries() +
vstorage->GetEstimatedActiveKeys();
return true;
case kNumSnapshots:
*value = db->snapshots().count();
return true;
case kOldestSnapshotTime:
*value = static_cast<uint64_t>(db->snapshots().GetOldestSnapshotTime());
return true;
#ifndef ROCKSDB_LITE
case kIsFileDeletionEnabled:
*value = db->IsFileDeletionsEnabled();
@@ -361,8 +369,8 @@ void InternalStats::DumpCFStats(std::string* value) {
const VersionStorageInfo* vstorage = cfd_->current()->storage_info();
int num_levels_to_check =
(cfd_->options()->compaction_style != kCompactionStyleUniversal &&
cfd_->options()->compaction_style != kCompactionStyleFIFO)
(cfd_->ioptions()->compaction_style != kCompactionStyleUniversal &&
cfd_->ioptions()->compaction_style != kCompactionStyleFIFO)
? vstorage->num_levels() - 1
: 1;
@@ -425,29 +433,22 @@ void InternalStats::DumpCFStats(std::string* value) {
total_slowdown_count_soft += stall_leveln_slowdown_count_soft_[level];
total_slowdown_hard += stall_leveln_slowdown_hard_[level];
total_slowdown_count_hard += stall_leveln_slowdown_count_hard_[level];
int64_t bytes_read = comp_stats_[level].bytes_readn +
comp_stats_[level].bytes_readnp1;
double rw_amp = (comp_stats_[level].bytes_readn == 0) ? 0.0
: (comp_stats_[level].bytes_written + bytes_read) /
static_cast<double>(comp_stats_[level].bytes_readn);
double w_amp = (comp_stats_[level].bytes_readn == 0) ? 0.0
: comp_stats_[level].bytes_written /
static_cast<double>(comp_stats_[level].bytes_readn);
PrintLevelStats(buf, sizeof(buf), "L" + std::to_string(level), files,
PrintLevelStats(buf, sizeof(buf), "L" + ToString(level), files,
files_being_compacted[level],
vstorage->NumLevelBytes(level), compaction_score[level],
rw_amp, w_amp, stall_us, stalls, comp_stats_[level]);
w_amp, stall_us, stalls, comp_stats_[level]);
value->append(buf);
}
}
uint64_t curr_ingest = cf_stats_value_[BYTES_FLUSHED];
// Cumulative summary
double rw_amp = (stats_sum.bytes_written + stats_sum.bytes_readn +
stats_sum.bytes_readnp1) / static_cast<double>(curr_ingest + 1);
double w_amp = stats_sum.bytes_written / static_cast<double>(curr_ingest + 1);
// Stats summary across levels
PrintLevelStats(buf, sizeof(buf), "Sum", total_files,
total_files_being_compacted, total_file_size, 0, rw_amp, w_amp,
total_files_being_compacted, total_file_size, 0, w_amp,
total_stall_us, total_stall_count, stats_sum);
value->append(buf);
// Interval summary
@@ -455,12 +456,9 @@ void InternalStats::DumpCFStats(std::string* value) {
curr_ingest - cf_stats_snapshot_.ingest_bytes + 1;
CompactionStats interval_stats(stats_sum);
interval_stats.Subtract(cf_stats_snapshot_.comp_stats);
rw_amp = (interval_stats.bytes_written +
interval_stats.bytes_readn + interval_stats.bytes_readnp1) /
static_cast<double>(interval_ingest);
w_amp = interval_stats.bytes_written / static_cast<double>(interval_ingest);
PrintLevelStats(buf, sizeof(buf), "Int", 0, 0, 0, 0,
rw_amp, w_amp, total_stall_us - cf_stats_snapshot_.stall_us,
w_amp, total_stall_us - cf_stats_snapshot_.stall_us,
total_stall_count - cf_stats_snapshot_.stall_count, interval_stats);
value->append(buf);
@@ -496,4 +494,14 @@ void InternalStats::DumpCFStats(std::string* value) {
cf_stats_snapshot_.stall_count = total_stall_count;
}
#else
DBPropertyType GetPropertyType(const Slice& property, bool* is_int_property,
bool* need_out_of_mutex) {
return kUnknown;
}
#endif // !ROCKSDB_LITE
} // namespace rocksdb
+88
View File
@@ -46,12 +46,16 @@ enum DBPropertyType : uint32_t {
kEstimatedUsageByTableReaders, // Estimated memory by table readers.
kIsFileDeletionEnabled, // Equals disable_delete_obsolete_files_,
// 0 means file deletions enabled
kNumSnapshots, // Number of snapshots in the system
kOldestSnapshotTime, // Unix timestamp of the first snapshot
};
extern DBPropertyType GetPropertyType(const Slice& property,
bool* is_int_property,
bool* need_out_of_mutex);
#ifndef ROCKSDB_LITE
class InternalStats {
public:
enum InternalCFStatsType {
@@ -117,6 +121,9 @@ class InternalStats {
// Total bytes written during compaction between levels N and N+1
uint64_t bytes_written;
// Total bytes moved to this level
uint64_t bytes_moved;
// Files read from level N during compaction between levels N and N+1
int files_in_leveln;
@@ -141,6 +148,7 @@ class InternalStats {
bytes_readn(0),
bytes_readnp1(0),
bytes_written(0),
bytes_moved(0),
files_in_leveln(0),
files_in_levelnp1(0),
files_out_levelnp1(0),
@@ -153,6 +161,7 @@ class InternalStats {
bytes_readn(c.bytes_readn),
bytes_readnp1(c.bytes_readnp1),
bytes_written(c.bytes_written),
bytes_moved(c.bytes_moved),
files_in_leveln(c.files_in_leveln),
files_in_levelnp1(c.files_in_levelnp1),
files_out_levelnp1(c.files_out_levelnp1),
@@ -165,6 +174,7 @@ class InternalStats {
this->bytes_readn += c.bytes_readn;
this->bytes_readnp1 += c.bytes_readnp1;
this->bytes_written += c.bytes_written;
this->bytes_moved += c.bytes_moved;
this->files_in_leveln += c.files_in_leveln;
this->files_in_levelnp1 += c.files_in_levelnp1;
this->files_out_levelnp1 += c.files_out_levelnp1;
@@ -178,6 +188,7 @@ class InternalStats {
this->bytes_readn -= c.bytes_readn;
this->bytes_readnp1 -= c.bytes_readnp1;
this->bytes_written -= c.bytes_written;
this->bytes_moved -= c.bytes_moved;
this->files_in_leveln -= c.files_in_leveln;
this->files_in_levelnp1 -= c.files_in_levelnp1;
this->files_out_levelnp1 -= c.files_out_levelnp1;
@@ -191,6 +202,10 @@ class InternalStats {
comp_stats_[level].Add(stats);
}
void IncBytesMoved(int level, uint64_t amount) {
comp_stats_[level].bytes_moved += amount;
}
void RecordLevelNSlowdown(int level, uint64_t micros, bool soft) {
if (soft) {
stall_leveln_slowdown_soft_[level] += micros;
@@ -296,4 +311,77 @@ class InternalStats {
const uint64_t started_at_;
};
#else
class InternalStats {
public:
enum InternalCFStatsType {
LEVEL0_SLOWDOWN,
MEMTABLE_COMPACTION,
LEVEL0_NUM_FILES,
WRITE_STALLS_ENUM_MAX,
BYTES_FLUSHED,
INTERNAL_CF_STATS_ENUM_MAX,
};
enum InternalDBStatsType {
WAL_FILE_BYTES,
WAL_FILE_SYNCED,
BYTES_WRITTEN,
NUMBER_KEYS_WRITTEN,
WRITE_DONE_BY_OTHER,
WRITE_DONE_BY_SELF,
WRITE_WITH_WAL,
INTERNAL_DB_STATS_ENUM_MAX,
};
InternalStats(int num_levels, Env* env, ColumnFamilyData* cfd) {}
struct CompactionStats {
uint64_t micros;
uint64_t bytes_readn;
uint64_t bytes_readnp1;
uint64_t bytes_written;
uint64_t bytes_moved;
int files_in_leveln;
int files_in_levelnp1;
int files_out_levelnp1;
uint64_t num_input_records;
uint64_t num_dropped_records;
int count;
explicit CompactionStats(int _count = 0) {}
explicit CompactionStats(const CompactionStats& c) {}
void Add(const CompactionStats& c) {}
void Subtract(const CompactionStats& c) {}
};
void AddCompactionStats(int level, const CompactionStats& stats) {}
void IncBytesMoved(int level, uint64_t amount) {}
void RecordLevelNSlowdown(int level, uint64_t micros, bool soft) {}
void AddCFStats(InternalCFStatsType type, uint64_t value) {}
void AddDBStats(InternalDBStatsType type, uint64_t value) {}
uint64_t GetBackgroundErrorCount() const { return 0; }
uint64_t BumpAndGetBackgroundErrorCount() { return 0; }
bool GetStringProperty(DBPropertyType property_type, const Slice& property,
std::string* value) { return false; }
bool GetIntProperty(DBPropertyType property_type, uint64_t* value,
DBImpl* db) const { return false; }
bool GetIntPropertyOutOfMutex(DBPropertyType property_type, Version* version,
uint64_t* value) const { return false; }
};
#endif // !ROCKSDB_LITE
} // namespace rocksdb
+13 -2
View File
@@ -21,7 +21,8 @@ class MemTable;
struct JobContext {
inline bool HaveSomethingToDelete() const {
return candidate_files.size() || sst_delete_files.size() ||
log_delete_files.size();
log_delete_files.size() || new_superversion != nullptr ||
superversions_to_free.size() > 0 || memtables_to_free.size() > 0;
}
// Structure to store information for candidate files to delete.
@@ -73,7 +74,7 @@ struct JobContext {
new_superversion = create_superversion ? new SuperVersion() : nullptr;
}
~JobContext() {
void Clean() {
// free pending memtables
for (auto m : memtables_to_free) {
delete m;
@@ -85,6 +86,16 @@ struct JobContext {
// if new_superversion was not used, it will be non-nullptr and needs
// to be freed here
delete new_superversion;
memtables_to_free.clear();
superversions_to_free.clear();
new_superversion = nullptr;
}
~JobContext() {
assert(memtables_to_free.size() == 0);
assert(superversions_to_free.size() == 0);
assert(new_superversion == nullptr);
}
};
+25 -21
View File
@@ -135,10 +135,12 @@ class EventListenerTest {
}
Status Flush(int cf = 0) {
FlushOptions opt = FlushOptions();
opt.wait = true;
if (cf == 0) {
return db_->Flush(FlushOptions());
return db_->Flush(opt);
} else {
return db_->Flush(FlushOptions(), handles_[cf]);
return db_->Flush(opt, handles_[cf]);
}
}
@@ -173,6 +175,7 @@ class TestFlushListener : public EventListener {
TEST(EventListenerTest, OnSingleDBFlushTest) {
Options options;
options.write_buffer_size = 100000;
TestFlushListener* listener = new TestFlushListener();
options.listeners.emplace_back(listener);
std::vector<std::string> cf_names = {
@@ -180,15 +183,15 @@ TEST(EventListenerTest, OnSingleDBFlushTest) {
"nikitich", "alyosha", "popovich"};
CreateAndReopenWithCF(cf_names, &options);
ASSERT_OK(Put(1, "pikachu", "pikachu"));
ASSERT_OK(Put(2, "ilya", "ilya"));
ASSERT_OK(Put(3, "muromec", "muromec"));
ASSERT_OK(Put(4, "dobrynia", "dobrynia"));
ASSERT_OK(Put(5, "nikitich", "nikitich"));
ASSERT_OK(Put(6, "alyosha", "alyosha"));
ASSERT_OK(Put(7, "popovich", "popovich"));
ASSERT_OK(Put(1, "pikachu", std::string(90000, 'p')));
ASSERT_OK(Put(2, "ilya", std::string(90000, 'i')));
ASSERT_OK(Put(3, "muromec", std::string(90000, 'm')));
ASSERT_OK(Put(4, "dobrynia", std::string(90000, 'd')));
ASSERT_OK(Put(5, "nikitich", std::string(90000, 'n')));
ASSERT_OK(Put(6, "alyosha", std::string(90000, 'a')));
ASSERT_OK(Put(7, "popovich", std::string(90000, 'p')));
for (size_t i = 1; i < 8; ++i) {
Flush(static_cast<int>(i));
ASSERT_OK(Flush(static_cast<int>(i)));
dbfull()->TEST_WaitForFlushMemTable();
ASSERT_EQ(listener->flushed_dbs_.size(), i);
ASSERT_EQ(listener->flushed_column_family_names_.size(), i);
@@ -203,6 +206,7 @@ TEST(EventListenerTest, OnSingleDBFlushTest) {
TEST(EventListenerTest, MultiCF) {
Options options;
options.write_buffer_size = 100000;
TestFlushListener* listener = new TestFlushListener();
options.listeners.emplace_back(listener);
std::vector<std::string> cf_names = {
@@ -210,15 +214,15 @@ TEST(EventListenerTest, MultiCF) {
"nikitich", "alyosha", "popovich"};
CreateAndReopenWithCF(cf_names, &options);
ASSERT_OK(Put(1, "pikachu", "pikachu"));
ASSERT_OK(Put(2, "ilya", "ilya"));
ASSERT_OK(Put(3, "muromec", "muromec"));
ASSERT_OK(Put(4, "dobrynia", "dobrynia"));
ASSERT_OK(Put(5, "nikitich", "nikitich"));
ASSERT_OK(Put(6, "alyosha", "alyosha"));
ASSERT_OK(Put(7, "popovich", "popovich"));
ASSERT_OK(Put(1, "pikachu", std::string(90000, 'p')));
ASSERT_OK(Put(2, "ilya", std::string(90000, 'i')));
ASSERT_OK(Put(3, "muromec", std::string(90000, 'm')));
ASSERT_OK(Put(4, "dobrynia", std::string(90000, 'd')));
ASSERT_OK(Put(5, "nikitich", std::string(90000, 'n')));
ASSERT_OK(Put(6, "alyosha", std::string(90000, 'a')));
ASSERT_OK(Put(7, "popovich", std::string(90000, 'p')));
for (size_t i = 1; i < 8; ++i) {
Flush(static_cast<int>(i));
ASSERT_OK(Flush(static_cast<int>(i)));
ASSERT_EQ(listener->flushed_dbs_.size(), i);
ASSERT_EQ(listener->flushed_column_family_names_.size(), i);
}
@@ -254,10 +258,10 @@ TEST(EventListenerTest, MultiDBMultiListeners) {
std::vector<std::vector<ColumnFamilyHandle *>> vec_handles;
for (int d = 0; d < kNumDBs; ++d) {
ASSERT_OK(DestroyDB(dbname_ + std::to_string(d), options));
ASSERT_OK(DestroyDB(dbname_ + ToString(d), options));
DB* db;
std::vector<ColumnFamilyHandle*> handles;
ASSERT_OK(DB::Open(options, dbname_ + std::to_string(d), &db));
ASSERT_OK(DB::Open(options, dbname_ + ToString(d), &db));
for (size_t c = 0; c < cf_names.size(); ++c) {
ColumnFamilyHandle* handle;
db->CreateColumnFamily(cf_opts, cf_names[c], &handle);
@@ -327,7 +331,7 @@ TEST(EventListenerTest, DisableBGCompaction) {
db_->GetColumnFamilyMetaData(handles_[1], &cf_meta);
// keep writing until writes are forced to stop.
for (int i = 0; static_cast<int>(cf_meta.file_count) < kStopTrigger; ++i) {
Put(1, std::to_string(i), std::string(100000, 'x'), wopts);
Put(1, ToString(i), std::string(100000, 'x'), wopts);
db_->GetColumnFamilyMetaData(handles_[1], &cf_meta);
}
ASSERT_GE(listener->slowdown_count, kStopTrigger - kSlowdownTrigger);
+3 -1
View File
@@ -15,6 +15,7 @@
#include "util/benchharness.h"
#include "db/version_set.h"
#include "db/write_controller.h"
#include "db/writebuffer.h"
#include "util/mutexlock.h"
namespace rocksdb {
@@ -52,9 +53,10 @@ void BM_LogAndApply(int iters, int num_base_files) {
// Notice we are using the default options not through SanitizeOptions().
// We might want to initialize some options manually if needed.
options.db_paths.emplace_back(dbname, 0);
WriteBuffer wb(options.db_write_buffer_size);
// The parameter of table cache is passed in as null, so any file I/O
// operation is likely to fail.
vset = new VersionSet(dbname, &options, sopt, nullptr, &wc);
vset = new VersionSet(dbname, &options, sopt, nullptr, &wb, &wc);
std::vector<ColumnFamilyDescriptor> dummy;
dummy.push_back(ColumnFamilyDescriptor());
ASSERT_OK(vset->Recover(dummy));
+8 -4
View File
@@ -15,6 +15,7 @@
#include "db/dbformat.h"
#include "db/merge_context.h"
#include "db/writebuffer.h"
#include "rocksdb/comparator.h"
#include "rocksdb/env.h"
#include "rocksdb/iterator.h"
@@ -52,14 +53,17 @@ MemTableOptions::MemTableOptions(
MemTable::MemTable(const InternalKeyComparator& cmp,
const ImmutableCFOptions& ioptions,
const MutableCFOptions& mutable_cf_options)
const MutableCFOptions& mutable_cf_options,
WriteBuffer* write_buffer)
: comparator_(cmp),
moptions_(ioptions, mutable_cf_options),
refs_(0),
kArenaBlockSize(OptimizeBlockSize(moptions_.arena_block_size)),
arena_(moptions_.arena_block_size),
allocator_(&arena_, write_buffer),
table_(ioptions.memtable_factory->CreateMemTableRep(
comparator_, &arena_, ioptions.prefix_extractor, ioptions.info_log)),
comparator_, &allocator_, ioptions.prefix_extractor,
ioptions.info_log)),
num_entries_(0),
flush_in_progress_(false),
flush_completed_(false),
@@ -76,7 +80,7 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
assert(!should_flush_);
if (prefix_extractor_ && moptions_.memtable_prefix_bloom_bits > 0) {
prefix_bloom_.reset(new DynamicBloom(
&arena_,
&allocator_,
moptions_.memtable_prefix_bloom_bits, ioptions.bloom_locality,
moptions_.memtable_prefix_bloom_probes, nullptr,
moptions_.memtable_prefix_bloom_huge_page_tlb_size,
@@ -179,7 +183,7 @@ Slice MemTableRep::UserKey(const char* key) const {
}
KeyHandle MemTableRep::Allocate(const size_t len, char** buf) {
*buf = arena_->Allocate(len);
*buf = allocator_->Allocate(len);
return static_cast<KeyHandle>(*buf);
}
+9 -5
View File
@@ -19,16 +19,17 @@
#include "rocksdb/db.h"
#include "rocksdb/memtablerep.h"
#include "rocksdb/immutable_options.h"
#include "db/memtable_allocator.h"
#include "util/arena.h"
#include "util/dynamic_bloom.h"
#include "util/mutable_cf_options.h"
namespace rocksdb {
class Arena;
class Mutex;
class MemTableIterator;
class MergeContext;
class WriteBuffer;
struct MemTableOptions {
explicit MemTableOptions(
@@ -67,7 +68,8 @@ class MemTable {
// is zero and the caller must call Ref() at least once.
explicit MemTable(const InternalKeyComparator& comparator,
const ImmutableCFOptions& ioptions,
const MutableCFOptions& mutable_cf_options);
const MutableCFOptions& mutable_cf_options,
WriteBuffer* write_buffer);
~MemTable();
@@ -183,7 +185,10 @@ class MemTable {
void SetNextLogNumber(uint64_t num) { mem_next_logfile_number_ = num; }
// Notify the underlying storage that no more items will be added
void MarkImmutable() { table_->MarkReadOnly(); }
void MarkImmutable() {
table_->MarkReadOnly();
allocator_.DoneAllocating();
}
// return true if the current MemTableRep supports merge operator.
bool IsMergeOperatorSupported() const {
@@ -200,8 +205,6 @@ class MemTable {
return comparator_.comparator;
}
const Arena& TEST_GetArena() const { return arena_; }
const MemTableOptions* GetMemTableOptions() const { return &moptions_; }
private:
@@ -217,6 +220,7 @@ class MemTable {
int refs_;
const size_t kArenaBlockSize;
Arena arena_;
MemTableAllocator allocator_;
unique_ptr<MemTableRep> table_;
uint64_t num_entries_;
+52
View File
@@ -0,0 +1,52 @@
// Copyright (c) 2014, 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 <assert.h>
#include "db/memtable_allocator.h"
#include "db/writebuffer.h"
#include "util/arena.h"
namespace rocksdb {
MemTableAllocator::MemTableAllocator(Arena* arena, WriteBuffer* write_buffer)
: arena_(arena), write_buffer_(write_buffer), bytes_allocated_(0) {
}
MemTableAllocator::~MemTableAllocator() {
DoneAllocating();
}
char* MemTableAllocator::Allocate(size_t bytes) {
assert(write_buffer_ != nullptr);
bytes_allocated_ += bytes;
write_buffer_->ReserveMem(bytes);
return arena_->Allocate(bytes);
}
char* MemTableAllocator::AllocateAligned(size_t bytes, size_t huge_page_size,
Logger* logger) {
assert(write_buffer_ != nullptr);
bytes_allocated_ += bytes;
write_buffer_->ReserveMem(bytes);
return arena_->AllocateAligned(bytes, huge_page_size, logger);
}
void MemTableAllocator::DoneAllocating() {
if (write_buffer_ != nullptr) {
write_buffer_->FreeMem(bytes_allocated_);
write_buffer_ = nullptr;
}
}
size_t MemTableAllocator::BlockSize() const {
return arena_->BlockSize();
}
} // namespace rocksdb
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) 2014, 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.
//
// This is used by the MemTable to allocate write buffer memory. It connects
// to WriteBuffer so we can track and enforce overall write buffer limits.
#pragma once
#include "util/allocator.h"
namespace rocksdb {
class Arena;
class Logger;
class WriteBuffer;
class MemTableAllocator : public Allocator {
public:
explicit MemTableAllocator(Arena* arena, WriteBuffer* write_buffer);
~MemTableAllocator();
// Allocator interface
char* Allocate(size_t bytes) override;
char* AllocateAligned(size_t bytes, size_t huge_page_size = 0,
Logger* logger = nullptr) override;
size_t BlockSize() const override;
// Call when we're finished allocating memory so we can free it from
// the write buffer's limit.
void DoneAllocating();
private:
Arena* arena_;
WriteBuffer* write_buffer_;
size_t bytes_allocated_;
// No copying allowed
MemTableAllocator(const MemTableAllocator&);
void operator=(const MemTableAllocator&);
};
} // namespace rocksdb
+16 -15
View File
@@ -14,6 +14,7 @@
#include "util/histogram.h"
#include "util/stop_watch.h"
#include "util/testharness.h"
#include "util/string_util.h"
bool FLAGS_random_key = false;
@@ -66,21 +67,21 @@ TEST(PerfContextTest, SeekIntoDeletion) {
ReadOptions read_options;
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::string key = "k" + ToString(i);
std::string value = "v" + ToString(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);
std::string key = "k" + ToString(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 key = "k" + ToString(i);
std::string value;
perf_context.Reset();
@@ -118,7 +119,7 @@ TEST(PerfContextTest, SeekIntoDeletion) {
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);
std::string key = "k" + ToString(i);
perf_context.Reset();
StopWatchNano timer(Env::Default(), true);
@@ -231,8 +232,8 @@ void ProfileQueries(bool enabled_time = false) {
db->Flush(fo);
continue;
}
std::string key = "k" + std::to_string(i);
std::string value = "v" + std::to_string(i);
std::string key = "k" + ToString(i);
std::string value = "v" + ToString(i);
std::vector<std::string> values;
@@ -245,8 +246,8 @@ void ProfileQueries(bool enabled_time = false) {
}
for (const int i : keys) {
std::string key = "k" + std::to_string(i);
std::string value = "v" + std::to_string(i);
std::string key = "k" + ToString(i);
std::string value = "v" + ToString(i);
std::vector<Slice> multiget_keys = {Slice(key)};
std::vector<std::string> values;
@@ -335,8 +336,8 @@ void ProfileQueries(bool enabled_time = false) {
hist_mget_num_memtable_checked.Clear();
for (const int i : keys) {
std::string key = "k" + std::to_string(i);
std::string value = "v" + std::to_string(i);
std::string key = "k" + ToString(i);
std::string value = "v" + ToString(i);
std::vector<Slice> multiget_keys = {Slice(key)};
std::vector<std::string> values;
@@ -451,8 +452,8 @@ TEST(PerfContextTest, SeekKeyComparison) {
SetPerfLevel(kEnableTime);
StopWatchNano timer(Env::Default());
for (const int i : keys) {
std::string key = "k" + std::to_string(i);
std::string value = "v" + std::to_string(i);
std::string key = "k" + ToString(i);
std::string value = "v" + ToString(i);
perf_context.Reset();
timer.Start();
@@ -471,8 +472,8 @@ TEST(PerfContextTest, SeekKeyComparison) {
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::string key = "k" + ToString(i);
std::string value = "v" + ToString(i);
std::unique_ptr<Iterator> iter(db->NewIterator(read_options));
perf_context.Reset();
+4 -4
View File
@@ -628,7 +628,7 @@ TEST(PlainTableDBTest, IteratorLargeKeys) {
};
for (size_t i = 0; i < 7; i++) {
ASSERT_OK(Put(key_list[i], std::to_string(i)));
ASSERT_OK(Put(key_list[i], ToString(i)));
}
dbfull()->TEST_FlushMemTable();
@@ -639,7 +639,7 @@ TEST(PlainTableDBTest, IteratorLargeKeys) {
for (size_t i = 0; i < 7; i++) {
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key_list[i], iter->key().ToString());
ASSERT_EQ(std::to_string(i), iter->value().ToString());
ASSERT_EQ(ToString(i), iter->value().ToString());
iter->Next();
}
@@ -676,7 +676,7 @@ TEST(PlainTableDBTest, IteratorLargeKeysWithPrefix) {
MakeLongKeyWithPrefix(26, '6')};
for (size_t i = 0; i < 7; i++) {
ASSERT_OK(Put(key_list[i], std::to_string(i)));
ASSERT_OK(Put(key_list[i], ToString(i)));
}
dbfull()->TEST_FlushMemTable();
@@ -687,7 +687,7 @@ TEST(PlainTableDBTest, IteratorLargeKeysWithPrefix) {
for (size_t i = 0; i < 7; i++) {
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key_list[i], iter->key().ToString());
ASSERT_EQ(std::to_string(i), iter->value().ToString());
ASSERT_EQ(ToString(i), iter->value().ToString());
iter->Next();
}
+1 -1
View File
@@ -442,7 +442,7 @@ TEST(PrefixTest, DynamicPrefixIterator) {
for (auto prefix : prefixes) {
TestKey test_key(prefix, FLAGS_items_per_prefix / 2);
Slice key = TestKeyToSlice(test_key);
std::string value = "v" + std::to_string(0);
std::string value = "v" + ToString(0);
perf_context.Reset();
StopWatchNano timer(Env::Default(), true);
+4 -2
View File
@@ -45,6 +45,7 @@
#include "db/memtable.h"
#include "db/table_cache.h"
#include "db/version_edit.h"
#include "db/writebuffer.h"
#include "db/write_batch_internal.h"
#include "rocksdb/comparator.h"
#include "rocksdb/db.h"
@@ -220,9 +221,10 @@ class Repairer {
std::string scratch;
Slice record;
WriteBatch batch;
WriteBuffer wb(options_.db_write_buffer_size);
MemTable* mem = new MemTable(icmp_, ioptions_,
MutableCFOptions(options_, ioptions_));
auto cf_mems_default = new ColumnFamilyMemTablesDefault(mem, &options_);
MutableCFOptions(options_, ioptions_), &wb);
auto cf_mems_default = new ColumnFamilyMemTablesDefault(mem);
mem->Ref();
int counter = 0;
while (reader.ReadRecord(&record, &scratch)) {
+12 -12
View File
@@ -34,9 +34,8 @@
#include <assert.h>
#include <atomic>
#include <stdlib.h>
#include "util/arena.h"
#include "port/port.h"
#include "util/arena.h"
#include "util/allocator.h"
#include "util/random.h"
namespace rocksdb {
@@ -48,9 +47,9 @@ class SkipList {
public:
// Create a new SkipList object that will use "cmp" for comparing keys,
// and will allocate memory using "*arena". Objects allocated in the arena
// must remain allocated for the lifetime of the skiplist object.
explicit SkipList(Comparator cmp, Arena* arena,
// and will allocate memory using "*allocator". Objects allocated in the
// allocator must remain allocated for the lifetime of the skiplist object.
explicit SkipList(Comparator cmp, Allocator* allocator,
int32_t max_height = 12, int32_t branching_factor = 4);
// Insert key into the list.
@@ -110,7 +109,7 @@ class SkipList {
// Immutable after construction
Comparator const compare_;
Arena* const arena_; // Arena used for allocations of nodes
Allocator* const allocator_; // Allocator used for allocations of nodes
Node* const head_;
@@ -196,7 +195,7 @@ struct SkipList<Key, Comparator>::Node {
template<typename Key, class Comparator>
typename SkipList<Key, Comparator>::Node*
SkipList<Key, Comparator>::NewNode(const Key& key, int height) {
char* mem = arena_->AllocateAligned(
char* mem = allocator_->AllocateAligned(
sizeof(Node) + sizeof(std::atomic<Node*>) * (height - 1));
return new (mem) Node(key);
}
@@ -356,23 +355,24 @@ typename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::FindLast()
}
template<typename Key, class Comparator>
SkipList<Key, Comparator>::SkipList(const Comparator cmp, Arena* arena,
SkipList<Key, Comparator>::SkipList(const Comparator cmp, Allocator* allocator,
int32_t max_height,
int32_t branching_factor)
: kMaxHeight_(max_height),
kBranching_(branching_factor),
compare_(cmp),
arena_(arena),
allocator_(allocator),
head_(NewNode(0 /* any key will do */, max_height)),
max_height_(1),
prev_height_(1),
rnd_(0xdeadbeef) {
assert(kMaxHeight_ > 0);
assert(kBranching_ > 0);
// Allocate the prev_ Node* array, directly from the passed-in arena.
// Allocate the prev_ Node* array, directly from the passed-in allocator.
// prev_ does not need to be freed, as its life cycle is tied up with
// the arena as a whole.
prev_ = (Node**) arena_->AllocateAligned(sizeof(Node*) * kMaxHeight_);
// the allocator as a whole.
prev_ = reinterpret_cast<Node**>(
allocator_->AllocateAligned(sizeof(Node*) * kMaxHeight_));
for (int i = 0; i < kMaxHeight_; i++) {
head_->SetNext(i, nullptr);
prev_[i] = head_;
+18 -1
View File
@@ -28,6 +28,8 @@ class SnapshotImpl : public Snapshot {
SnapshotImpl* next_;
SnapshotList* list_; // just for sanity checks
int64_t unix_time_;
};
class SnapshotList {
@@ -36,20 +38,23 @@ class SnapshotList {
list_.prev_ = &list_;
list_.next_ = &list_;
list_.number_ = 0xFFFFFFFFL; // placeholder marker, for debugging
count_ = 0;
}
bool empty() const { return list_.next_ == &list_; }
SnapshotImpl* oldest() const { assert(!empty()); return list_.next_; }
SnapshotImpl* newest() const { assert(!empty()); return list_.prev_; }
const SnapshotImpl* New(SequenceNumber seq) {
const SnapshotImpl* New(SequenceNumber seq, uint64_t unix_time) {
SnapshotImpl* s = new SnapshotImpl;
s->number_ = seq;
s->unix_time_ = unix_time;
s->list_ = this;
s->next_ = &list_;
s->prev_ = list_.prev_;
s->prev_->next_ = s;
s->next_->prev_ = s;
count_++;
return s;
}
@@ -57,6 +62,7 @@ class SnapshotList {
assert(s->list_ == this);
s->prev_->next_ = s->next_;
s->next_->prev_ = s->prev_;
count_--;
delete s;
}
@@ -78,9 +84,20 @@ class SnapshotList {
return newest()->number_;
}
int64_t GetOldestSnapshotTime() const {
if (empty()) {
return 0;
} else {
return oldest()->unix_time_;
}
}
uint64_t count() const { return count_; }
private:
// Dummy head of doubly-linked list of snapshots
SnapshotImpl list_;
uint64_t count_;
};
} // namespace rocksdb
+2 -1
View File
@@ -7,6 +7,7 @@
#include "db/dbformat.h"
#include "util/coding.h"
#include "util/string_util.h"
namespace rocksdb {
@@ -40,7 +41,7 @@ Status InternalKeyPropertiesCollector::Finish(
UserCollectedProperties
InternalKeyPropertiesCollector::GetReadableProperties() const {
return {
{ "kDeletedKeys", std::to_string(deleted_keys_) }
{ "kDeletedKeys", ToString(deleted_keys_) }
};
}
+2 -2
View File
@@ -135,8 +135,8 @@ TEST(VersionBuilderTest, EstimatedActiveKeys) {
const uint32_t kDeletionsPerFile = 100;
for (uint32_t i = 0; i < kNumFiles; ++i) {
Add(static_cast<int>(i / kFilesPerLevel), i + 1,
std::to_string((i + 100) * 1000).c_str(),
std::to_string((i + 100) * 1000 + 999).c_str(),
ToString((i + 100) * 1000).c_str(),
ToString((i + 100) * 1000 + 999).c_str(),
100U, 0, 100, 100,
kEntriesPerFile, kDeletionsPerFile,
(i < kTotalSamples));
+12 -4
View File
@@ -31,6 +31,7 @@
#include "db/table_cache.h"
#include "db/compaction.h"
#include "db/version_builder.h"
#include "db/writebuffer.h"
#include "rocksdb/env.h"
#include "rocksdb/merge_operator.h"
#include "table/table_reader.h"
@@ -1490,9 +1491,11 @@ struct VersionSet::ManifestWriter {
VersionSet::VersionSet(const std::string& dbname, const DBOptions* db_options,
const EnvOptions& storage_options, Cache* table_cache,
WriteBuffer* write_buffer,
WriteController* write_controller)
: column_family_set_(new ColumnFamilySet(
dbname, db_options, storage_options, table_cache, write_controller)),
dbname, db_options, storage_options, table_cache,
write_buffer, write_controller)),
env_(db_options->env),
dbname_(dbname),
db_options_(db_options),
@@ -2215,7 +2218,8 @@ Status VersionSet::ReduceNumberOfLevels(const std::string& dbname,
options->max_open_files - 10, options->table_cache_numshardbits,
options->table_cache_remove_scan_count_limit));
WriteController wc;
VersionSet versions(dbname, options, env_options, tc.get(), &wc);
WriteBuffer wb(options->db_write_buffer_size);
VersionSet versions(dbname, options, env_options, tc.get(), &wb, &wc);
Status status;
std::vector<ColumnFamilyDescriptor> dummy;
@@ -2436,7 +2440,6 @@ Status VersionSet::DumpManifest(Options& options, std::string& dscname,
v->storage_info()->num_levels() - 1);
cfd->compaction_picker()->SizeBeingCompacted(size_being_compacted);
v->PrepareApply(*cfd->GetLatestMutableCFOptions(), size_being_compacted);
delete builder;
printf("--------------- Column family \"%s\" (ID %u) --------------\n",
cfd->GetName().c_str(), (unsigned int)cfd->GetID());
@@ -2451,6 +2454,11 @@ Status VersionSet::DumpManifest(Options& options, std::string& dscname,
delete v;
}
// Free builders
for (auto& builder : builders) {
delete builder.second;
}
next_file_number_.store(next_file + 1);
last_sequence_ = last_sequence;
prev_log_number_ = previous_log_number;
@@ -2639,7 +2647,7 @@ Iterator* VersionSet::MakeInputIterator(Compaction* c) {
auto cfd = c->column_family_data();
ReadOptions read_options;
read_options.verify_checksums =
cfd->options()->verify_checksums_in_compaction;
c->mutable_cf_options()->verify_checksums_in_compaction;
read_options.fill_cache = false;
// Level-0 files have to be merged together. For other levels,
+2 -1
View File
@@ -50,6 +50,7 @@ class LookupKey;
class MemTable;
class Version;
class VersionSet;
class WriteBuffer;
class MergeContext;
class ColumnFamilyData;
class ColumnFamilySet;
@@ -475,7 +476,7 @@ class VersionSet {
public:
VersionSet(const std::string& dbname, const DBOptions* db_options,
const EnvOptions& env_options, Cache* table_cache,
WriteController* write_controller);
WriteBuffer* write_buffer, WriteController* write_controller);
~VersionSet();
// Apply *edit to the current version to form a new descriptor that
+3 -2
View File
@@ -31,6 +31,7 @@
#include "util/logging.h"
#include "util/mutexlock.h"
#include "util/sync_point.h"
#include "util/string_util.h"
namespace rocksdb {
@@ -355,9 +356,9 @@ Status WalManager::ReadFirstRecord(const WalFileType type,
SequenceNumber* sequence) {
if (type != kAliveLogFile && type != kArchivedLogFile) {
Log(InfoLogLevel::ERROR_LEVEL, db_options_.info_log,
"[WalManger] Unknown file type %s", std::to_string(type).c_str());
"[WalManger] Unknown file type %s", ToString(type).c_str());
return Status::NotSupported(
"File Type Not Known " + std::to_string(type));
"File Type Not Known " + ToString(type));
}
{
MutexLock l(&read_first_record_cache_mutex_);
+6 -2
View File
@@ -13,6 +13,7 @@
#include "db/log_writer.h"
#include "db/column_family.h"
#include "db/version_set.h"
#include "db/writebuffer.h"
#include "util/testharness.h"
#include "util/testutil.h"
#include "table/mock_table.h"
@@ -28,6 +29,7 @@ class WalManagerTest {
: env_(Env::Default()),
dbname_(test::TmpDir() + "/wal_manager_test"),
table_cache_(NewLRUCache(50000, 16, 8)),
write_buffer_(db_options_.db_write_buffer_size),
current_log_number_(0) {
DestroyDB(dbname_, Options());
}
@@ -40,7 +42,8 @@ class WalManagerTest {
db_options_.wal_dir = dbname_;
versions_.reset(new VersionSet(dbname_, &db_options_, env_options_,
table_cache_.get(), &write_controller_));
table_cache_.get(), &write_buffer_,
&write_controller_));
wal_manager_.reset(new WalManager(db_options_, env_options_));
}
@@ -73,7 +76,7 @@ class WalManagerTest {
for (int i = 1; i <= num_logs; ++i) {
RollTheLog(true);
for (int k = 0; k < entries_per_log; ++k) {
Put(std::to_string(k), std::string(1024, 'a'));
Put(ToString(k), std::string(1024, 'a'));
}
}
}
@@ -93,6 +96,7 @@ class WalManagerTest {
EnvOptions env_options_;
std::shared_ptr<Cache> table_cache_;
DBOptions db_options_;
WriteBuffer write_buffer_;
std::unique_ptr<VersionSet> versions_;
std::unique_ptr<WalManager> wal_manager_;
-14
View File
@@ -48,20 +48,6 @@ WriteBatch::~WriteBatch() { }
WriteBatch::Handler::~Handler() { }
void WriteBatch::Handler::Put(const Slice& key, const Slice& value) {
// you need to either implement Put or PutCF
throw std::runtime_error("Handler::Put not implemented!");
}
void WriteBatch::Handler::Merge(const Slice& key, const Slice& value) {
throw std::runtime_error("Handler::Merge not implemented!");
}
void WriteBatch::Handler::Delete(const Slice& key) {
// you need to either implement Delete or DeleteCF
throw std::runtime_error("Handler::Delete not implemented!");
}
void WriteBatch::Handler::LogData(const Slice& blob) {
// If the user has not specified something to do with blobs, then we ignore
// them.
+2 -9
View File
@@ -26,15 +26,14 @@ class ColumnFamilyMemTables {
// been processed)
virtual uint64_t GetLogNumber() const = 0;
virtual MemTable* GetMemTable() const = 0;
virtual const Options* GetOptions() const = 0;
virtual ColumnFamilyHandle* GetColumnFamilyHandle() = 0;
virtual void CheckMemtableFull() = 0;
};
class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables {
public:
ColumnFamilyMemTablesDefault(MemTable* mem, const Options* options)
: ok_(false), mem_(mem), options_(options) {}
explicit ColumnFamilyMemTablesDefault(MemTable* mem)
: ok_(false), mem_(mem) {}
bool Seek(uint32_t column_family_id) override {
ok_ = (column_family_id == 0);
@@ -48,11 +47,6 @@ class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables {
return mem_;
}
const Options* GetOptions() const override {
assert(ok_);
return options_;
}
ColumnFamilyHandle* GetColumnFamilyHandle() override { return nullptr; }
void CheckMemtableFull() override {}
@@ -60,7 +54,6 @@ class ColumnFamilyMemTablesDefault : public ColumnFamilyMemTables {
private:
bool ok_;
MemTable* mem_;
const Options* const options_;
};
// WriteBatchInternal provides static methods for manipulating a
+40 -5
View File
@@ -13,6 +13,7 @@
#include "db/memtable.h"
#include "db/column_family.h"
#include "db/write_batch_internal.h"
#include "db/writebuffer.h"
#include "rocksdb/env.h"
#include "rocksdb/memtablerep.h"
#include "rocksdb/utilities/write_batch_with_index.h"
@@ -28,11 +29,12 @@ static std::string PrintContents(WriteBatch* b) {
Options options;
options.memtable_factory = factory;
ImmutableCFOptions ioptions(options);
WriteBuffer wb(options.db_write_buffer_size);
MemTable* mem = new MemTable(cmp, ioptions,
MutableCFOptions(options, ioptions));
MutableCFOptions(options, ioptions), &wb);
mem->Ref();
std::string state;
ColumnFamilyMemTablesDefault cf_mems_default(mem, &options);
ColumnFamilyMemTablesDefault cf_mems_default(mem);
Status s = WriteBatchInternal::InsertInto(b, &cf_mems_default);
int count = 0;
Arena arena;
@@ -155,7 +157,7 @@ namespace {
if (column_family_id == 0) {
seen += "Put(" + key.ToString() + ", " + value.ToString() + ")";
} else {
seen += "PutCF(" + std::to_string(column_family_id) + ", " +
seen += "PutCF(" + ToString(column_family_id) + ", " +
key.ToString() + ", " + value.ToString() + ")";
}
return Status::OK();
@@ -165,7 +167,7 @@ namespace {
if (column_family_id == 0) {
seen += "Merge(" + key.ToString() + ", " + value.ToString() + ")";
} else {
seen += "MergeCF(" + std::to_string(column_family_id) + ", " +
seen += "MergeCF(" + ToString(column_family_id) + ", " +
key.ToString() + ", " + value.ToString() + ")";
}
return Status::OK();
@@ -177,7 +179,7 @@ namespace {
if (column_family_id == 0) {
seen += "Delete(" + key.ToString() + ")";
} else {
seen += "DeleteCF(" + std::to_string(column_family_id) + ", " +
seen += "DeleteCF(" + ToString(column_family_id) + ", " +
key.ToString() + ")";
}
return Status::OK();
@@ -185,6 +187,39 @@ namespace {
};
}
TEST(WriteBatchTest, MergeNotImplemented) {
WriteBatch batch;
batch.Merge(Slice("foo"), Slice("bar"));
ASSERT_EQ(1, batch.Count());
ASSERT_EQ("Merge(foo, bar)@0",
PrintContents(&batch));
WriteBatch::Handler handler;
ASSERT_OK(batch.Iterate(&handler));
}
TEST(WriteBatchTest, PutNotImplemented) {
WriteBatch batch;
batch.Put(Slice("k1"), Slice("v1"));
ASSERT_EQ(1, batch.Count());
ASSERT_EQ("Put(k1, v1)@0",
PrintContents(&batch));
WriteBatch::Handler handler;
ASSERT_OK(batch.Iterate(&handler));
}
TEST(WriteBatchTest, DeleteNotImplemented) {
WriteBatch batch;
batch.Delete(Slice("k2"));
ASSERT_EQ(1, batch.Count());
ASSERT_EQ("Delete(k2)@0",
PrintContents(&batch));
WriteBatch::Handler handler;
ASSERT_OK(batch.Iterate(&handler));
}
TEST(WriteBatchTest, Blob) {
WriteBatch batch;
batch.Put(Slice("k1"), Slice("v1"));
+44
View File
@@ -0,0 +1,44 @@
// Copyright (c) 2014, 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.
//
// WriteBuffer is for managing memory allocation for one or more MemTables.
#pragma once
namespace rocksdb {
class WriteBuffer {
public:
explicit WriteBuffer(size_t _buffer_size)
: buffer_size_(_buffer_size), memory_used_(0) {}
~WriteBuffer() {}
size_t memory_usage() const { return memory_used_; }
size_t buffer_size() const { return buffer_size_; }
// Should only be called from write thread
bool ShouldFlush() const {
return buffer_size() > 0 && memory_usage() >= buffer_size();
}
// Should only be called from write thread
void ReserveMem(size_t mem) { memory_used_ += mem; }
void FreeMem(size_t mem) { memory_used_ -= mem; }
private:
const size_t buffer_size_;
size_t memory_used_;
// No copying allowed
WriteBuffer(const WriteBuffer&);
void operator=(const WriteBuffer&);
};
} // namespace rocksdb
+2 -2
View File
@@ -156,14 +156,14 @@ int main() {
// if background compaction is not working, write will stall
// because of options.level0_stop_writes_trigger
for (int i = 1000; i < 99999; ++i) {
db->Put(WriteOptions(), std::to_string(i),
db->Put(WriteOptions(), ToString(i),
std::string(500, 'a' + (i % 26)));
}
// verify the values are still there
std::string value;
for (int i = 1000; i < 99999; ++i) {
db->Get(ReadOptions(), std::to_string(i),
db->Get(ReadOptions(), ToString(i),
&value);
assert(value == std::string(500, 'a' + (i % 26)));
}
+7 -1
View File
@@ -93,6 +93,8 @@ class HdfsEnv : public Env {
virtual Status RenameFile(const std::string& src, const std::string& target);
virtual Status LinkFile(const std::string& src, const std::string& target);
virtual Status LockFile(const std::string& fname, FileLock** lock);
virtual Status UnlockFile(FileLock* lock);
@@ -236,7 +238,7 @@ class HdfsEnv : public Env {
explicit HdfsEnv(const std::string& fsname) {
fprintf(stderr, "You have not build rocksdb with HDFS support\n");
fprintf(stderr, "Please see hdfs/README for details\n");
throw std::exception();
abort();
}
virtual ~HdfsEnv() {
@@ -291,6 +293,10 @@ class HdfsEnv : public Env {
virtual Status RenameFile(const std::string& src, const std::string& target){return notsup;}
virtual Status LinkFile(const std::string& src, const std::string& target) {
return notsup;
}
virtual Status LockFile(const std::string& fname, FileLock** lock){return notsup;}
virtual Status UnlockFile(FileLock* lock){return notsup;}
+22
View File
@@ -77,6 +77,8 @@ typedef struct rocksdb_mergeoperator_t rocksdb_mergeoperator_t;
typedef struct rocksdb_options_t rocksdb_options_t;
typedef struct rocksdb_block_based_table_options_t
rocksdb_block_based_table_options_t;
typedef struct rocksdb_cuckoo_table_options_t
rocksdb_cuckoo_table_options_t;
typedef struct rocksdb_randomfile_t rocksdb_randomfile_t;
typedef struct rocksdb_readoptions_t rocksdb_readoptions_t;
typedef struct rocksdb_seqfile_t rocksdb_seqfile_t;
@@ -376,6 +378,25 @@ extern void rocksdb_block_based_options_set_whole_key_filtering(
extern void rocksdb_options_set_block_based_table_factory(
rocksdb_options_t *opt, rocksdb_block_based_table_options_t* table_options);
/* Cuckoo table options */
extern rocksdb_cuckoo_table_options_t*
rocksdb_cuckoo_options_create();
extern void rocksdb_cuckoo_options_destroy(
rocksdb_cuckoo_table_options_t* options);
extern void rocksdb_cuckoo_options_set_hash_ratio(
rocksdb_cuckoo_table_options_t* options, double v);
extern void rocksdb_cuckoo_options_set_max_search_depth(
rocksdb_cuckoo_table_options_t* options, uint32_t v);
extern void rocksdb_cuckoo_options_set_cuckoo_block_size(
rocksdb_cuckoo_table_options_t* options, uint32_t v);
extern void rocksdb_cuckoo_options_set_identity_as_first_hash(
rocksdb_cuckoo_table_options_t* options, unsigned char v);
extern void rocksdb_cuckoo_options_set_use_module_hash(
rocksdb_cuckoo_table_options_t* options, unsigned char v);
extern void rocksdb_options_set_cuckoo_table_factory(
rocksdb_options_t *opt, rocksdb_cuckoo_table_options_t* table_options);
/* Options */
extern rocksdb_options_t* rocksdb_options_create();
@@ -419,6 +440,7 @@ extern void rocksdb_options_set_info_log(rocksdb_options_t*, rocksdb_logger_t*);
extern void rocksdb_options_set_info_log_level(rocksdb_options_t*, int);
extern void rocksdb_options_set_write_buffer_size(rocksdb_options_t*, size_t);
extern void rocksdb_options_set_max_open_files(rocksdb_options_t*, int);
extern void rocksdb_options_set_max_total_wal_size(rocksdb_options_t* opt, uint64_t n);
extern void rocksdb_options_set_compression_options(
rocksdb_options_t*, int, int, int);
extern void rocksdb_options_set_prefix_extractor(
+13
View File
@@ -22,6 +22,7 @@
#include "rocksdb/types.h"
#include "rocksdb/transaction_log.h"
#include "rocksdb/listener.h"
#include "rocksdb/thread_status.h"
namespace rocksdb {
@@ -100,6 +101,9 @@ class DB {
// that modify data, like put/delete, will return error.
// If the db is opened in read only mode, then no compactions
// will happen.
//
// Not supported in ROCKSDB_LITE, in which case the function will
// return Status::NotSupported.
static Status OpenForReadOnly(const Options& options,
const std::string& name, DB** dbptr,
bool error_if_log_file_exist = false);
@@ -109,6 +113,9 @@ class DB {
// database that should be opened. However, you always need to specify default
// column family. The default column family name is 'default' and it's stored
// in rocksdb::kDefaultColumnFamilyName
//
// Not supported in ROCKSDB_LITE, in which case the function will
// return Status::NotSupported.
static Status OpenForReadOnly(
const DBOptions& db_options, const std::string& name,
const std::vector<ColumnFamilyDescriptor>& column_families,
@@ -541,6 +548,12 @@ Status DestroyDB(const std::string& name, const Options& options);
Status RepairDB(const std::string& dbname, const Options& options);
#endif
#if ROCKSDB_USING_THREAD_STATUS
// Obtain the status of all rocksdb-related threads.
Status GetThreadList(std::vector<ThreadStatus>* thread_list);
#endif
} // namespace rocksdb
#endif // STORAGE_ROCKSDB_INCLUDE_DB_H_
+10
View File
@@ -178,6 +178,11 @@ class Env {
virtual Status RenameFile(const std::string& src,
const std::string& target) = 0;
// Hard Link file src to target.
virtual Status LinkFile(const std::string& src, const std::string& target) {
return Status::NotSupported("LinkFile is not supported for this Env");
}
// Lock the specified file. Used to prevent concurrent access to
// the same db by multiple processes. On failure, stores nullptr in
// *lock and returns non-OK.
@@ -747,6 +752,11 @@ class EnvWrapper : public Env {
Status RenameFile(const std::string& s, const std::string& t) {
return target_->RenameFile(s, t);
}
Status LinkFile(const std::string& s, const std::string& t) {
return target_->LinkFile(s, t);
}
Status LockFile(const std::string& f, FileLock** l) {
return target_->LockFile(f, l);
}
+13 -9
View File
@@ -14,8 +14,8 @@
// (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.
// The factory will be passed an MemTableAllocator object when a new MemTableRep
// is requested.
//
// Users can implement their own memtable representations. We include three
// types built in:
@@ -41,6 +41,7 @@
namespace rocksdb {
class Arena;
class MemTableAllocator;
class LookupKey;
class Slice;
class SliceTransform;
@@ -65,7 +66,7 @@ class MemTableRep {
virtual ~KeyComparator() { }
};
explicit MemTableRep(Arena* arena) : arena_(arena) {}
explicit MemTableRep(MemTableAllocator* allocator) : allocator_(allocator) {}
// Allocate a buf of len size for storing key. The idea is that a specific
// memtable representation knows its underlying data structure better. By
@@ -101,7 +102,7 @@ class MemTableRep {
bool (*callback_func)(void* arg, const char* entry));
// Report an approximation of how much memory has been used other than memory
// that was allocated through the arena.
// that was allocated through the allocator.
virtual size_t ApproximateMemoryUsage() = 0;
virtual ~MemTableRep() { }
@@ -150,7 +151,7 @@ class MemTableRep {
// Return an iterator that has a special Seek semantics. The result of
// a Seek might only include keys with the same prefix as the target key.
// arena: If not null, the arena needs to be used to allocate the Iterator.
// arena: If not null, the arena is used to allocate the Iterator.
// When destroying the iterator, the caller will not call "delete"
// but Iterator::~Iterator() directly. The destructor needs to destroy
// all the states but those allocated in arena.
@@ -171,7 +172,7 @@ class MemTableRep {
// user key.
virtual Slice UserKey(const char* key) const;
Arena* arena_;
MemTableAllocator* allocator_;
};
// This is the base class for all factories that are used by RocksDB to create
@@ -180,7 +181,8 @@ class MemTableRepFactory {
public:
virtual ~MemTableRepFactory() {}
virtual MemTableRep* CreateMemTableRep(const MemTableRep::KeyComparator&,
Arena*, const SliceTransform*,
MemTableAllocator*,
const SliceTransform*,
Logger* logger) = 0;
virtual const char* Name() const = 0;
};
@@ -197,7 +199,8 @@ class SkipListFactory : public MemTableRepFactory {
explicit SkipListFactory(size_t lookahead = 0) : lookahead_(lookahead) {}
virtual MemTableRep* CreateMemTableRep(const MemTableRep::KeyComparator&,
Arena*, const SliceTransform*,
MemTableAllocator*,
const SliceTransform*,
Logger* logger) override;
virtual const char* Name() const override { return "SkipListFactory"; }
@@ -220,7 +223,8 @@ class VectorRepFactory : public MemTableRepFactory {
public:
explicit VectorRepFactory(size_t count = 0) : count_(count) { }
virtual MemTableRep* CreateMemTableRep(const MemTableRep::KeyComparator&,
Arena*, const SliceTransform*,
MemTableAllocator*,
const SliceTransform*,
Logger* logger) override;
virtual const char* Name() const override {
return "VectorRepFactory";
+43 -8
View File
@@ -56,11 +56,18 @@ enum CompressionType : char {
};
enum CompactionStyle : char {
kCompactionStyleLevel = 0x0, // level based compaction style
kCompactionStyleUniversal = 0x1, // Universal compaction style
kCompactionStyleFIFO = 0x2, // FIFO compaction style
kCompactionStyleNone = 0x3, // Disable background compaction. Compaction
// jobs are submitted via CompactFiles()
// level based compaction style
kCompactionStyleLevel = 0x0,
// Universal compaction style
// Not supported in ROCKSDB_LITE.
kCompactionStyleUniversal = 0x1,
// FIFO compaction style
// Not supported in ROCKSDB_LITE
kCompactionStyleFIFO = 0x2,
// Disable background compaction. Compaction jobs are submitted
// via CompactFiles().
// Not supported in ROCKSDB_LITE
kCompactionStyleNone = 0x3,
};
struct CompactionOptionsFIFO {
@@ -101,9 +108,10 @@ struct Options;
struct ColumnFamilyOptions {
// Some functions that make it easier to optimize RocksDB
#ifndef ROCKSDB_LITE
// Use this if you don't need to keep the data sorted, i.e. you'll never use
// an iterator, only Put() and Get() API calls
//
// Not supported in ROCKSDB_LITE
ColumnFamilyOptions* OptimizeForPointLookup(
uint64_t block_cache_size_mb);
@@ -121,11 +129,12 @@ struct ColumnFamilyOptions {
// biggest performance gains.
// Note: we might use more memory than memtable_memory_budget during high
// write rate period
//
// OptimizeUniversalStyleCompaction is not supported in ROCKSDB_LITE
ColumnFamilyOptions* OptimizeLevelStyleCompaction(
uint64_t memtable_memory_budget = 512 * 1024 * 1024);
ColumnFamilyOptions* OptimizeUniversalStyleCompaction(
uint64_t memtable_memory_budget = 512 * 1024 * 1024);
#endif // ROCKSDB_LITE
// -------------------
// Parameters that affect behavior
@@ -196,6 +205,9 @@ struct ColumnFamilyOptions {
// Also, a larger write buffer will result in a longer recovery time
// the next time the database is opened.
//
// Note that write_buffer_size is enforced per column family.
// See db_write_buffer_size for sharing memory across column families.
//
// Default: 4MB
//
// Dynamically changeable through SetOptions() API
@@ -310,6 +322,7 @@ struct ColumnFamilyOptions {
//
// Dynamically changeable through SetOptions() API
uint64_t target_file_size_base;
// By default target_file_size_multiplier is 1, which means
// by default files in different levels will have similar size.
//
@@ -329,6 +342,7 @@ struct ColumnFamilyOptions {
//
// Dynamically changeable through SetOptions() API
uint64_t max_bytes_for_level_base;
// Default: 10.
//
// Dynamically changeable through SetOptions() API
@@ -421,7 +435,10 @@ struct ColumnFamilyOptions {
// If true, compaction will verify checksum on every read that happens
// as part of compaction
//
// Default: true
//
// Dynamically changeable through SetOptions() API
bool verify_checksums_in_compaction;
// The options needed to support Universal Style compactions
@@ -669,7 +686,7 @@ struct DBOptions {
// column families whose memtables are backed by the oldest live WAL file
// (i.e. the ones that are causing all the space amplification). If set to 0
// (default), we will dynamically choose the WAL size limit to be
// [sum of all write_buffer_size * max_write_buffer_number] * 2
// [sum of all write_buffer_size * max_write_buffer_number] * 4
// Default: 0
uint64_t max_total_wal_size;
@@ -847,6 +864,18 @@ struct DBOptions {
// Default: true
bool advise_random_on_open;
// Amount of data to build up in memtables across all column
// families before writing to disk.
//
// This is distinct from write_buffer_size, which enforces a limit
// for a single memtable.
//
// This feature is disabled by default. Specify a non-zero value
// to enable it.
//
// Default: 0 (disabled)
size_t db_write_buffer_size;
// Specify the file access pattern once a compaction is started.
// It will be applied to all input files of a compaction.
// Default: NORMAL
@@ -881,6 +910,12 @@ struct DBOptions {
// When rate limiter is enabled, it automatically enables bytes_per_sync
// to 1MB.
uint64_t bytes_per_sync;
// If true, then the status of the threads involved in this DB will
// be tracked and available via GetThreadList() API.
//
// Default: false
bool enable_thread_tracking;
};
// Options to control the behavior of a database (passed to DB::Open)
+3 -2
View File
@@ -369,13 +369,14 @@ class TableFactory {
};
#ifndef ROCKSDB_LITE
// Create a special table factory that can open both of block based table format
// and plain table, based on setting inside the SST files. It should be used to
// Create a special table factory that can open either of the supported
// table formats, based on setting inside the SST files. It should be used to
// convert a DB from one table format to another.
// @table_factory_to_write: the table factory used when writing to new files.
// @block_based_table_factory: block based table factory to use. If NULL, use
// a default one.
// @plain_table_factory: plain table factory to use. If NULL, use a default one.
// @cuckoo_table_factory: cuckoo table factory to use. If NULL, use a default one.
extern TableFactory* NewAdaptiveTableFactory(
std::shared_ptr<TableFactory> table_factory_to_write = nullptr,
std::shared_ptr<TableFactory> block_based_table_factory = nullptr,
+67
View File
@@ -0,0 +1,67 @@
// Copyright (c) 2014, 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 <cstddef>
#include <string>
#ifndef ROCKSDB_USING_THREAD_STATUS
#define ROCKSDB_USING_THREAD_STATUS \
!defined(ROCKSDB_LITE) && \
!defined(NROCKSDB_THREAD_STATUS) && \
!defined(OS_MACOSX) && \
!defined(IOS_CROSS_COMPILE)
#endif
namespace rocksdb {
// A structure that describes the current status of a thread.
// The status of active threads can be fetched using
// rocksdb::GetThreadList().
struct ThreadStatus {
enum ThreadType {
ROCKSDB_HIGH_PRIORITY = 0x0,
ROCKSDB_LOW_PRIORITY = 0x1,
USER_THREAD = 0x2,
TOTAL = 0x3
};
#if ROCKSDB_USING_THREAD_STATUS
ThreadStatus(const uint64_t _id,
const ThreadType _thread_type,
const std::string& _db_name,
const std::string& _cf_name,
const std::string& _event) :
thread_id(_id), thread_type(_thread_type),
db_name(_db_name),
cf_name(_cf_name),
event(_event) {}
// An unique ID for the thread.
const uint64_t thread_id;
// The type of the thread, it could be ROCKSDB_HIGH_PRIORITY,
// ROCKSDB_LOW_PRIORITY, and USER_THREAD
const ThreadType thread_type;
// The name of the DB instance where the thread is currently
// involved with. It would be set to empty string if the thread
// does not involve in any DB operation.
const std::string db_name;
// The name of the column family where the thread is currently
// It would be set to empty string if the thread does not involve
// in any column family.
const std::string cf_name;
// The event that the current thread is involved.
// It would be set to empty string if the information about event
// is not currently available.
const std::string event;
#endif // ROCKSDB_USING_THREAD_STATUS
};
} // namespace rocksdb
+34
View File
@@ -0,0 +1,34 @@
// 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.
//
// A checkpoint is an openable snapshot of a database at a point in time.
#pragma once
#include <string>
#include "rocksdb/status.h"
namespace rocksdb {
class DB;
class Checkpoint {
public:
// Creates a Checkpoint object to be used for creating openable sbapshots
static Status Create(DB* db, Checkpoint** checkpoint_ptr);
// Builds an openable snapshot of RocksDB on the same disk, which
// accepts an output directory on the same disk, and under the directory
// (1) hard-linked SST files pointing to existing live SST files
// SST files will be copied if output directory is on a different filesystem
// (2) a copied manifest files and other files
// The directory should not already exist and will be created by this API.
// The directory will be an absolute path
virtual Status CreateCheckpoint(const std::string& checkpoint_dir);
virtual ~Checkpoint() {}
};
} // namespace rocksdb
+144
View File
@@ -0,0 +1,144 @@
// Copyright (c) 2014, 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 <stddef.h>
namespace rocksdb {
class Cache;
class Comparator;
class Env;
class FilterPolicy;
class Logger;
struct Options;
class Snapshot;
enum CompressionType : char;
// Options to control the behavior of a database (passed to
// DB::Open). A LevelDBOptions object can be initialized as though
// it were a LevelDB Options object, and then it can be converted into
// a RocksDB Options object.
struct LevelDBOptions {
// -------------------
// Parameters that affect behavior
// Comparator used to define the order of keys in the table.
// Default: a comparator that uses lexicographic byte-wise ordering
//
// REQUIRES: The client must ensure that the comparator supplied
// here has the same name and orders keys *exactly* the same as the
// comparator provided to previous open calls on the same DB.
const Comparator* comparator;
// If true, the database will be created if it is missing.
// Default: false
bool create_if_missing;
// If true, an error is raised if the database already exists.
// Default: false
bool error_if_exists;
// If true, the implementation will do aggressive checking of the
// data it is processing and will stop early if it detects any
// errors. This may have unforeseen ramifications: for example, a
// corruption of one DB entry may cause a large number of entries to
// become unreadable or for the entire DB to become unopenable.
// Default: false
bool paranoid_checks;
// Use the specified object to interact with the environment,
// e.g. to read/write files, schedule background work, etc.
// Default: Env::Default()
Env* env;
// Any internal progress/error information generated by the db will
// be written to info_log if it is non-NULL, or to a file stored
// in the same directory as the DB contents if info_log is NULL.
// Default: NULL
Logger* info_log;
// -------------------
// Parameters that affect performance
// Amount of data to build up in memory (backed by an unsorted log
// on disk) before converting to a sorted on-disk file.
//
// Larger values increase performance, especially during bulk loads.
// Up to two write buffers may be held in memory at the same time,
// so you may wish to adjust this parameter to control memory usage.
// Also, a larger write buffer will result in a longer recovery time
// the next time the database is opened.
//
// Default: 4MB
size_t write_buffer_size;
// Number of open files that can be used by the DB. You may need to
// increase this if your database has a large working set (budget
// one open file per 2MB of working set).
//
// Default: 1000
int max_open_files;
// Control over blocks (user data is stored in a set of blocks, and
// 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.
// Default: NULL
Cache* block_cache;
// Approximate size of user data packed per block. Note that the
// block size specified here corresponds to uncompressed data. The
// actual size of the unit read from disk may be smaller if
// compression is enabled. This parameter can be changed dynamically.
//
// Default: 4K
size_t block_size;
// Number of keys between restart points for delta encoding of keys.
// This parameter can be changed dynamically. Most clients should
// leave this parameter alone.
//
// Default: 16
int block_restart_interval;
// Compress blocks using the specified compression algorithm. This
// parameter can be changed dynamically.
//
// Default: kSnappyCompression, which gives lightweight but fast
// compression.
//
// Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:
// ~200-500MB/s compression
// ~400-800MB/s decompression
// Note that these speeds are significantly faster than most
// persistent storage speeds, and therefore it is typically never
// worth switching to kNoCompression. Even if the input data is
// incompressible, the kSnappyCompression implementation will
// efficiently detect that and will switch to uncompressed mode.
CompressionType compression;
// If non-NULL, use the specified filter policy to reduce disk reads.
// Many applications will benefit from passing the result of
// NewBloomFilterPolicy() here.
//
// Default: NULL
const FilterPolicy* filter_policy;
// Create a LevelDBOptions object with default values for all fields.
LevelDBOptions();
};
// Converts a LevelDBOptions object into a RocksDB Options object.
Options ConvertOptions(const LevelDBOptions& leveldb_options);
} // namespace rocksdb
+1 -1
View File
@@ -5,7 +5,7 @@
#pragma once
#define ROCKSDB_MAJOR 3
#define ROCKSDB_MINOR 8
#define ROCKSDB_MINOR 9
#define ROCKSDB_PATCH 0
// Do not use these. We made the mistake of declaring macros starting with
+7 -4
View File
@@ -105,10 +105,11 @@ class WriteBatch {
return Status::InvalidArgument(
"non-default column family and PutCF not implemented");
}
virtual void Put(const Slice& key, const Slice& value);
virtual void Put(const Slice& key, const Slice& value) {}
// Merge and LogData are not pure virtual. Otherwise, we would break
// existing clients of Handler on a source code level. The default
// implementation of Merge simply throws a runtime exception.
// implementation of Merge does nothing.
virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
const Slice& value) {
if (column_family_id == 0) {
@@ -118,7 +119,8 @@ class WriteBatch {
return Status::InvalidArgument(
"non-default column family and MergeCF not implemented");
}
virtual void Merge(const Slice& key, const Slice& value);
virtual void Merge(const Slice& key, const Slice& value) {}
// The default implementation of LogData does nothing.
virtual void LogData(const Slice& blob);
virtual Status DeleteCF(uint32_t column_family_id, const Slice& key) {
@@ -129,7 +131,8 @@ class WriteBatch {
return Status::InvalidArgument(
"non-default column family and DeleteCF not implemented");
}
virtual void Delete(const Slice& key);
virtual void Delete(const Slice& key) {}
// Continue is called by WriteBatch::Iterate. If it returns false,
// iteration is halted. Otherwise, it continues iterating. The default
// implementation always returns true.
+65 -34
View File
@@ -4,6 +4,7 @@ NATIVE_JAVA_CLASSES = org.rocksdb.AbstractComparator\
org.rocksdb.BackupableDBOptions\
org.rocksdb.BlockBasedTableConfig\
org.rocksdb.BloomFilter\
org.rocksdb.Checkpoint\
org.rocksdb.ColumnFamilyHandle\
org.rocksdb.ColumnFamilyOptions\
org.rocksdb.Comparator\
@@ -32,9 +33,9 @@ NATIVE_JAVA_CLASSES = org.rocksdb.AbstractComparator\
org.rocksdb.StringAppendOperator\
org.rocksdb.WriteBatch\
org.rocksdb.WriteBatch.Handler\
org.rocksdb.WriteBatchInternal\
org.rocksdb.WriteBatchTest\
org.rocksdb.WriteOptions\
org.rocksdb.test.WriteBatchInternal\
org.rocksdb.test.WriteBatchTest\
org.rocksdb.WriteOptions\
ROCKSDB_MAJOR = $(shell egrep "ROCKSDB_MAJOR.[0-9]" ../include/rocksdb/version.h | cut -d ' ' -f 3)
ROCKSDB_MINOR = $(shell egrep "ROCKSDB_MINOR.[0-9]" ../include/rocksdb/version.h | cut -d ' ' -f 3)
@@ -43,21 +44,68 @@ ROCKSDB_PATCH = $(shell egrep "ROCKSDB_PATCH.[0-9]" ../include/rocksdb/version.h
NATIVE_INCLUDE = ./include
ARCH := $(shell getconf LONG_BIT)
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-linux$(ARCH).jar
ifeq ($(PLATFORM), OS_MACOSX)
ROCKSDB_JAR = rocksdbjni-$(ROCKSDB_MAJOR).$(ROCKSDB_MINOR).$(ROCKSDB_PATCH)-osx.jar
endif
JAVA_TESTS = org.rocksdb.test.BackupableDBOptionsTest\
org.rocksdb.test.BackupableDBTest\
org.rocksdb.test.BlockBasedTableConfigTest\
org.rocksdb.test.CheckPointTest\
org.rocksdb.test.ColumnFamilyOptionsTest\
org.rocksdb.test.ColumnFamilyTest\
org.rocksdb.test.ComparatorOptionsTest\
org.rocksdb.test.ComparatorTest\
org.rocksdb.test.DBOptionsTest\
org.rocksdb.test.DirectComparatorTest\
org.rocksdb.test.EnvironmentTest\
org.rocksdb.test.FilterTest\
org.rocksdb.test.FlushTest\
org.rocksdb.test.InfoLogLevelTest\
org.rocksdb.test.KeyMayExistTest\
org.rocksdb.test.MemTableTest\
org.rocksdb.test.MergeTest\
org.rocksdb.test.MixedOptionsTest\
org.rocksdb.test.OptionsTest\
org.rocksdb.test.PlainTableConfigTest\
org.rocksdb.test.ReadOnlyTest\
org.rocksdb.test.ReadOptionsTest\
org.rocksdb.test.RocksDBTest\
org.rocksdb.test.RocksEnvTest\
org.rocksdb.test.RocksIteratorTest\
org.rocksdb.test.SizeUnitTest\
org.rocksdb.test.SnapshotTest\
org.rocksdb.test.StatisticsCollectorTest\
org.rocksdb.test.WriteBatchHandlerTest\
org.rocksdb.test.WriteBatchTest\
org.rocksdb.test.WriteOptionsTest\
JAVA_TEST_LIBDIR = ./test-libs/
JAVA_JUNIT_JAR = $(JAVA_TEST_LIBDIR)junit-4.12-beta-2.jar
JAVA_HAMCR_JAR = $(JAVA_TEST_LIBDIR)hamcrest-core-1.3.jar
JAVA_MOCKITO_JAR = $(JAVA_TEST_LIBDIR)mockito-all-1.9.5.jar
JAVA_CGLIB_JAR = $(JAVA_TEST_LIBDIR)cglib-2.2.2.jar
JAVA_ASSERTJ_JAR = $(JAVA_TEST_LIBDIR)assertj-core-1.7.0.jar
JAVA_TESTCLASSPATH = $(ROCKSDB_JAR):$(JAVA_JUNIT_JAR):$(JAVA_HAMCR_JAR):$(JAVA_MOCKITO_JAR):$(JAVA_CGLIB_JAR):$(JAVA_ASSERTJ_JAR):.:./*
clean:
-find . -name "*.class" -exec rm {} \;
-find . -name "hs*.log" -exec rm {} \;
rm -rf include/*
rm -rf javadoc/*
rm -rf test-libs/
rm -rf target
rm -rf librocksdbjni*
rm -f rocksdbjni*
javadocs:
mkdir -p javadoc; javadoc -d javadoc -sourcepath . -subpackages org
mkdir -p javadoc; javadoc -d javadoc -sourcepath . -subpackages org -exclude org.rocksdb.test
java: javadocs
javalib: java javadocs
java: resolve_test_deps
javac org/rocksdb/util/*.java org/rocksdb/*.java
javac -cp $(JAVA_TESTCLASSPATH) org/rocksdb/test/*.java
@cp ../HISTORY.md ./HISTORY-CPP.md
@rm -f ./HISTORY-CPP.md
javah -d $(NATIVE_INCLUDE) -jni $(NATIVE_JAVA_CLASSES)
@@ -76,33 +124,16 @@ column_family_sample: java
java -ea -Djava.library.path=.:../ -cp ".:./*" -Xcheck:jni RocksDBColumnFamilySample /tmp/rocksdbjni
@rm -rf /tmp/rocksdbjni
test: java
@rm -rf /tmp/rocksdbjni_*
javac org/rocksdb/test/*.java
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.WriteBatchTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.BackupableDBTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.BlockBasedTableConfigTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.DBOptionsTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.ColumnFamilyTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.ColumnFamilyOptionsTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.FilterTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.FlushTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.KeyMayExistTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.MemTableTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.MergeTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.MixedOptionsTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.OptionsTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.PlainTableConfigTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.ReadOnlyTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.ReadOptionsTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.RocksIteratorTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.SnapshotTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.StatisticsCollectorTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.ComparatorOptionsTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.ComparatorTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.DirectComparatorTest
java -ea -Djava.library.path=.:../ -cp "$(ROCKSDB_JAR):.:./*" org.rocksdb.test.WriteBatchHandlerTest
@rm -rf /tmp/rocksdbjni_*
resolve_test_deps:
mkdir -p "$(JAVA_TEST_LIBDIR)"
test -s "$(JAVA_JUNIT_JAR)" || curl -k -L -o $(JAVA_JUNIT_JAR) http://search.maven.org/remotecontent?filepath=junit/junit/4.12-beta-2/junit-4.12-beta-2.jar
test -s "$(JAVA_HAMCR_JAR)" || curl -k -L -o $(JAVA_HAMCR_JAR) http://search.maven.org/remotecontent?filepath=org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
test -s "$(JAVA_MOCKITO_JAR)" || curl -k -L -o "$(JAVA_MOCKITO_JAR)" http://search.maven.org/remotecontent?filepath=org/mockito/mockito-all/1.9.5/mockito-all-1.9.5.jar
test -s "$(JAVA_CGLIB_JAR)" || curl -k -L -o "$(JAVA_CGLIB_JAR)" http://search.maven.org/remotecontent?filepath=cglib/cglib/2.2.2/cglib-2.2.2.jar
test -s "$(JAVA_ASSERTJ_JAR)" || curl -k -L -o "$(JAVA_ASSERTJ_JAR)" http://central.maven.org/maven2/org/assertj/assertj-core/1.7.0/assertj-core-1.7.0.jar
test: java resolve_test_deps
java -ea -Xcheck:jni -Djava.library.path=.:../ -cp "$(JAVA_TESTCLASSPATH)" org.rocksdb.test.RocksJunitRunner $(JAVA_TESTS)
db_bench: java
javac org/rocksdb/benchmark/*.java
+3
View File
@@ -44,6 +44,9 @@ public class RocksDBColumnFamilySample {
db.close();
db = null;
}
if (options != null) {
options.dispose();
}
}
// open DB with two column families
+1 -1
View File
@@ -119,7 +119,7 @@ public class RocksDBSample {
byte[] value = db.get("hello".getBytes());
assert("world".equals(new String(value)));
String str = db.getProperty("rocksdb.stats");
assert(str != null && str != "");
assert(str != null && !str.equals(""));
} catch (RocksDBException e) {
System.out.format("[ERROR] caught the unexpceted exception -- %s\n", e);
assert(db == null);
+53 -16
View File
@@ -8,21 +8,23 @@ package org.rocksdb;
import java.util.List;
/**
* A subclass of RocksDB which supports backup-related operations.
* <p>A subclass of RocksDB which supports
* backup-related operations.</p>
*
* @see org.rocksdb.BackupableDBOptions
*/
public class BackupableDB extends RocksDB {
/**
* Open a {@code BackupableDB} under the specified path.
* <p>Open a {@code BackupableDB} under the specified path.
* Note that the backup path should be set properly in the
* input BackupableDBOptions.
* input BackupableDBOptions.</p>
*
* @param opt {@link org.rocksdb.Options} to set for the database.
* @param bopt {@link org.rocksdb.BackupableDBOptions} to use.
* @param db_path Path to store data to. The path for storing the backup should be
* specified in the {@link org.rocksdb.BackupableDBOptions}.
* @return BackupableDB reference to the opened database.
*
* @return {@link BackupableDB} reference to the opened database.
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
@@ -43,8 +45,8 @@ public class BackupableDB extends RocksDB {
}
/**
* Captures the state of the database in the latest backup.
* Note that this function is not thread-safe.
* <p>Captures the state of the database in the latest backup.
* Note that this function is not thread-safe.</p>
*
* @param flushBeforeBackup if true, then all data will be flushed
* before creating backup.
@@ -54,11 +56,12 @@ public class BackupableDB extends RocksDB {
*/
public void createNewBackup(boolean flushBeforeBackup)
throws RocksDBException {
assert(isInitialized());
createNewBackup(nativeHandle_, flushBeforeBackup);
}
/**
* Deletes old backups, keeping latest numBackupsToKeep alive.
* <p>Deletes old backups, keeping latest numBackupsToKeep alive.</p>
*
* @param numBackupsToKeep Number of latest backups to keep.
*
@@ -67,11 +70,12 @@ public class BackupableDB extends RocksDB {
*/
public void purgeOldBackups(int numBackupsToKeep)
throws RocksDBException {
assert(isInitialized());
purgeOldBackups(nativeHandle_, numBackupsToKeep);
}
/**
* Deletes a specific backup.
* <p>Deletes a specific backup.</p>
*
* @param backupId of backup to delete.
*
@@ -79,25 +83,54 @@ public class BackupableDB extends RocksDB {
* native library.
*/
public void deleteBackup(int backupId) throws RocksDBException {
assert(isInitialized());
deleteBackup0(nativeHandle_, backupId);
}
/**
* Returns a list of {@link BackupInfo} instances, which describe
* already made backups.
* <p>Returns a list of {@link BackupInfo} instances, which describe
* already made backups.</p>
*
* @return List of {@link BackupInfo} instances.
*/
public List<BackupInfo> getBackupInfos() {
assert(isInitialized());
return getBackupInfo(nativeHandle_);
}
/**
* Close the BackupableDB instance and release resource.
* <p>Returns a list of corrupted backup ids. If there
* is no corrupted backup the method will return an
* empty list.</p>
*
* Internally, BackupableDB owns the {@code rocksdb::DB} pointer to its associated
* {@link org.rocksdb.RocksDB}. The release of that RocksDB pointer is handled in the destructor
* of the c++ {@code rocksdb::BackupableDB} and should be transparent to Java developers.
* @return array of backup ids as int ids.
*/
public int[] getCorruptedBackups() {
assert(isInitialized());
return getCorruptedBackups(nativeHandle_);
}
/**
* <p>Will delete all the files we don't need anymore. It will
* do the full scan of the files/ directory and delete all the
* files that are not referenced.</p>
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public void garbageCollect() throws RocksDBException {
assert(isInitialized());
garbageCollect(nativeHandle_);
}
/**
* <p>Close the BackupableDB instance and release resource.</p>
*
* <p>Internally, {@link BackupableDB} owns the {@code rocksdb::DB}
* pointer to its associated {@link org.rocksdb.RocksDB}.
* The release of that RocksDB pointer is handled in the destructor
* of the c++ {@code rocksdb::BackupableDB} and should be transparent
* to Java developers.</p>
*/
@Override public synchronized void close() {
if (isInitialized()) {
@@ -106,8 +139,9 @@ public class BackupableDB extends RocksDB {
}
/**
* A protected construction that will be used in the static factory
* method {@link #open(Options, BackupableDBOptions, String)}.
* <p>A protected construction that will be used in the static
* factory method {@link #open(Options, BackupableDBOptions, String)}.
* </p>
*/
protected BackupableDB() {
super();
@@ -126,4 +160,7 @@ public class BackupableDB extends RocksDB {
private native void deleteBackup0(long nativeHandle, int backupId)
throws RocksDBException;
protected native List<BackupInfo> getBackupInfo(long handle);
private native int[] getCorruptedBackups(long handle);
private native void garbageCollect(long handle)
throws RocksDBException;
}
+230 -40
View File
@@ -5,57 +5,38 @@
package org.rocksdb;
import java.io.File;
import java.nio.file.Path;
/**
* BackupableDBOptions to control the behavior of a backupable database.
* <p>BackupableDBOptions to control the behavior of a backupable database.
* It will be used during the creation of a {@link org.rocksdb.BackupableDB}.
*
* Note that dispose() must be called before an Options instance
* become out-of-scope to release the allocated memory in c++.
* </p>
* <p>Note that dispose() must be called before an Options instance
* become out-of-scope to release the allocated memory in c++.</p>
*
* @see org.rocksdb.BackupableDB
*/
public class BackupableDBOptions extends RocksObject {
/**
* BackupableDBOptions constructor
* <p>BackupableDBOptions constructor.</p>
*
* @param path Where to keep the backup files. Has to be different than db name.
* Best to set this to {@code db name_ + "/backups"}
* @param shareTableFiles If {@code share_table_files == true}, backup will assume
* that table files with same name have the same contents. This enables incremental
* backups and avoids unnecessary data copies. If {@code share_table_files == false},
* each backup will be on its own and will not share any data with other backups.
* Default: true
* @param sync If {@code sync == true}, we can guarantee you'll get consistent backup
* even on a machine crash/reboot. Backup process is slower with sync enabled.
* If {@code sync == false}, we don't guarantee anything on machine reboot.
* However,chances are some of the backups are consistent.
* Default: true
* @param destroyOldData If true, it will delete whatever backups there are already.
* Default: false
* @param backupLogFiles If false, we won't backup log files. This option can be
* useful for backing up in-memory databases where log file are persisted,but table
* files are in memory.
* Default: true
* @param backupRateLimit Max bytes that can be transferred in a second during backup.
* If 0 or negative, then go as fast as you can. Default: 0
* @param restoreRateLimit Max bytes that can be transferred in a second during restore.
* If 0 or negative, then go as fast as you can. Default: 0
* Best to set this to {@code db name_ + "/backups"}
* @throws java.lang.IllegalArgumentException if illegal path is used.
*/
public BackupableDBOptions(String path, boolean shareTableFiles, boolean sync,
boolean destroyOldData, boolean backupLogFiles, long backupRateLimit,
long restoreRateLimit) {
public BackupableDBOptions(String path) {
super();
backupRateLimit = (backupRateLimit <= 0) ? 0 : backupRateLimit;
restoreRateLimit = (restoreRateLimit <= 0) ? 0 : restoreRateLimit;
newBackupableDBOptions(path, shareTableFiles, sync, destroyOldData,
backupLogFiles, backupRateLimit, restoreRateLimit);
File backupPath = path == null ? null : new File(path);
if (backupPath == null || !backupPath.isDirectory() || !backupPath.canWrite()) {
throw new IllegalArgumentException("Illegal path provided.");
}
newBackupableDBOptions(path);
}
/**
* Returns the path to the BackupableDB directory.
* <p>Returns the path to the BackupableDB directory.</p>
*
* @return the path to the BackupableDB directory.
*/
@@ -64,18 +45,227 @@ public class BackupableDBOptions extends RocksObject {
return backupDir(nativeHandle_);
}
/**
* <p>Share table files between backups.</p>
*
* @param shareTableFiles If {@code share_table_files == true}, backup will assume
* that table files with same name have the same contents. This enables incremental
* backups and avoids unnecessary data copies. If {@code share_table_files == false},
* each backup will be on its own and will not share any data with other backups.
*
* <p>Default: true</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setShareTableFiles(boolean shareTableFiles) {
assert(isInitialized());
setShareTableFiles(nativeHandle_, shareTableFiles);
return this;
}
/**
* <p>Share table files between backups.</p>
*
* @return boolean value indicating if SST files will be shared between
* backups.
*/
public boolean shareTableFiles() {
assert(isInitialized());
return shareTableFiles(nativeHandle_);
}
/**
* <p>Set synchronous backups.</p>
*
* @param sync If {@code sync == true}, we can guarantee you'll get consistent backup
* even on a machine crash/reboot. Backup process is slower with sync enabled.
* If {@code sync == false}, we don't guarantee anything on machine reboot.
* However,chances are some of the backups are consistent.
*
* <p>Default: true</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setSync(boolean sync) {
assert(isInitialized());
setSync(nativeHandle_, sync);
return this;
}
/**
* <p>Are synchronous backups activated.</p>
*
* @return boolean value if synchronous backups are configured.
*/
public boolean sync() {
assert(isInitialized());
return sync(nativeHandle_);
}
/**
* <p>Set if old data will be destroyed.</p>
*
* @param destroyOldData If true, it will delete whatever backups there are already.
*
* <p>Default: false</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setDestroyOldData(boolean destroyOldData) {
assert(isInitialized());
setDestroyOldData(nativeHandle_, destroyOldData);
return this;
}
/**
* <p>Returns if old data will be destroyed will performing new backups.</p>
*
* @return boolean value indicating if old data will be destroyed.
*/
public boolean destroyOldData() {
assert(isInitialized());
return destroyOldData(nativeHandle_);
}
/**
* <p>Set if log files shall be persisted.</p>
*
* @param backupLogFiles If false, we won't backup log files. This option can be
* useful for backing up in-memory databases where log file are persisted,but table
* files are in memory.
*
* <p>Default: true</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setBackupLogFiles(boolean backupLogFiles) {
assert(isInitialized());
setBackupLogFiles(nativeHandle_, backupLogFiles);
return this;
}
/**
* <p>Return information if log files shall be persisted.</p>
*
* @return boolean value indicating if log files will be persisted.
*/
public boolean backupLogFiles() {
assert(isInitialized());
return backupLogFiles(nativeHandle_);
}
/**
* <p>Set backup rate limit.</p>
*
* @param backupRateLimit Max bytes that can be transferred in a second during backup.
* If 0 or negative, then go as fast as you can.
*
* <p>Default: 0</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setBackupRateLimit(long backupRateLimit) {
assert(isInitialized());
backupRateLimit = (backupRateLimit <= 0) ? 0 : backupRateLimit;
setBackupRateLimit(nativeHandle_, backupRateLimit);
return this;
}
/**
* <p>Return backup rate limit which described the max bytes that can be transferred in a
* second during backup.</p>
*
* @return numerical value describing the backup transfer limit in bytes per second.
*/
public long backupRateLimit() {
assert(isInitialized());
return backupRateLimit(nativeHandle_);
}
/**
* <p>Set restore rate limit.</p>
*
* @param restoreRateLimit Max bytes that can be transferred in a second during restore.
* If 0 or negative, then go as fast as you can.
*
* <p>Default: 0</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setRestoreRateLimit(long restoreRateLimit) {
assert(isInitialized());
restoreRateLimit = (restoreRateLimit <= 0) ? 0 : restoreRateLimit;
setRestoreRateLimit(nativeHandle_, restoreRateLimit);
return this;
}
/**
* <p>Return restore rate limit which described the max bytes that can be transferred in a
* second during restore.</p>
*
* @return numerical value describing the restore transfer limit in bytes per second.
*/
public long restoreRateLimit() {
assert(isInitialized());
return restoreRateLimit(nativeHandle_);
}
/**
* <p>Only used if share_table_files is set to true. If true, will consider that
* backups can come from different databases, hence a sst is not uniquely
* identified by its name, but by the triple (file name, crc32, file length)</p>
*
* @param shareFilesWithChecksum boolean value indicating if SST files are stored
* using the triple (file name, crc32, file length) and not its name.
*
* <p>Note: this is an experimental option, and you'll need to set it manually
* turn it on only if you know what you're doing*</p>
*
* <p>Default: false</p>
*
* @return instance of current BackupableDBOptions.
*/
public BackupableDBOptions setShareFilesWithChecksum(
boolean shareFilesWithChecksum) {
assert(isInitialized());
setShareFilesWithChecksum(nativeHandle_, shareFilesWithChecksum);
return this;
}
/**
* <p>Return of share files with checksum is active.</p>
*
* @return boolean value indicating if share files with checksum
* is active.
*/
public boolean shareFilesWithChecksum() {
assert(isInitialized());
return shareFilesWithChecksum(nativeHandle_);
}
/**
* Release the memory allocated for the current instance
* in the c++ side.
*/
@Override protected void disposeInternal() {
assert(isInitialized());
disposeInternal(nativeHandle_);
}
private native void newBackupableDBOptions(String path,
boolean shareTableFiles, boolean sync, boolean destroyOldData,
boolean backupLogFiles, long backupRateLimit, long restoreRateLimit);
private native void newBackupableDBOptions(String path);
private native String backupDir(long handle);
private native void setShareTableFiles(long handle, boolean flag);
private native boolean shareTableFiles(long handle);
private native void setSync(long handle, boolean flag);
private native boolean sync(long handle);
private native void setDestroyOldData(long handle, boolean flag);
private native boolean destroyOldData(long handle);
private native void setBackupLogFiles(long handle, boolean flag);
private native boolean backupLogFiles(long handle);
private native void setBackupRateLimit(long handle, long rateLimit);
private native long backupRateLimit(long handle);
private native void setRestoreRateLimit(long handle, long rateLimit);
private native long restoreRateLimit(long handle);
private native void setShareFilesWithChecksum(long handle, boolean flag);
private native boolean shareFilesWithChecksum(long handle);
private native void disposeInternal(long handle);
}
+72
View File
@@ -0,0 +1,72 @@
// Copyright (c) 2014, 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.
package org.rocksdb;
/**
* Provides Checkpoint functionality. Checkpoints
* provide persistent snapshots of RocksDB databases.
*/
public class Checkpoint extends RocksObject {
/**
* Creates a Checkpoint object to be used for creating open-able
* snapshots.
*
* @param db {@link RocksDB} instance.
* @return a Checkpoint instance.
*
* @throws java.lang.IllegalArgumentException if {@link RocksDB}
* instance is null.
* @throws java.lang.IllegalStateException if {@link RocksDB}
* instance is not initialized.
*/
public static Checkpoint create(RocksDB db) {
if (db == null) {
throw new IllegalArgumentException(
"RocksDB instance shall not be null.");
} else if (!db.isInitialized()) {
throw new IllegalStateException(
"RocksDB instance must be initialized.");
}
Checkpoint checkpoint = new Checkpoint(db);
return checkpoint;
}
/**
* <p>Builds an open-able snapshot of RocksDB on the same disk, which
* accepts an output directory on the same disk, and under the directory
* (1) hard-linked SST files pointing to existing live SST files
* (2) a copied manifest files and other files</p>
*
* @param checkpointPath path to the folder where the snapshot is going
* to be stored.
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
public void createCheckpoint(String checkpointPath)
throws RocksDBException {
createCheckpoint(nativeHandle_, checkpointPath);
}
@Override
protected void disposeInternal() {
disposeInternal(nativeHandle_);
}
private Checkpoint(RocksDB db) {
super();
nativeHandle_ = newCheckpoint(db.nativeHandle_);
db_ = db;
}
RocksDB db_;
private static native long newCheckpoint(long dbHandle);
private native void disposeInternal(long handle);
private native void createCheckpoint(long handle, String checkpointPath)
throws RocksDBException;
}
+6 -4
View File
@@ -30,13 +30,15 @@ public class ColumnFamilyHandle extends RocksObject {
* before freeing the native handle.</p>
*/
@Override protected void disposeInternal() {
assert(isInitialized());
if (rocksDB_.isInitialized()) {
disposeInternal(nativeHandle_);
synchronized (rocksDB_) {
assert (isInitialized());
if (rocksDB_.isInitialized()) {
disposeInternal(nativeHandle_);
}
}
}
private native void disposeInternal(long handle);
private RocksDB rocksDB_;
private final RocksDB rocksDB_;
}
+62
View File
@@ -5,6 +5,8 @@
package org.rocksdb;
import java.util.Properties;
/**
* ColumnFamilyOptions to control the behavior of a database. It will be used
* during the creation of a {@link org.rocksdb.RocksDB} (i.e., RocksDB.open()).
@@ -29,6 +31,47 @@ public class ColumnFamilyOptions extends RocksObject
newColumnFamilyOptions();
}
/**
* <p>Method to get a options instance by using pre-configured
* property values. If one or many values are undefined in
* the context of RocksDB the method will return a null
* value.</p>
*
* <p><strong>Note</strong>: Property keys can be derived from
* getter methods within the options class. Example: the method
* {@code writeBufferSize()} has a property key:
* {@code write_buffer_size}.</p>
*
* @param properties {@link java.util.Properties} instance.
*
* @return {@link org.rocksdb.ColumnFamilyOptions instance}
* or null.
*
* @throws java.lang.IllegalArgumentException if null or empty
* {@link Properties} instance is passed to the method call.
*/
public static ColumnFamilyOptions getColumnFamilyOptionsFromProps(
Properties properties) {
if (properties == null || properties.size() == 0) {
throw new IllegalArgumentException(
"Properties value must contain at least one value.");
}
ColumnFamilyOptions columnFamilyOptions = null;
StringBuilder stringBuilder = new StringBuilder();
for (final String name : properties.stringPropertyNames()){
stringBuilder.append(name);
stringBuilder.append("=");
stringBuilder.append(properties.getProperty(name));
stringBuilder.append(";");
}
long handle = getColumnFamilyOptionsFromProps(
stringBuilder.toString());
if (handle != 0){
columnFamilyOptions = new ColumnFamilyOptions(handle);
}
return columnFamilyOptions;
}
@Override
public ColumnFamilyOptions optimizeForPointLookup(
long blockCacheSizeMb) {
@@ -84,6 +127,11 @@ public class ColumnFamilyOptions extends RocksObject
@Override
public ColumnFamilyOptions setMergeOperatorName(String name) {
assert (isInitialized());
if (name == null) {
throw new IllegalArgumentException(
"Merge operator name must not be null.");
}
setMergeOperatorName(nativeHandle_, name);
return this;
}
@@ -522,6 +570,20 @@ public class ColumnFamilyOptions extends RocksObject
disposeInternal(nativeHandle_);
}
/**
* <p>Private constructor to be used by
* {@link #getColumnFamilyOptionsFromProps(java.util.Properties)}</p>
*
* @param handle native handle to ColumnFamilyOptions instance.
*/
private ColumnFamilyOptions(long handle) {
super();
nativeHandle_ = handle;
}
private static native long getColumnFamilyOptionsFromProps(
String optString);
private native void newColumnFamilyOptions();
private native void disposeInternal(long handle);
+44 -10
View File
@@ -14,25 +14,59 @@ package org.rocksdb;
* compression method (if any) is used to compress a block.</p>
*/
public enum CompressionType {
NO_COMPRESSION((byte) 0),
SNAPPY_COMPRESSION((byte) 1),
ZLIB_COMPRESSION((byte) 2),
BZLIB2_COMPRESSION((byte) 3),
LZ4_COMPRESSION((byte) 4),
LZ4HC_COMPRESSION((byte) 5);
private final byte value_;
NO_COMPRESSION((byte) 0, null),
SNAPPY_COMPRESSION((byte) 1, "snappy"),
ZLIB_COMPRESSION((byte) 2, "z"),
BZLIB2_COMPRESSION((byte) 3, "bzip2"),
LZ4_COMPRESSION((byte) 4, "lz4"),
LZ4HC_COMPRESSION((byte) 5, "lz4hc");
private CompressionType(byte value) {
value_ = value;
/**
* <p>Get the CompressionType enumeration value by
* passing the library name to this method.</p>
*
* <p>If library cannot be found the enumeration
* value {@code NO_COMPRESSION} will be returned.</p>
*
* @return CompressionType instance.
*/
public static CompressionType getCompressionType(String libraryName) {
if (libraryName != null) {
for (CompressionType compressionType : CompressionType.values()) {
if (compressionType.getLibraryName() != null &&
compressionType.getLibraryName().equals(libraryName)) {
return compressionType;
}
}
}
return CompressionType.NO_COMPRESSION;
}
/**
* Returns the byte value of the enumerations value
* <p>Returns the byte value of the enumerations value.</p>
*
* @return byte representation
*/
public byte getValue() {
return value_;
}
/**
* <p>Returns the library name of the compression type
* identified by the enumeration value.</p>
*
* @return library name
*/
public String getLibraryName() {
return libraryName_;
}
private CompressionType(byte value, final String libraryName) {
value_ = value;
libraryName_ = libraryName;
}
private final byte value_;
private final String libraryName_;
}
+74
View File
@@ -5,6 +5,8 @@
package org.rocksdb;
import java.util.Properties;
/**
* DBOptions to control the behavior of a database. It will be used
* during the creation of a {@link org.rocksdb.RocksDB} (i.e., RocksDB.open()).
@@ -29,6 +31,47 @@ public class DBOptions extends RocksObject implements DBOptionsInterface {
newDBOptions();
}
/**
* <p>Method to get a options instance by using pre-configured
* property values. If one or many values are undefined in
* the context of RocksDB the method will return a null
* value.</p>
*
* <p><strong>Note</strong>: Property keys can be derived from
* getter methods within the options class. Example: the method
* {@code allowMmapReads()} has a property key:
* {@code allow_mmap_reads}.</p>
*
* @param properties {@link java.util.Properties} instance.
*
* @return {@link org.rocksdb.DBOptions instance}
* or null.
*
* @throws java.lang.IllegalArgumentException if null or empty
* {@link java.util.Properties} instance is passed to the method call.
*/
public static DBOptions getDBOptionsFromProps(
Properties properties) {
if (properties == null || properties.size() == 0) {
throw new IllegalArgumentException(
"Properties value must contain at least one value.");
}
DBOptions dbOptions = null;
StringBuilder stringBuilder = new StringBuilder();
for (final String name : properties.stringPropertyNames()){
stringBuilder.append(name);
stringBuilder.append("=");
stringBuilder.append(properties.getProperty(name));
stringBuilder.append(";");
}
long handle = getDBOptionsFromProps(
stringBuilder.toString());
if (handle != 0){
dbOptions = new DBOptions(handle);
}
return dbOptions;
}
@Override
public DBOptions setCreateIfMissing(boolean flag) {
assert(isInitialized());
@@ -83,11 +126,26 @@ public class DBOptions extends RocksObject implements DBOptionsInterface {
@Override
public DBOptions setRateLimiterConfig(RateLimiterConfig config) {
assert(isInitialized());
rateLimiterConfig_ = config;
setRateLimiter(nativeHandle_, config.newRateLimiterHandle());
return this;
}
@Override
public DBOptions setInfoLogLevel(InfoLogLevel infoLogLevel) {
assert(isInitialized());
setInfoLogLevel(nativeHandle_, infoLogLevel.getValue());
return this;
}
@Override
public InfoLogLevel infoLogLevel() {
assert(isInitialized());
return InfoLogLevel.getInfoLogLevel(
infoLogLevel(nativeHandle_));
}
@Override
public DBOptions setMaxOpenFiles(int maxOpenFiles) {
assert(isInitialized());
@@ -472,6 +530,20 @@ public class DBOptions extends RocksObject implements DBOptionsInterface {
static final int DEFAULT_NUM_SHARD_BITS = -1;
/**
* <p>Private constructor to be used by
* {@link #getDBOptionsFromProps(java.util.Properties)}</p>
*
* @param handle native handle to DBOptions instance.
*/
private DBOptions(long handle) {
super();
nativeHandle_ = handle;
}
private static native long getDBOptionsFromProps(
String optString);
private native void newDBOptions();
private native void disposeInternal(long handle);
@@ -487,6 +559,8 @@ public class DBOptions extends RocksObject implements DBOptionsInterface {
private native boolean paranoidChecks(long handle);
private native void setRateLimiter(long handle,
long rateLimiterHandle);
private native void setInfoLogLevel(long handle, byte logLevel);
private native byte infoLogLevel(long handle);
private native void setMaxOpenFiles(long handle, int maxOpenFiles);
private native int maxOpenFiles(long handle);
private native void setMaxTotalWalSize(long handle,
+14
View File
@@ -113,6 +113,20 @@ public interface DBOptionsInterface {
*/
Object setRateLimiterConfig(RateLimiterConfig config);
/**
* <p>Sets the RocksDB log level. Default level is INFO</p>
*
* @param infoLogLevel log level to set.
* @return the instance of the current Object.
*/
Object setInfoLogLevel(InfoLogLevel infoLogLevel);
/**
* <p>Returns currently set log level.</p>
* @return {@link org.rocksdb.InfoLogLevel} instance.
*/
InfoLogLevel infoLogLevel();
/**
* Number of open files that can be used by the DB. You may need to
* increase this if your database has a large working set. Value -1 means
+47
View File
@@ -0,0 +1,47 @@
package org.rocksdb;
/**
* RocksDB log levels.
*/
public enum InfoLogLevel {
DEBUG_LEVEL((byte)0),
INFO_LEVEL((byte)1),
WARN_LEVEL((byte)2),
ERROR_LEVEL((byte)3),
FATAL_LEVEL((byte)4),
NUM_INFO_LOG_LEVELS((byte)5);
private final byte value_;
private InfoLogLevel(byte value) {
value_ = value;
}
/**
* Returns the byte value of the enumerations value
*
* @return byte representation
*/
public byte getValue() {
return value_;
}
/**
* Get InfoLogLevel by byte value.
*
* @param value byte representation of InfoLogLevel.
*
* @return {@link org.rocksdb.InfoLogLevel} instance or null.
* @throws java.lang.IllegalArgumentException if an invalid
* value is provided.
*/
public static InfoLogLevel getInfoLogLevel(byte value) {
for (InfoLogLevel infoLogLevel : InfoLogLevel.values()) {
if (infoLogLevel.getValue() == value){
return infoLogLevel;
}
}
throw new IllegalArgumentException(
"Illegal value provided for InfoLogLevel.");
}
}
+46 -27
View File
@@ -1,6 +1,9 @@
package org.rocksdb;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import org.rocksdb.util.Environment;
/**
@@ -8,42 +11,58 @@ import org.rocksdb.util.Environment;
* The shared library is extracted to a temp folder and loaded from there.
*/
public class NativeLibraryLoader {
private static String sharedLibraryName = Environment.getJniLibraryName("rocksdb");
private static String tempFileSuffix = "." + Environment.getJniLibraryExtension();
//singleton
private static final NativeLibraryLoader instance = new NativeLibraryLoader();
public static void loadLibraryFromJar(String tmpDir)
private static final String sharedLibraryName = Environment.getJniLibraryName("rocksdb");
private static final String tempFilePrefix = "librocksdbjni";
private static final String tempFileSuffix = "." + Environment.getJniLibraryExtension();
/**
* Get a reference to the NativeLibraryLoader
*
* @return The NativeLibraryLoader
*/
public static NativeLibraryLoader getInstance() {
return instance;
}
/**
* Attempts to extract the native RocksDB library
* from the classpath and load it
*
* @param tmpDir A temporary directory to use
* to copy the native library to. If null,
* or the empty string, we rely on Java's
* {@link java.io.File#createTempFile(String, String)}
* function to provide a temporary location.
* The temporary file will be registered for deletion
* on exit.
*
* @throws java.io.IOException if a filesystem operation fails.
*/
public void loadLibraryFromJar(final String tmpDir)
throws IOException {
File temp;
String tempFilePrefix = "librocksdbjni";
if(tmpDir == null || tmpDir.equals(""))
final File temp;
if(tmpDir == null || tmpDir.equals("")) {
temp = File.createTempFile(tempFilePrefix, tempFileSuffix);
else
temp = new File(tmpDir + "/" + sharedLibraryName);
temp.deleteOnExit();
} else {
temp = new File(tmpDir, sharedLibraryName);
}
if (!temp.exists()) {
throw new RuntimeException("File " + temp.getAbsolutePath() + " does not exist.");
} else {
temp.deleteOnExit();
}
byte[] buffer = new byte[102400];
int readBytes;
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(sharedLibraryName);
if (is == null) {
throw new RuntimeException(sharedLibraryName + " was not found inside JAR.");
}
OutputStream os = null;
try {
os = new FileOutputStream(temp);
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
// attempt to copy the library from the Jar file to the temp destination
try(final InputStream is = getClass().getClassLoader().getResourceAsStream(sharedLibraryName)) {
if (is == null) {
throw new RuntimeException(sharedLibraryName + " was not found inside JAR.");
} else {
Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
} finally {
if(os != null)
os.close();
is.close();
}
System.load(temp.getAbsolutePath());
+21 -1
View File
@@ -165,6 +165,11 @@ public class Options extends RocksObject
@Override
public Options setMergeOperatorName(String name) {
assert (isInitialized());
if (name == null) {
throw new IllegalArgumentException(
"Merge operator name must not be null.");
}
setMergeOperatorName(nativeHandle_, name);
return this;
}
@@ -616,6 +621,20 @@ public class Options extends RocksObject
return this;
}
@Override
public Options setInfoLogLevel(InfoLogLevel infoLogLevel) {
assert(isInitialized());
setInfoLogLevel(nativeHandle_, infoLogLevel.getValue());
return this;
}
@Override
public InfoLogLevel infoLogLevel() {
assert(isInitialized());
return InfoLogLevel.getInfoLogLevel(
infoLogLevel(nativeHandle_));
}
@Override
public String memTableFactoryName() {
assert(isInitialized());
@@ -1010,7 +1029,6 @@ public class Options extends RocksObject
long cfOptHandle);
private native void disposeInternal(long handle);
private native void setEnv(long optHandle, long envHandle);
private native long getEnvHandle(long handle);
private native void prepareForBulkLoad(long handle);
// DB native handles
@@ -1026,6 +1044,8 @@ public class Options extends RocksObject
private native boolean paranoidChecks(long handle);
private native void setRateLimiter(long handle,
long rateLimiterHandle);
private native void setInfoLogLevel(long handle, byte logLevel);
private native byte infoLogLevel(long handle);
private native void setMaxOpenFiles(long handle, int maxOpenFiles);
private native int maxOpenFiles(long handle);
private native void setMaxTotalWalSize(long handle,
-1
View File
@@ -155,7 +155,6 @@ public class ReadOptions extends RocksObject {
@Override protected void disposeInternal() {
assert(isInitialized());
disposeInternal(nativeHandle_);
}
private native void disposeInternal(long handle);
+58 -22
View File
@@ -8,15 +8,17 @@ package org.rocksdb;
import java.util.List;
/**
* This class is used to access information about backups and restore from them.
* <p>This class is used to access information about backups and
* restore from them.</p>
*
* Note that dispose() must be called before this instance become out-of-scope
* to release the allocated memory in c++.
* <p>Note: {@code dispose()} must be called before this instance
* become out-of-scope to release the allocated
* memory in c++.</p>
*
*/
public class RestoreBackupableDB extends RocksObject {
/**
* Constructor
* <p>Construct new estoreBackupableDB instance.</p>
*
* @param options {@link org.rocksdb.BackupableDBOptions} instance
*/
@@ -26,16 +28,18 @@ public class RestoreBackupableDB extends RocksObject {
}
/**
* Restore from backup with backup_id
* IMPORTANT -- if options_.share_table_files == true and you restore DB
* from some backup that is not the latest, and you start creating new
* backups from the new DB, they will probably fail.
* <p>Restore from backup with backup_id.</p>
*
* Example: Let's say you have backups 1, 2, 3, 4, 5 and you restore 3.
* If you add new data to the DB and try creating a new backup now, the
* database will diverge from backups 4 and 5 and the new backup will fail.
* If you want to create new backup, you will first have to delete backups 4
* and 5.
* <p><strong>Important</strong>: If options_.share_table_files == true
* and you restore DB from some backup that is not the latest, and you
* start creating new backups from the new DB, they will probably
* fail.</p>
*
* <p><strong>Example</strong>: Let's say you have backups 1, 2, 3, 4, 5
* and you restore 3. If you add new data to the DB and try creating a new
* backup now, the database will diverge from backups 4 and 5 and the new
* backup will fail. If you want to create new backup, you will first have
* to delete backups 4 and 5.</p>
*
* @param backupId id pointing to backup
* @param dbDir database directory to restore to
@@ -47,12 +51,13 @@ public class RestoreBackupableDB extends RocksObject {
*/
public void restoreDBFromBackup(long backupId, String dbDir, String walDir,
RestoreOptions restoreOptions) throws RocksDBException {
assert(isInitialized());
restoreDBFromBackup0(nativeHandle_, backupId, dbDir, walDir,
restoreOptions.nativeHandle_);
}
/**
* Restore from the latest backup.
* <p>Restore from the latest backup.</p>
*
* @param dbDir database directory to restore to
* @param walDir directory where wal files are located
@@ -63,12 +68,13 @@ public class RestoreBackupableDB extends RocksObject {
*/
public void restoreDBFromLatestBackup(String dbDir, String walDir,
RestoreOptions restoreOptions) throws RocksDBException {
assert(isInitialized());
restoreDBFromLatestBackup0(nativeHandle_, dbDir, walDir,
restoreOptions.nativeHandle_);
}
/**
* Deletes old backups, keeping latest numBackupsToKeep alive.
* <p>Deletes old backups, keeping latest numBackupsToKeep alive.</p>
*
* @param numBackupsToKeep of latest backups to keep
*
@@ -76,11 +82,12 @@ public class RestoreBackupableDB extends RocksObject {
* native library.
*/
public void purgeOldBackups(int numBackupsToKeep) throws RocksDBException {
assert(isInitialized());
purgeOldBackups0(nativeHandle_, numBackupsToKeep);
}
/**
* Deletes a specific backup.
* <p>Deletes a specific backup.</p>
*
* @param backupId of backup to delete.
*
@@ -88,25 +95,51 @@ public class RestoreBackupableDB extends RocksObject {
* native library.
*/
public void deleteBackup(int backupId) throws RocksDBException {
assert(isInitialized());
deleteBackup0(nativeHandle_, backupId);
}
/**
* Returns a list of {@link BackupInfo} instances, which describe
* already made backups.
* <p>Returns a list of {@link BackupInfo} instances, which describe
* already made backups.</p>
*
* @return List of {@link BackupInfo} instances.
*/
public List<BackupInfo> getBackupInfos() {
assert(isInitialized());
return getBackupInfo(nativeHandle_);
}
/**
* Release the memory allocated for the current instance
* in the c++ side.
* <p>Returns a list of corrupted backup ids. If there
* is no corrupted backup the method will return an
* empty list.</p>
*
* @return array of backup ids as int ids.
*/
public int[] getCorruptedBackups() {
assert(isInitialized());
return getCorruptedBackups(nativeHandle_);
}
/**
* <p>Will delete all the files we don't need anymore. It will
* do the full scan of the files/ directory and delete all the
* files that are not referenced.</p>
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public void garbageCollect() throws RocksDBException {
assert(isInitialized());
garbageCollect(nativeHandle_);
}
/**
* <p>Release the memory allocated for the current instance
* in the c++ side.</p>
*/
@Override public synchronized void disposeInternal() {
assert(isInitialized());
dispose(nativeHandle_);
}
@@ -121,6 +154,9 @@ public class RestoreBackupableDB extends RocksObject {
throws RocksDBException;
private native void deleteBackup0(long nativeHandle, int backupId)
throws RocksDBException;
protected native List<BackupInfo> getBackupInfo(long handle);
private native List<BackupInfo> getBackupInfo(long handle);
private native int[] getCorruptedBackups(long handle);
private native void garbageCollect(long handle)
throws RocksDBException;
private native void dispose(long nativeHandle);
}
+78 -9
View File
@@ -18,8 +18,6 @@ import org.rocksdb.util.Environment;
public class RocksDB extends RocksObject {
public static final String DEFAULT_COLUMN_FAMILY = "default";
public static final int NOT_FOUND = -1;
private static final String[] compressionLibs_ = {
"snappy", "z", "bzip2", "lz4", "lz4hc"};
static {
RocksDB.loadLibrary();
@@ -35,16 +33,18 @@ public class RocksDB extends RocksObject {
public static synchronized void loadLibrary() {
String tmpDir = System.getenv("ROCKSDB_SHAREDLIB_DIR");
// loading possibly necessary libraries.
for (String lib : compressionLibs_) {
for (CompressionType compressionType : CompressionType.values()) {
try {
System.loadLibrary(lib);
if (compressionType.getLibraryName() != null) {
System.loadLibrary(compressionType.getLibraryName());
}
} catch (UnsatisfiedLinkError e) {
// since it may be optional, we ignore its loading failure here.
}
}
try
{
NativeLibraryLoader.loadLibraryFromJar(tmpDir);
NativeLibraryLoader.getInstance().loadLibraryFromJar(tmpDir);
}
catch (IOException e)
{
@@ -60,10 +60,14 @@ public class RocksDB extends RocksObject {
* of a library.
*/
public static synchronized void loadLibrary(List<String> paths) {
for (String lib : compressionLibs_) {
for (CompressionType compressionType : CompressionType.values()) {
if (compressionType.equals(CompressionType.NO_COMPRESSION)) {
continue;
}
for (String path : paths) {
try {
System.load(path + "/" + Environment.getSharedLibraryName(lib));
System.load(path + "/" + Environment.getSharedLibraryName(
compressionType.getLibraryName()));
break;
} catch (UnsatisfiedLinkError e) {
// since they are optional, we ignore loading fails.
@@ -103,6 +107,7 @@ public class RocksDB extends RocksObject {
// This allows to use the rocksjni default Options instead of
// the c++ one.
Options options = new Options();
options.setCreateIfMissing(true);
return open(options, path);
}
@@ -363,8 +368,10 @@ public class RocksDB extends RocksObject {
}
@Override protected void disposeInternal() {
assert(isInitialized());
disposeInternal(nativeHandle_);
synchronized (this) {
assert (isInitialized());
disposeInternal(nativeHandle_);
}
}
/**
@@ -1029,6 +1036,62 @@ public class RocksDB extends RocksObject {
return getProperty0(nativeHandle_, property, property.length());
}
/**
* <p> Similar to GetProperty(), but only works for a subset of properties whose
* return value is a numerical value. Return the value as long.</p>
*
* <p><strong>Note</strong>: As the returned property is of type
* {@code uint64_t} on C++ side the returning value can be negative
* because Java supports in Java 7 only signed long values.</p>
*
* <p><strong>Java 7</strong>: To mitigate the problem of the non
* existent unsigned long tpye, values should be encapsulated using
* {@link java.math.BigInteger} to reflect the correct value. The correct
* behavior is guaranteed if {@code 2^64} is added to negative values.</p>
*
* <p><strong>Java 8</strong>: In Java 8 the value should be treated as
* unsigned long using provided methods of type {@link Long}.</p>
*
* @param property to be fetched.
*
* @return numerical property value.
*
* @throws RocksDBException if an error happens in the underlying native code.
*/
public long getLongProperty(String property) throws RocksDBException {
return getLongProperty(nativeHandle_, property, property.length());
}
/**
* <p> Similar to GetProperty(), but only works for a subset of properties whose
* return value is a numerical value. Return the value as long.</p>
*
* <p><strong>Note</strong>: As the returned property is of type
* {@code uint64_t} on C++ side the returning value can be negative
* because Java supports in Java 7 only signed long values.</p>
*
* <p><strong>Java 7</strong>: To mitigate the problem of the non
* existent unsigned long tpye, values should be encapsulated using
* {@link java.math.BigInteger} to reflect the correct value. The correct
* behavior is guaranteed if {@code 2^64} is added to negative values.</p>
*
* <p><strong>Java 8</strong>: In Java 8 the value should be treated as
* unsigned long using provided methods of type {@link Long}.</p>
*
* @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
* instance
* @param property to be fetched.
*
* @return numerical property value
*
* @throws RocksDBException if an error happens in the underlying native code.
*/
public long getLongProperty(ColumnFamilyHandle columnFamilyHandle, String property)
throws RocksDBException {
return getLongProperty(nativeHandle_, columnFamilyHandle.nativeHandle_, property,
property.length());
}
/**
* Return a heap-allocated iterator over the contents of the database.
* The result of newIterator() is initially invalid (caller must
@@ -1150,6 +1213,8 @@ public class RocksDB extends RocksObject {
throws RocksDBException, IllegalArgumentException {
// throws RocksDBException if something goes wrong
dropColumnFamily(nativeHandle_, columnFamilyHandle.nativeHandle_);
// After the drop the native handle is not valid anymore
columnFamilyHandle.nativeHandle_ = 0;
}
/**
@@ -1292,6 +1357,10 @@ public class RocksDB extends RocksObject {
String property, int propertyLength) throws RocksDBException;
protected native String getProperty0(long nativeHandle, long cfHandle,
String property, int propertyLength) throws RocksDBException;
protected native long getLongProperty(long nativeHandle,
String property, int propertyLength) throws RocksDBException;
protected native long getLongProperty(long nativeHandle, long cfHandle,
String property, int propertyLength) throws RocksDBException;
protected native long iterator0(long handle);
protected native long iterator0(long handle, long cfHandle);
protected native long[] iterators(long handle,
+2 -1
View File
@@ -18,6 +18,7 @@ public class RocksEnv extends RocksObject {
static {
default_env_ = new RocksEnv(getDefaultEnvInternal());
}
private static native long getDefaultEnvInternal();
@@ -101,7 +102,7 @@ public class RocksEnv extends RocksObject {
* {@link RocksObject} must implement to release their associated C++
* resource.
*/
protected void disposeInternal() {
@Override protected void disposeInternal() {
disposeInternal(nativeHandle_);
}
private native void disposeInternal(long handle);
+6 -4
View File
@@ -143,9 +143,11 @@ public class RocksIterator extends RocksObject {
* before freeing the native handle.</p>
*/
@Override protected void disposeInternal() {
assert(isInitialized());
if (rocksDB_.isInitialized()) {
disposeInternal(nativeHandle_);
synchronized (rocksDB_) {
assert (isInitialized());
if (rocksDB_.isInitialized()) {
disposeInternal(nativeHandle_);
}
}
}
@@ -160,5 +162,5 @@ public class RocksIterator extends RocksObject {
private native void seek0(long handle, byte[] target, int targetLen);
private native void status0(long handle);
RocksDB rocksDB_;
final RocksDB rocksDB_;
}
-10
View File
@@ -221,13 +221,3 @@ public class WriteBatch extends RocksObject {
private native void disposeInternal(long handle);
}
}
/**
* Package-private class which provides java api to access
* c++ WriteBatchInternal.
*/
class WriteBatchInternal {
static native void setSequence(WriteBatch batch, long sn);
static native long sequence(WriteBatch batch);
static native void append(WriteBatch b1, WriteBatch b2);
}
-124
View File
@@ -1,124 +0,0 @@
// Copyright (c) 2014, 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.
package org.rocksdb;
import java.util.*;
import java.io.UnsupportedEncodingException;
/**
* This class mimics the db/write_batch_test.cc in the c++ rocksdb library.
*/
public class WriteBatchTest {
static {
RocksDB.loadLibrary();
}
public static void main(String args[]) {
System.out.println("Testing WriteBatchTest.Empty ===");
Empty();
System.out.println("Testing WriteBatchTest.Multiple ===");
Multiple();
System.out.println("Testing WriteBatchTest.Append ===");
Append();
System.out.println("Testing WriteBatchTest.Blob ===");
Blob();
// The following tests have not yet ported.
// Continue();
// PutGatherSlices();
System.out.println("Passed all WriteBatchTest!");
}
static void Empty() {
WriteBatch batch = new WriteBatch();
assert(batch.count() == 0);
}
static void Multiple() {
try {
WriteBatch batch = new WriteBatch();
batch.put("foo".getBytes("US-ASCII"), "bar".getBytes("US-ASCII"));
batch.remove("box".getBytes("US-ASCII"));
batch.put("baz".getBytes("US-ASCII"), "boo".getBytes("US-ASCII"));
WriteBatchInternal.setSequence(batch, 100);
assert(100 == WriteBatchInternal.sequence(batch));
assert(3 == batch.count());
assert(("Put(baz, boo)@102" +
"Delete(box)@101" +
"Put(foo, bar)@100")
.equals(new String(getContents(batch), "US-ASCII")));
} catch (UnsupportedEncodingException e) {
System.err.println(e);
assert(false);
}
}
static void Append() {
WriteBatch b1 = new WriteBatch();
WriteBatch b2 = new WriteBatch();
WriteBatchInternal.setSequence(b1, 200);
WriteBatchInternal.setSequence(b2, 300);
WriteBatchInternal.append(b1, b2);
assert(getContents(b1).length == 0);
assert(b1.count() == 0);
try {
b2.put("a".getBytes("US-ASCII"), "va".getBytes("US-ASCII"));
WriteBatchInternal.append(b1, b2);
assert("Put(a, va)@200".equals(new String(getContents(b1), "US-ASCII")));
assert(1 == b1.count());
b2.clear();
b2.put("b".getBytes("US-ASCII"), "vb".getBytes("US-ASCII"));
WriteBatchInternal.append(b1, b2);
assert(("Put(a, va)@200" +
"Put(b, vb)@201")
.equals(new String(getContents(b1), "US-ASCII")));
assert(2 == b1.count());
b2.remove("foo".getBytes("US-ASCII"));
WriteBatchInternal.append(b1, b2);
assert(("Put(a, va)@200" +
"Put(b, vb)@202" +
"Put(b, vb)@201" +
"Delete(foo)@203")
.equals(new String(getContents(b1), "US-ASCII")));
assert(4 == b1.count());
} catch (UnsupportedEncodingException e) {
System.err.println(e);
assert(false);
}
}
static void Blob() {
WriteBatch batch = new WriteBatch();
try {
batch.put("k1".getBytes("US-ASCII"), "v1".getBytes("US-ASCII"));
batch.put("k2".getBytes("US-ASCII"), "v2".getBytes("US-ASCII"));
batch.put("k3".getBytes("US-ASCII"), "v3".getBytes("US-ASCII"));
batch.putLogData("blob1".getBytes("US-ASCII"));
batch.remove("k2".getBytes("US-ASCII"));
batch.putLogData("blob2".getBytes("US-ASCII"));
batch.merge("foo".getBytes("US-ASCII"), "bar".getBytes("US-ASCII"));
assert(5 == batch.count());
assert(("Merge(foo, bar)@4" +
"Put(k1, v1)@0" +
"Delete(k2)@3" +
"Put(k2, v2)@1" +
"Put(k3, v3)@2")
.equals(new String(getContents(batch), "US-ASCII")));
} catch (UnsupportedEncodingException e) {
System.err.println(e);
assert(false);
}
}
static native byte[] getContents(WriteBatch batch);
}
+95 -88
View File
@@ -163,15 +163,6 @@ public class DbBenchmark {
EXISTING
}
enum CompressionType {
NONE,
SNAPPY,
ZLIB,
BZIP2,
LZ4,
LZ4HC
}
static {
RocksDB.loadLibrary();
}
@@ -457,18 +448,16 @@ public class DbBenchmark {
// options.setPrefixSize((Integer)flags_.get(Flag.prefix_size));
// options.setKeysPerPrefix((Long)flags_.get(Flag.keys_per_prefix));
compressionType_ = (String) flags.get(Flag.compression_type);
compression_ = CompressionType.NONE;
compression_ = CompressionType.NO_COMPRESSION;
try {
if (compressionType_.equals("snappy")) {
System.loadLibrary("snappy");
} else if (compressionType_.equals("zlib")) {
System.loadLibrary("z");
} else if (compressionType_.equals("bzip2")) {
System.loadLibrary("bzip2");
} else if (compressionType_.equals("lz4")) {
System.loadLibrary("lz4");
} else if (compressionType_.equals("lz4hc")) {
System.loadLibrary("lz4hc");
if (compressionType_!=null) {
final CompressionType compressionType =
CompressionType.getCompressionType(compressionType_);
if (compressionType != null &&
compressionType != CompressionType.NO_COMPRESSION) {
System.loadLibrary(compressionType.getLibraryName());
}
}
} catch (UnsatisfiedLinkError e) {
System.err.format("Unable to load %s library:%s%n" +
@@ -495,26 +484,32 @@ public class DbBenchmark {
} else {
options.setCreateIfMissing(false);
}
if (memtable_.equals("skip_list")) {
options.setMemTableConfig(new SkipListMemTableConfig());
} else if (memtable_.equals("vector")) {
options.setMemTableConfig(new VectorMemTableConfig());
} else if (memtable_.equals("hash_linkedlist")) {
options.setMemTableConfig(
new HashLinkedListMemTableConfig()
.setBucketCount(hashBucketCount_));
options.useFixedLengthPrefixExtractor(prefixSize_);
} else if (memtable_.equals("hash_skiplist") ||
memtable_.equals("prefix_hash")) {
options.setMemTableConfig(
new HashSkipListMemTableConfig()
.setBucketCount(hashBucketCount_));
options.useFixedLengthPrefixExtractor(prefixSize_);
} else {
System.err.format(
"unable to detect the specified memtable, " +
"use the default memtable factory %s%n",
options.memTableFactoryName());
switch (memtable_) {
case "skip_list":
options.setMemTableConfig(new SkipListMemTableConfig());
break;
case "vector":
options.setMemTableConfig(new VectorMemTableConfig());
break;
case "hash_linkedlist":
options.setMemTableConfig(
new HashLinkedListMemTableConfig()
.setBucketCount(hashBucketCount_));
options.useFixedLengthPrefixExtractor(prefixSize_);
break;
case "hash_skiplist":
case "prefix_hash":
options.setMemTableConfig(
new HashSkipListMemTableConfig()
.setBucketCount(hashBucketCount_));
options.useFixedLengthPrefixExtractor(prefixSize_);
break;
default:
System.err.format(
"unable to detect the specified memtable, " +
"use the default memtable factory %s%n",
options.memTableFactoryName());
break;
}
if (usePlainTable_) {
options.setTableFormatConfig(
@@ -645,53 +640,65 @@ public class DbBenchmark {
int currentTaskId = 0;
boolean known = true;
if (benchmark.equals("fillseq")) {
tasks.add(new WriteSequentialTask(
currentTaskId++, randSeed_, num_, num_, writeOpt, 1));
} else if (benchmark.equals("fillbatch")) {
tasks.add(new WriteRandomTask(
currentTaskId++, randSeed_, num_ / 1000, num_, writeOpt, 1000));
} else if (benchmark.equals("fillrandom")) {
tasks.add(new WriteRandomTask(
currentTaskId++, randSeed_, num_, num_, writeOpt, 1));
} else if (benchmark.equals("filluniquerandom")) {
tasks.add(new WriteUniqueRandomTask(
currentTaskId++, randSeed_, num_, num_, writeOpt, 1));
} else if (benchmark.equals("fillsync")) {
writeOpt.setSync(true);
tasks.add(new WriteRandomTask(
currentTaskId++, randSeed_, num_ / 1000, num_ / 1000,
writeOpt, 1));
} else if (benchmark.equals("readseq")) {
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadSequentialTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_));
}
} else if (benchmark.equals("readrandom")) {
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadRandomTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_));
}
} else if (benchmark.equals("readwhilewriting")) {
WriteTask writeTask = new WriteRandomTask(
-1, randSeed_, Long.MAX_VALUE, num_, writeOpt, 1, writesPerSeconds_);
writeTask.stats_.setExcludeFromMerge();
bgTasks.add(writeTask);
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadRandomTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_));
}
} else if (benchmark.equals("readhot")) {
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadRandomTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_ / 100));
}
} else if (benchmark.equals("delete")) {
destroyDb();
open(options);
} else {
known = false;
System.err.println("Unknown benchmark: " + benchmark);
switch (benchmark) {
case "fillseq":
tasks.add(new WriteSequentialTask(
currentTaskId++, randSeed_, num_, num_, writeOpt, 1));
break;
case "fillbatch":
tasks.add(new WriteRandomTask(
currentTaskId++, randSeed_, num_ / 1000, num_, writeOpt, 1000));
break;
case "fillrandom":
tasks.add(new WriteRandomTask(
currentTaskId++, randSeed_, num_, num_, writeOpt, 1));
break;
case "filluniquerandom":
tasks.add(new WriteUniqueRandomTask(
currentTaskId++, randSeed_, num_, num_, writeOpt, 1));
break;
case "fillsync":
writeOpt.setSync(true);
tasks.add(new WriteRandomTask(
currentTaskId++, randSeed_, num_ / 1000, num_ / 1000,
writeOpt, 1));
break;
case "readseq":
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadSequentialTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_));
}
break;
case "readrandom":
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadRandomTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_));
}
break;
case "readwhilewriting":
WriteTask writeTask = new WriteRandomTask(
-1, randSeed_, Long.MAX_VALUE, num_, writeOpt, 1, writesPerSeconds_);
writeTask.stats_.setExcludeFromMerge();
bgTasks.add(writeTask);
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadRandomTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_));
}
break;
case "readhot":
for (int t = 0; t < threadNum_; ++t) {
tasks.add(new ReadRandomTask(
currentTaskId++, randSeed_, reads_ / threadNum_, num_ / 100));
}
break;
case "delete":
destroyDb();
open(options);
break;
default:
known = false;
System.err.println("Unknown benchmark: " + benchmark);
break;
}
if (known) {
ExecutorService executor = Executors.newCachedThreadPool();
@@ -800,7 +807,7 @@ public class DbBenchmark {
System.out.printf(
"%-16s : %11.5f micros/op; %6.1f MB/s;%s %d / %d task(s) finished.\n",
benchmark, (double) elapsedSeconds / stats.done_ * 1e6,
benchmark, elapsedSeconds / stats.done_ * 1e6,
(stats.bytes_ / 1048576.0) / elapsedSeconds, extra,
taskFinishedCount, concurrentThreads);
}
@@ -9,9 +9,11 @@ import org.rocksdb.*;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import static org.assertj.core.api.Assertions.assertThat;
import static org.rocksdb.test.Types.byteToInt;
import static org.rocksdb.test.Types.intToByte;
@@ -39,7 +41,7 @@ public abstract class AbstractComparatorTest {
*
* @throws java.io.IOException if IO error happens.
*/
public void testRoundtrip(final Path db_path) throws IOException {
public void testRoundtrip(final Path db_path) throws IOException, RocksDBException {
Options opt = null;
RocksDB db = null;
@@ -64,7 +66,6 @@ public abstract class AbstractComparatorTest {
}
db.close();
// re-open db and read from start to end
// integer keys should be in ascending
// order as defined by SimpleIntComparator
@@ -75,17 +76,14 @@ public abstract class AbstractComparatorTest {
int count = 0;
for (it.seekToFirst(); it.isValid(); it.next()) {
final int thisKey = byteToInt(it.key());
assert(thisKey > lastKey);
assertThat(thisKey).isGreaterThan(lastKey);
lastKey = thisKey;
count++;
}
db.close();
assert(count == ITERATIONS);
assertThat(count).isEqualTo(ITERATIONS);
} catch (final RocksDBException e) {
System.err.format("[ERROR]: %s%n", e);
e.printStackTrace();
} finally {
if (db != null) {
db.close();
@@ -94,8 +92,97 @@ public abstract class AbstractComparatorTest {
if (opt != null) {
opt.dispose();
}
}
}
removeDb(db_path); // cleanup after ourselves!
/**
* Test which stores random keys into a column family
* in the database
* using an @see getAscendingIntKeyComparator
* it then checks that these keys are read back in
* ascending order
*
* @param db_path A path where we can store database
* files temporarily
*
* @throws java.io.IOException if IO error happens.
*/
public void testRoundtripCf(final Path db_path) throws IOException,
RocksDBException {
DBOptions opt = null;
RocksDB db = null;
List<ColumnFamilyDescriptor> cfDescriptors =
new ArrayList<>();
cfDescriptors.add(new ColumnFamilyDescriptor(
RocksDB.DEFAULT_COLUMN_FAMILY));
cfDescriptors.add(new ColumnFamilyDescriptor("new_cf",
new ColumnFamilyOptions().setComparator(
getAscendingIntKeyComparator())));
List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
try {
opt = new DBOptions().
setCreateIfMissing(true).
setCreateMissingColumnFamilies(true);
// store 10,000 random integer keys
final int ITERATIONS = 10000;
db = RocksDB.open(opt, db_path.toString(), cfDescriptors, cfHandles);
assertThat(cfDescriptors.size()).isEqualTo(2);
assertThat(cfHandles.size()).isEqualTo(2);
final Random random = new Random();
for (int i = 0; i < ITERATIONS; i++) {
final byte key[] = intToByte(random.nextInt());
if (i > 0 && db.get(cfHandles.get(1), key) != null) {
// does key already exist (avoid duplicates)
i--; // generate a different key
} else {
db.put(cfHandles.get(1), key, "value".getBytes());
}
}
for (ColumnFamilyHandle handle : cfHandles) {
handle.dispose();
}
cfHandles.clear();
db.close();
// re-open db and read from start to end
// integer keys should be in ascending
// order as defined by SimpleIntComparator
db = RocksDB.open(opt, db_path.toString(), cfDescriptors, cfHandles);
assertThat(cfDescriptors.size()).isEqualTo(2);
assertThat(cfHandles.size()).isEqualTo(2);
final RocksIterator it = db.newIterator(cfHandles.get(1));
it.seekToFirst();
int lastKey = Integer.MIN_VALUE;
int count = 0;
for (it.seekToFirst(); it.isValid(); it.next()) {
final int thisKey = byteToInt(it.key());
assertThat(thisKey).isGreaterThan(lastKey);
lastKey = thisKey;
count++;
}
for (ColumnFamilyHandle handle : cfHandles) {
handle.dispose();
}
cfHandles.clear();
db.close();
assertThat(count).isEqualTo(ITERATIONS);
} finally {
for (ColumnFamilyHandle handle : cfHandles) {
handle.dispose();
}
if (db != null) {
db.close();
}
if (opt != null) {
opt.dispose();
}
}
}
@@ -126,43 +213,4 @@ public abstract class AbstractComparatorTest {
return result;
}
/**
* Utility method for deleting database files
*
* @param db_path The path to the database to remove
* from the filesystem
*/
private static void removeDb(final Path db_path) throws IOException {
Files.walkFileTree(db_path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(final Path file, IOException exc)
throws IOException {
// try to delete the file anyway, even if its attributes
// could not be read, since delete-only access is
// theoretically possible
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(final Path dir, IOException exc)
throws IOException {
if (exc == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
} else {
// directory iteration failed; propagate exception
throw exc;
}
}
});
}
}
@@ -0,0 +1,284 @@
// Copyright (c) 2014, 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.
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.rocksdb.BackupableDBOptions;
import java.util.Random;
import static org.assertj.core.api.Assertions.assertThat;
public class BackupableDBOptionsTest {
private final static String ARBITRARY_PATH = "/tmp";
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
@Rule
public ExpectedException exception = ExpectedException.none();
public static final Random rand = PlatformRandomHelper.
getPlatformSpecificRandomFactory();
@Test
public void backupDir() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
assertThat(backupableDBOptions.backupDir()).
isEqualTo(ARBITRARY_PATH);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void shareTableFiles() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
boolean value = rand.nextBoolean();
backupableDBOptions.setShareTableFiles(value);
assertThat(backupableDBOptions.shareTableFiles()).
isEqualTo(value);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void sync() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
boolean value = rand.nextBoolean();
backupableDBOptions.setSync(value);
assertThat(backupableDBOptions.sync()).isEqualTo(value);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void destroyOldData() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
boolean value = rand.nextBoolean();
backupableDBOptions.setDestroyOldData(value);
assertThat(backupableDBOptions.destroyOldData()).
isEqualTo(value);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void backupLogFiles() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
boolean value = rand.nextBoolean();
backupableDBOptions.setBackupLogFiles(value);
assertThat(backupableDBOptions.backupLogFiles()).
isEqualTo(value);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void backupRateLimit() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
long value = Math.abs(rand.nextLong());
backupableDBOptions.setBackupRateLimit(value);
assertThat(backupableDBOptions.backupRateLimit()).
isEqualTo(value);
// negative will be mapped to 0
backupableDBOptions.setBackupRateLimit(-1);
assertThat(backupableDBOptions.backupRateLimit()).
isEqualTo(0);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void restoreRateLimit() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
long value = Math.abs(rand.nextLong());
backupableDBOptions.setRestoreRateLimit(value);
assertThat(backupableDBOptions.restoreRateLimit()).
isEqualTo(value);
// negative will be mapped to 0
backupableDBOptions.setRestoreRateLimit(-1);
assertThat(backupableDBOptions.restoreRateLimit()).
isEqualTo(0);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void shareFilesWithChecksum() {
BackupableDBOptions backupableDBOptions = null;
try {
backupableDBOptions = new BackupableDBOptions(ARBITRARY_PATH);
boolean value = rand.nextBoolean();
backupableDBOptions.setShareFilesWithChecksum(value);
assertThat(backupableDBOptions.shareFilesWithChecksum()).
isEqualTo(value);
} finally {
if (backupableDBOptions != null) {
backupableDBOptions.dispose();
}
}
}
@Test
public void failBackupDirIsNull() {
exception.expect(IllegalArgumentException.class);
new BackupableDBOptions(null);
}
@Test
public void failBackupDirIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.backupDir();
}
@Test
public void failSetShareTableFilesIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setShareTableFiles(true);
}
@Test
public void failShareTableFilesIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.shareTableFiles();
}
@Test
public void failSetSyncIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setSync(true);
}
@Test
public void failSyncIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.sync();
}
@Test
public void failSetDestroyOldDataIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setDestroyOldData(true);
}
@Test
public void failDestroyOldDataIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.destroyOldData();
}
@Test
public void failSetBackupLogFilesIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setBackupLogFiles(true);
}
@Test
public void failBackupLogFilesIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.backupLogFiles();
}
@Test
public void failSetBackupRateLimitIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setBackupRateLimit(1);
}
@Test
public void failBackupRateLimitIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.backupRateLimit();
}
@Test
public void failSetRestoreRateLimitIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setRestoreRateLimit(1);
}
@Test
public void failRestoreRateLimitIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.restoreRateLimit();
}
@Test
public void failSetShareFilesWithChecksumIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.setShareFilesWithChecksum(true);
}
@Test
public void failShareFilesWithChecksumIfDisposed(){
BackupableDBOptions options = setupUninitializedBackupableDBOptions(
exception);
options.shareFilesWithChecksum();
}
private BackupableDBOptions setupUninitializedBackupableDBOptions(
ExpectedException exception) {
BackupableDBOptions backupableDBOptions =
new BackupableDBOptions(ARBITRARY_PATH);
backupableDBOptions.dispose();
exception.expect(AssertionError.class);
return backupableDBOptions;
}
}
+402 -101
View File
@@ -5,121 +5,422 @@
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rocksdb.*;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class BackupableDBTest {
static final String db_path = "/tmp/rocksdbjni_backupable_db_test";
static final String backup_path = "/tmp/rocksdbjni_backupable_db_backup_test";
static {
RocksDB.loadLibrary();
}
public static void main(String[] args) {
Options opt = new Options();
opt.setCreateIfMissing(true);
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
BackupableDBOptions bopt = new BackupableDBOptions(backup_path, false,
true, false, true, 0, 0);
@Rule
public TemporaryFolder dbFolder = new TemporaryFolder();
@Rule
public TemporaryFolder backupFolder = new TemporaryFolder();
@Test
public void backupDb() throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
List<BackupInfo> backupInfos;
List<BackupInfo> restoreInfos;
try {
bdb = BackupableDB.open(opt, bopt, db_path);
bdb.put("abc".getBytes(), "def".getBytes());
bdb.put("ghi".getBytes(), "jkl".getBytes());
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 0);
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
// Create two backups
bdb.createNewBackup(false);
bdb.createNewBackup(true);
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 1);
// Retrieving backup infos twice shall not
// lead to different results
List<BackupInfo> tmpBackupInfo = bdb.getBackupInfos();
assert(tmpBackupInfo.get(0).backupId() ==
backupInfos.get(0).backupId());
assert(tmpBackupInfo.get(0).timestamp() ==
backupInfos.get(0).timestamp());
assert(tmpBackupInfo.get(0).size() ==
backupInfos.get(0).size());
assert(tmpBackupInfo.get(0).numberFiles() ==
backupInfos.get(0).numberFiles());
// delete record after backup
bdb.remove("abc".getBytes());
byte[] value = bdb.get("abc".getBytes());
assert(value == null);
bdb.close();
// restore from backup
RestoreOptions ropt = new RestoreOptions(false);
RestoreBackupableDB rdb = new RestoreBackupableDB(bopt);
// getting backup infos from restorable db should
// lead to the same infos as from backupable db
restoreInfos = rdb.getBackupInfos();
assert(restoreInfos.size() == backupInfos.size());
assert(restoreInfos.get(0).backupId() ==
backupInfos.get(0).backupId());
assert(restoreInfos.get(0).timestamp() ==
backupInfos.get(0).timestamp());
assert(restoreInfos.get(0).size() ==
backupInfos.get(0).size());
assert(restoreInfos.get(0).numberFiles() ==
backupInfos.get(0).numberFiles());
rdb.restoreDBFromLatestBackup(db_path, db_path,
ropt);
// do nothing because there is only one backup
rdb.purgeOldBackups(1);
restoreInfos = rdb.getBackupInfos();
assert(restoreInfos.size() == 1);
rdb.dispose();
ropt.dispose();
// verify that backed up data contains deleted record
bdb = BackupableDB.open(opt, bopt, db_path);
value = bdb.get("abc".getBytes());
assert(new String(value).equals("def"));
bdb.createNewBackup(false);
// after new backup there must be two backup infos
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 2);
// deleting the backup must be possible using the
// id provided by backup infos
bdb.deleteBackup(backupInfos.get(1).backupId());
// after deletion there should only be one info
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 1);
bdb.createNewBackup(false);
bdb.createNewBackup(false);
bdb.createNewBackup(false);
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 4);
// purge everything and keep two
bdb.purgeOldBackups(2);
// backup infos need to be two
backupInfos = bdb.getBackupInfos();
assert(backupInfos.size() == 2);
assert(backupInfos.get(0).backupId() == 4);
assert(backupInfos.get(1).backupId() == 5);
System.out.println("Backup and restore test passed");
} catch (RocksDBException e) {
System.err.format("[ERROR]: %s%n", e);
e.printStackTrace();
verifyNumberOfValidBackups(bdb, 2);
} finally {
opt.dispose();
bopt.dispose();
if (bdb != null) {
bdb.close();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void deleteBackup() throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
try {
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
// Create two backups
bdb.createNewBackup(false);
bdb.createNewBackup(true);
List<BackupInfo> backupInfo =
verifyNumberOfValidBackups(bdb, 2);
// Delete the first backup
bdb.deleteBackup(backupInfo.get(0).backupId());
List<BackupInfo> newBackupInfo =
verifyNumberOfValidBackups(bdb, 1);
// The second backup must remain.
assertThat(newBackupInfo.get(0).backupId()).
isEqualTo(backupInfo.get(1).backupId());
} finally {
if (bdb != null) {
bdb.close();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void deleteBackupWithRestoreBackupableDB()
throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
RestoreBackupableDB rdb = null;
try {
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
// Create two backups
bdb.createNewBackup(false);
bdb.createNewBackup(true);
List<BackupInfo> backupInfo =
verifyNumberOfValidBackups(bdb, 2);
// init RestoreBackupableDB
rdb = new RestoreBackupableDB(bopt);
// Delete the first backup
rdb.deleteBackup(backupInfo.get(0).backupId());
// Fetch backup info using RestoreBackupableDB
List<BackupInfo> newBackupInfo = verifyNumberOfValidBackups(rdb, 1);
// The second backup must remain.
assertThat(newBackupInfo.get(0).backupId()).
isEqualTo(backupInfo.get(1).backupId());
} finally {
if (bdb != null) {
bdb.close();
}
if (rdb != null) {
rdb.dispose();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void purgeOldBackups() throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
try {
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
// Create two backups
bdb.createNewBackup(false);
bdb.createNewBackup(true);
bdb.createNewBackup(true);
bdb.createNewBackup(true);
List<BackupInfo> backupInfo =
verifyNumberOfValidBackups(bdb, 4);
// Delete everything except the latest backup
bdb.purgeOldBackups(1);
List<BackupInfo> newBackupInfo =
verifyNumberOfValidBackups(bdb, 1);
// The latest backup must remain.
assertThat(newBackupInfo.get(0).backupId()).
isEqualTo(backupInfo.get(3).backupId());
} finally {
if (bdb != null) {
bdb.close();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void purgeOldBackupsWithRestoreBackupableDb()
throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
RestoreBackupableDB rdb = null;
try {
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
// Create two backups
bdb.createNewBackup(false);
bdb.createNewBackup(true);
bdb.createNewBackup(true);
bdb.createNewBackup(true);
List<BackupInfo> infos = verifyNumberOfValidBackups(bdb, 4);
assertThat(infos.get(1).size()).
isEqualTo(infos.get(2).size());
assertThat(infos.get(1).numberFiles()).
isEqualTo(infos.get(2).numberFiles());
long maxTimeBeforePurge = Long.MIN_VALUE;
for (BackupInfo backupInfo : infos) {
if (maxTimeBeforePurge < backupInfo.timestamp()) {
maxTimeBeforePurge = backupInfo.timestamp();
}
}
// init RestoreBackupableDB
rdb = new RestoreBackupableDB(bopt);
// the same number of backups must
// exist using RestoreBackupableDB.
verifyNumberOfValidBackups(rdb, 4);
rdb.purgeOldBackups(1);
infos = verifyNumberOfValidBackups(rdb, 1);
assertThat(infos.get(0).timestamp()).
isEqualTo(maxTimeBeforePurge);
} finally {
if (bdb != null) {
bdb.close();
}
if (rdb != null) {
rdb.dispose();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void restoreLatestBackup()
throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
RestoreBackupableDB rdb = null;
try {
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
bdb.createNewBackup(true);
verifyNumberOfValidBackups(bdb, 1);
bdb.put("key1".getBytes(), "valueV2".getBytes());
bdb.put("key2".getBytes(), "valueV2".getBytes());
bdb.createNewBackup(true);
verifyNumberOfValidBackups(bdb, 2);
bdb.put("key1".getBytes(), "valueV3".getBytes());
bdb.put("key2".getBytes(), "valueV3".getBytes());
assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V3");
assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V3");
bdb.close();
// init RestoreBackupableDB
rdb = new RestoreBackupableDB(bopt);
verifyNumberOfValidBackups(rdb, 2);
// restore db from latest backup
rdb.restoreDBFromLatestBackup(dbFolder.getRoot().getAbsolutePath(),
dbFolder.getRoot().getAbsolutePath(),
new RestoreOptions(false));
// Open database again.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Values must have suffix V2 because of restoring latest backup.
assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V2");
assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V2");
} finally {
if (bdb != null) {
bdb.close();
}
if (rdb != null) {
rdb.dispose();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void restoreFromBackup()
throws RocksDBException {
Options opt = null;
BackupableDBOptions bopt = null;
BackupableDB bdb = null;
RestoreBackupableDB rdb = null;
try {
opt = new Options().setCreateIfMissing(true);
bopt = new BackupableDBOptions(
backupFolder.getRoot().getAbsolutePath());
assertThat(bopt.backupDir()).isEqualTo(
backupFolder.getRoot().getAbsolutePath());
// Open empty database.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Fill database with some test values
prepareDatabase(bdb);
bdb.createNewBackup(true);
verifyNumberOfValidBackups(bdb, 1);
bdb.put("key1".getBytes(), "valueV2".getBytes());
bdb.put("key2".getBytes(), "valueV2".getBytes());
bdb.createNewBackup(true);
verifyNumberOfValidBackups(bdb, 2);
bdb.put("key1".getBytes(), "valueV3".getBytes());
bdb.put("key2".getBytes(), "valueV3".getBytes());
assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V3");
assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V3");
bdb.close();
// init RestoreBackupableDB
rdb = new RestoreBackupableDB(bopt);
List<BackupInfo> backupInfo = verifyNumberOfValidBackups(rdb, 2);
// restore db from first backup
rdb.restoreDBFromBackup(backupInfo.get(0).backupId(),
dbFolder.getRoot().getAbsolutePath(),
dbFolder.getRoot().getAbsolutePath(),
new RestoreOptions(false));
// Open database again.
bdb = BackupableDB.open(opt, bopt,
dbFolder.getRoot().getAbsolutePath());
// Values must have suffix V2 because of restoring latest backup.
assertThat(new String(bdb.get("key1".getBytes()))).endsWith("V1");
assertThat(new String(bdb.get("key2".getBytes()))).endsWith("V1");
} finally {
if (bdb != null) {
bdb.close();
}
if (rdb != null) {
rdb.dispose();
}
if (bopt != null) {
bopt.dispose();
}
if (opt != null) {
opt.dispose();
}
}
}
/**
* Verify backups.
*
* @param bdb {@link BackupableDB} instance.
* @param expectedNumberOfBackups numerical value
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
private List<BackupInfo> verifyNumberOfValidBackups(BackupableDB bdb,
int expectedNumberOfBackups) throws RocksDBException {
// Verify that backups exist
assertThat(bdb.getCorruptedBackups().length).
isEqualTo(0);
bdb.garbageCollect();
List<BackupInfo> backupInfo = bdb.getBackupInfos();
assertThat(backupInfo.size()).
isEqualTo(expectedNumberOfBackups);
return backupInfo;
}
/**
* Verify backups.
*
* @param rdb {@link RestoreBackupableDB} instance.
* @param expectedNumberOfBackups numerical value
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
private List<BackupInfo> verifyNumberOfValidBackups(
RestoreBackupableDB rdb, int expectedNumberOfBackups)
throws RocksDBException {
// Verify that backups exist
assertThat(rdb.getCorruptedBackups().length).
isEqualTo(0);
rdb.garbageCollect();
List<BackupInfo> backupInfo = rdb.getBackupInfos();
assertThat(backupInfo.size()).
isEqualTo(expectedNumberOfBackups);
return backupInfo;
}
/**
* Fill database with some test values.
*
* @param db {@link RocksDB} instance.
* @throws RocksDBException thrown if an error occurs within the native
* part of the library.
*/
private void prepareDatabase(RocksDB db)
throws RocksDBException {
db.put("key1".getBytes(), "valueV1".getBytes());
db.put("key2".getBytes(), "valueV1".getBytes());
}
}
@@ -5,43 +5,161 @@
package org.rocksdb.test;
import org.rocksdb.BlockBasedTableConfig;
import org.rocksdb.ChecksumType;
import org.rocksdb.IndexType;
import org.junit.ClassRule;
import org.junit.Test;
import org.rocksdb.*;
import static org.assertj.core.api.Assertions.assertThat;
public class BlockBasedTableConfigTest {
public static void main(String[] args) {
BlockBasedTableConfig blockBasedTableConfig =
new BlockBasedTableConfig();
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
@Test
public void noBlockCache() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setNoBlockCache(true);
assert(blockBasedTableConfig.noBlockCache());
blockBasedTableConfig.setBlockCacheSize(8*1024);
assert(blockBasedTableConfig.blockCacheSize() == (8*1024));
assertThat(blockBasedTableConfig.noBlockCache()).isTrue();
}
@Test
public void blockCacheSize() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockCacheSize(8 * 1024);
assertThat(blockBasedTableConfig.blockCacheSize()).
isEqualTo(8 * 1024);
}
@Test
public void blockSizeDeviation() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockSizeDeviation(12);
assert(blockBasedTableConfig.blockSizeDeviation() == 12);
assertThat(blockBasedTableConfig.blockSizeDeviation()).
isEqualTo(12);
}
@Test
public void blockRestartInterval() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockRestartInterval(15);
assert(blockBasedTableConfig.blockRestartInterval() == 15);
assertThat(blockBasedTableConfig.blockRestartInterval()).
isEqualTo(15);
}
@Test
public void wholeKeyFiltering() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setWholeKeyFiltering(false);
assert(!blockBasedTableConfig.wholeKeyFiltering());
assertThat(blockBasedTableConfig.wholeKeyFiltering()).
isFalse();
}
@Test
public void cacheIndexAndFilterBlocks() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setCacheIndexAndFilterBlocks(true);
assert(blockBasedTableConfig.cacheIndexAndFilterBlocks());
assertThat(blockBasedTableConfig.cacheIndexAndFilterBlocks()).
isTrue();
}
@Test
public void hashIndexAllowCollision() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setHashIndexAllowCollision(false);
assert(!blockBasedTableConfig.hashIndexAllowCollision());
assertThat(blockBasedTableConfig.hashIndexAllowCollision()).
isFalse();
}
@Test
public void blockCacheCompressedSize() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockCacheCompressedSize(40);
assert(blockBasedTableConfig.blockCacheCompressedSize() == 40);
assertThat(blockBasedTableConfig.blockCacheCompressedSize()).
isEqualTo(40);
}
@Test
public void checksumType() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
assertThat(ChecksumType.values().length).isEqualTo(3);
assertThat(ChecksumType.valueOf("kxxHash")).
isEqualTo(ChecksumType.kxxHash);
blockBasedTableConfig.setChecksumType(ChecksumType.kNoChecksum);
blockBasedTableConfig.setChecksumType(ChecksumType.kxxHash);
assert(blockBasedTableConfig.checksumType().equals(
assertThat(blockBasedTableConfig.checksumType().equals(
ChecksumType.kxxHash));
}
@Test
public void indexType() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
assertThat(IndexType.values().length).isEqualTo(2);
blockBasedTableConfig.setIndexType(IndexType.kHashSearch);
assert(blockBasedTableConfig.indexType().equals(
assertThat(blockBasedTableConfig.indexType().equals(
IndexType.kHashSearch));
assertThat(IndexType.valueOf("kBinarySearch")).isNotNull();
blockBasedTableConfig.setIndexType(IndexType.valueOf("kBinarySearch"));
assertThat(blockBasedTableConfig.indexType().equals(
IndexType.kBinarySearch));
}
@Test
public void blockCacheCompressedNumShardBits() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockCacheCompressedNumShardBits(4);
assert(blockBasedTableConfig.blockCacheCompressedNumShardBits()
== 4);
assertThat(blockBasedTableConfig.blockCacheCompressedNumShardBits()).
isEqualTo(4);
}
@Test
public void cacheNumShardBits() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setCacheNumShardBits(5);
assert(blockBasedTableConfig.cacheNumShardBits() == 5);
System.out.println("BlockBasedTableConfig test passed");
assertThat(blockBasedTableConfig.cacheNumShardBits()).
isEqualTo(5);
}
@Test
public void blockSize() {
BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockSize(10);
assertThat(blockBasedTableConfig.blockSize()).isEqualTo(10);
}
@Test
public void blockBasedTableWithFilter() {
Options options = null;
try {
options = new Options();
options.setTableFormatConfig(
new BlockBasedTableConfig().setFilter(
new BloomFilter(10)));
assertThat(options.tableFactoryName()).
isEqualTo("BlockBasedTable");
} finally {
if (options != null) {
options.dispose();
}
}
}
@Test
public void blockBasedTableWithoutFilter() {
Options options = null;
try {
options = new Options();
options.setTableFormatConfig(
new BlockBasedTableConfig().setFilter(null));
assertThat(options.tableFactoryName()).
isEqualTo("BlockBasedTable");
} finally {
if (options != null) {
options.dispose();
}
}
}
}
+101
View File
@@ -0,0 +1,101 @@
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rocksdb.Checkpoint;
import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import static org.assertj.core.api.Assertions.assertThat;
public class CheckPointTest {
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
@Rule
public TemporaryFolder dbFolder = new TemporaryFolder();
@Rule
public TemporaryFolder checkpointFolder = new TemporaryFolder();
@Test
public void checkPoint() throws RocksDBException {
RocksDB db = null;
Options options = null;
Checkpoint checkpoint = null;
try {
options = new Options().
setCreateIfMissing(true);
db = RocksDB.open(options,
dbFolder.getRoot().getAbsolutePath());
db.put("key".getBytes(), "value".getBytes());
checkpoint = Checkpoint.create(db);
checkpoint.createCheckpoint(checkpointFolder.
getRoot().getAbsolutePath() + "/snapshot1");
db.put("key2".getBytes(), "value2".getBytes());
checkpoint.createCheckpoint(checkpointFolder.
getRoot().getAbsolutePath() + "/snapshot2");
db.close();
db = RocksDB.open(options,
checkpointFolder.getRoot().getAbsolutePath() +
"/snapshot1");
assertThat(new String(db.get("key".getBytes()))).
isEqualTo("value");
assertThat(db.get("key2".getBytes())).isNull();
db.close();
db = RocksDB.open(options,
checkpointFolder.getRoot().getAbsolutePath() +
"/snapshot2");
assertThat(new String(db.get("key".getBytes()))).
isEqualTo("value");
assertThat(new String(db.get("key2".getBytes()))).
isEqualTo("value2");
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
if (checkpoint != null) {
checkpoint.dispose();
}
}
}
@Test(expected = IllegalArgumentException.class)
public void failIfDbIsNull() {
Checkpoint.create(null);
}
@Test(expected = IllegalStateException.class)
public void failIfDbNotInitialized() throws RocksDBException {
RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
db.dispose();
Checkpoint.create(db);
}
@Test(expected = RocksDBException.class)
public void failWithIllegalPath() throws RocksDBException {
RocksDB db = null;
Checkpoint checkpoint = null;
try {
db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
checkpoint = Checkpoint.create(db);
checkpoint.createCheckpoint("/Z:///:\\C:\\TZ/-");
} finally {
if (db != null) {
db.close();
}
if (checkpoint != null) {
checkpoint.dispose();
}
}
}
}
+520 -109
View File
@@ -5,225 +5,636 @@
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Test;
import org.rocksdb.*;
import java.util.Properties;
import java.util.Random;
public class ColumnFamilyOptionsTest {
static {
RocksDB.loadLibrary();
}
import static org.assertj.core.api.Assertions.assertThat;
public static void testCFOptions(ColumnFamilyOptionsInterface opt) {
Random rand = PlatformRandomHelper.
getPlatformSpecificRandomFactory();
{ // WriteBufferSize test
try {
long longValue = rand.nextLong();
opt.setWriteBufferSize(longValue);
assert(opt.writeBufferSize() == longValue);
} catch (RocksDBException e) {
assert(false);
public class ColumnFamilyOptionsTest {
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
public static final Random rand = PlatformRandomHelper.
getPlatformSpecificRandomFactory();
@Test
public void getColumnFamilyOptionsFromProps() {
ColumnFamilyOptions opt = null;
try {
// setup sample properties
Properties properties = new Properties();
properties.put("write_buffer_size", "112");
properties.put("max_write_buffer_number", "13");
opt = ColumnFamilyOptions.
getColumnFamilyOptionsFromProps(properties);
assertThat(opt).isNotNull();
assertThat(String.valueOf(opt.writeBufferSize())).
isEqualTo(properties.get("write_buffer_size"));
assertThat(String.valueOf(opt.maxWriteBufferNumber())).
isEqualTo(properties.get("max_write_buffer_number"));
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MaxWriteBufferNumber test
@Test
public void failColumnFamilyOptionsFromPropsWithIllegalValue() {
ColumnFamilyOptions opt = null;
try {
// setup sample properties
Properties properties = new Properties();
properties.put("tomato", "1024");
properties.put("burger", "2");
opt = ColumnFamilyOptions.
getColumnFamilyOptionsFromProps(properties);
assertThat(opt).isNull();
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test(expected = IllegalArgumentException.class)
public void failColumnFamilyOptionsFromPropsWithNullValue() {
ColumnFamilyOptions.getColumnFamilyOptionsFromProps(null);
}
@Test(expected = IllegalArgumentException.class)
public void failColumnFamilyOptionsFromPropsWithEmptyProps() {
ColumnFamilyOptions.getColumnFamilyOptionsFromProps(
new Properties());
}
@Test
public void writeBufferSize() throws RocksDBException {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
long longValue = rand.nextLong();
opt.setWriteBufferSize(longValue);
assertThat(opt.writeBufferSize()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void maxWriteBufferNumber() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setMaxWriteBufferNumber(intValue);
assert(opt.maxWriteBufferNumber() == intValue);
assertThat(opt.maxWriteBufferNumber()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MinWriteBufferNumberToMerge test
@Test
public void minWriteBufferNumberToMerge() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setMinWriteBufferNumberToMerge(intValue);
assert(opt.minWriteBufferNumberToMerge() == intValue);
assertThat(opt.minWriteBufferNumberToMerge()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // NumLevels test
@Test
public void numLevels() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setNumLevels(intValue);
assert(opt.numLevels() == intValue);
assertThat(opt.numLevels()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // LevelFileNumCompactionTrigger test
@Test
public void levelZeroFileNumCompactionTrigger() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setLevelZeroFileNumCompactionTrigger(intValue);
assert(opt.levelZeroFileNumCompactionTrigger() == intValue);
assertThat(opt.levelZeroFileNumCompactionTrigger()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // LevelSlowdownWritesTrigger test
@Test
public void levelZeroSlowdownWritesTrigger() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setLevelZeroSlowdownWritesTrigger(intValue);
assert(opt.levelZeroSlowdownWritesTrigger() == intValue);
assertThat(opt.levelZeroSlowdownWritesTrigger()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // LevelStopWritesTrigger test
@Test
public void levelZeroStopWritesTrigger() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setLevelZeroStopWritesTrigger(intValue);
assert(opt.levelZeroStopWritesTrigger() == intValue);
assertThat(opt.levelZeroStopWritesTrigger()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MaxMemCompactionLevel test
@Test
public void maxMemCompactionLevel() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setMaxMemCompactionLevel(intValue);
assert(opt.maxMemCompactionLevel() == intValue);
assertThat(opt.maxMemCompactionLevel()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // TargetFileSizeBase test
@Test
public void targetFileSizeBase() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
long longValue = rand.nextLong();
opt.setTargetFileSizeBase(longValue);
assert(opt.targetFileSizeBase() == longValue);
assertThat(opt.targetFileSizeBase()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // TargetFileSizeMultiplier test
@Test
public void targetFileSizeMultiplier() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setTargetFileSizeMultiplier(intValue);
assert(opt.targetFileSizeMultiplier() == intValue);
assertThat(opt.targetFileSizeMultiplier()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MaxBytesForLevelBase test
@Test
public void maxBytesForLevelBase() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
long longValue = rand.nextLong();
opt.setMaxBytesForLevelBase(longValue);
assert(opt.maxBytesForLevelBase() == longValue);
assertThat(opt.maxBytesForLevelBase()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MaxBytesForLevelMultiplier test
@Test
public void maxBytesForLevelMultiplier() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setMaxBytesForLevelMultiplier(intValue);
assert(opt.maxBytesForLevelMultiplier() == intValue);
assertThat(opt.maxBytesForLevelMultiplier()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // ExpandedCompactionFactor test
@Test
public void expandedCompactionFactor() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setExpandedCompactionFactor(intValue);
assert(opt.expandedCompactionFactor() == intValue);
assertThat(opt.expandedCompactionFactor()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // SourceCompactionFactor test
@Test
public void sourceCompactionFactor() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setSourceCompactionFactor(intValue);
assert(opt.sourceCompactionFactor() == intValue);
assertThat(opt.sourceCompactionFactor()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MaxGrandparentOverlapFactor test
@Test
public void maxGrandparentOverlapFactor() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setMaxGrandparentOverlapFactor(intValue);
assert(opt.maxGrandparentOverlapFactor() == intValue);
assertThat(opt.maxGrandparentOverlapFactor()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // SoftRateLimit test
@Test
public void softRateLimit() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
double doubleValue = rand.nextDouble();
opt.setSoftRateLimit(doubleValue);
assert(opt.softRateLimit() == doubleValue);
assertThat(opt.softRateLimit()).isEqualTo(doubleValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // HardRateLimit test
@Test
public void hardRateLimit() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
double doubleValue = rand.nextDouble();
opt.setHardRateLimit(doubleValue);
assert(opt.hardRateLimit() == doubleValue);
assertThat(opt.hardRateLimit()).isEqualTo(doubleValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // RateLimitDelayMaxMilliseconds test
@Test
public void rateLimitDelayMaxMilliseconds() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setRateLimitDelayMaxMilliseconds(intValue);
assert(opt.rateLimitDelayMaxMilliseconds() == intValue);
}
{ // ArenaBlockSize test
try {
long longValue = rand.nextLong();
opt.setArenaBlockSize(longValue);
assert(opt.arenaBlockSize() == longValue);
} catch (RocksDBException e) {
assert(false);
assertThat(opt.rateLimitDelayMaxMilliseconds()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // DisableAutoCompactions test
@Test
public void arenaBlockSize() throws RocksDBException {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
long longValue = rand.nextLong();
opt.setArenaBlockSize(longValue);
assertThat(opt.arenaBlockSize()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void disableAutoCompactions() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
boolean boolValue = rand.nextBoolean();
opt.setDisableAutoCompactions(boolValue);
assert(opt.disableAutoCompactions() == boolValue);
assertThat(opt.disableAutoCompactions()).isEqualTo(boolValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // PurgeRedundantKvsWhileFlush test
@Test
public void purgeRedundantKvsWhileFlush() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
boolean boolValue = rand.nextBoolean();
opt.setPurgeRedundantKvsWhileFlush(boolValue);
assert(opt.purgeRedundantKvsWhileFlush() == boolValue);
assertThat(opt.purgeRedundantKvsWhileFlush()).isEqualTo(boolValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // VerifyChecksumsInCompaction test
@Test
public void verifyChecksumsInCompaction() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
boolean boolValue = rand.nextBoolean();
opt.setVerifyChecksumsInCompaction(boolValue);
assert(opt.verifyChecksumsInCompaction() == boolValue);
assertThat(opt.verifyChecksumsInCompaction()).isEqualTo(boolValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // FilterDeletes test
@Test
public void filterDeletes() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
boolean boolValue = rand.nextBoolean();
opt.setFilterDeletes(boolValue);
assert(opt.filterDeletes() == boolValue);
assertThat(opt.filterDeletes()).isEqualTo(boolValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MaxSequentialSkipInIterations test
@Test
public void maxSequentialSkipInIterations() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
long longValue = rand.nextLong();
opt.setMaxSequentialSkipInIterations(longValue);
assert(opt.maxSequentialSkipInIterations() == longValue);
assertThat(opt.maxSequentialSkipInIterations()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // InplaceUpdateSupport test
@Test
public void inplaceUpdateSupport() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
boolean boolValue = rand.nextBoolean();
opt.setInplaceUpdateSupport(boolValue);
assert(opt.inplaceUpdateSupport() == boolValue);
}
{ // InplaceUpdateNumLocks test
try {
long longValue = rand.nextLong();
opt.setInplaceUpdateNumLocks(longValue);
assert(opt.inplaceUpdateNumLocks() == longValue);
} catch (RocksDBException e) {
assert(false);
assertThat(opt.inplaceUpdateSupport()).isEqualTo(boolValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MemtablePrefixBloomBits test
@Test
public void inplaceUpdateNumLocks() throws RocksDBException {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
long longValue = rand.nextLong();
opt.setInplaceUpdateNumLocks(longValue);
assertThat(opt.inplaceUpdateNumLocks()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void memtablePrefixBloomBits() {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
int intValue = rand.nextInt();
opt.setMemtablePrefixBloomBits(intValue);
assert(opt.memtablePrefixBloomBits() == intValue);
}
{ // MemtablePrefixBloomProbes test
int intValue = rand.nextInt();
opt.setMemtablePrefixBloomProbes(intValue);
assert(opt.memtablePrefixBloomProbes() == intValue);
}
{ // BloomLocality test
int intValue = rand.nextInt();
opt.setBloomLocality(intValue);
assert(opt.bloomLocality() == intValue);
}
{ // MaxSuccessiveMerges test
try {
long longValue = rand.nextLong();
opt.setMaxSuccessiveMerges(longValue);
assert(opt.maxSuccessiveMerges() == longValue);
} catch (RocksDBException e){
assert(false);
assertThat(opt.memtablePrefixBloomBits()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
{ // MinPartialMergeOperands test
@Test
public void memtablePrefixBloomProbes() {
ColumnFamilyOptions opt = null;
try {
int intValue = rand.nextInt();
opt.setMinPartialMergeOperands(intValue);
assert(opt.minPartialMergeOperands() == intValue);
opt = new ColumnFamilyOptions();
opt.setMemtablePrefixBloomProbes(intValue);
assertThat(opt.memtablePrefixBloomProbes()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
public static void main(String[] args) {
ColumnFamilyOptions opt = new ColumnFamilyOptions();
testCFOptions(opt);
opt.dispose();
System.out.println("Passed DBOptionsTest");
@Test
public void bloomLocality() {
ColumnFamilyOptions opt = null;
try {
int intValue = rand.nextInt();
opt = new ColumnFamilyOptions();
opt.setBloomLocality(intValue);
assertThat(opt.bloomLocality()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void maxSuccessiveMerges() throws RocksDBException {
ColumnFamilyOptions opt = null;
try {
long longValue = rand.nextLong();
opt = new ColumnFamilyOptions();
opt.setMaxSuccessiveMerges(longValue);
assertThat(opt.maxSuccessiveMerges()).isEqualTo(longValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void minPartialMergeOperands() {
ColumnFamilyOptions opt = null;
try {
int intValue = rand.nextInt();
opt = new ColumnFamilyOptions();
opt.setMinPartialMergeOperands(intValue);
assertThat(opt.minPartialMergeOperands()).isEqualTo(intValue);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void memTable() throws RocksDBException {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
opt.setMemTableConfig(new HashLinkedListMemTableConfig());
assertThat(opt.memTableFactoryName()).
isEqualTo("HashLinkedListRepFactory");
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void comparator() throws RocksDBException {
ColumnFamilyOptions opt = null;
try {
opt = new ColumnFamilyOptions();
opt.setComparator(BuiltinComparator.BYTEWISE_COMPARATOR);
} finally {
if (opt != null) {
opt.dispose();
}
}
}
@Test
public void linkageOfPrepMethods() {
ColumnFamilyOptions options = null;
try {
options = new ColumnFamilyOptions();
options.optimizeUniversalStyleCompaction();
options.optimizeUniversalStyleCompaction(4000);
options.optimizeLevelStyleCompaction();
options.optimizeLevelStyleCompaction(3000);
options.optimizeForPointLookup(10);
} finally {
if (options != null) {
options.dispose();
}
}
}
@Test
public void shouldSetTestPrefixExtractor() {
ColumnFamilyOptions options = null;
try {
options = new ColumnFamilyOptions();
options.useFixedLengthPrefixExtractor(100);
options.useFixedLengthPrefixExtractor(10);
} finally {
if (options != null) {
options.dispose();
}
}
}
@Test
public void compressionTypes() {
ColumnFamilyOptions ColumnFamilyOptions = null;
try {
ColumnFamilyOptions = new ColumnFamilyOptions();
for (CompressionType compressionType :
CompressionType.values()) {
ColumnFamilyOptions.setCompressionType(compressionType);
assertThat(ColumnFamilyOptions.compressionType()).
isEqualTo(compressionType);
assertThat(CompressionType.valueOf("NO_COMPRESSION")).
isEqualTo(CompressionType.NO_COMPRESSION);
}
} finally {
if (ColumnFamilyOptions != null) {
ColumnFamilyOptions.dispose();
}
}
}
@Test
public void compactionStyles() {
ColumnFamilyOptions ColumnFamilyOptions = null;
try {
ColumnFamilyOptions = new ColumnFamilyOptions();
for (CompactionStyle compactionStyle :
CompactionStyle.values()) {
ColumnFamilyOptions.setCompactionStyle(compactionStyle);
assertThat(ColumnFamilyOptions.compactionStyle()).
isEqualTo(compactionStyle);
assertThat(CompactionStyle.valueOf("FIFO")).
isEqualTo(CompactionStyle.FIFO);
}
} finally {
if (ColumnFamilyOptions != null) {
ColumnFamilyOptions.dispose();
}
}
}
}
+460 -181
View File
@@ -9,79 +9,104 @@ import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rocksdb.*;
import static org.assertj.core.api.Assertions.assertThat;
public class ColumnFamilyTest {
static final String db_path = "/tmp/rocksdbjni_columnfamily_test";
static {
RocksDB.loadLibrary();
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
@Rule
public TemporaryFolder dbFolder = new TemporaryFolder();
@Test
public void listColumnFamilies() throws RocksDBException {
RocksDB db = null;
Options options = null;
try {
options = new Options();
options.setCreateIfMissing(true);
DBOptions dbOptions = new DBOptions();
dbOptions.setCreateIfMissing(true);
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath());
// Test listColumnFamilies
List<byte[]> columnFamilyNames;
columnFamilyNames = RocksDB.listColumnFamilies(options, dbFolder.getRoot().getAbsolutePath());
assertThat(columnFamilyNames).isNotNull();
assertThat(columnFamilyNames.size()).isGreaterThan(0);
assertThat(columnFamilyNames.size()).isEqualTo(1);
assertThat(new String(columnFamilyNames.get(0))).isEqualTo("default");
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
public static void main(String[] args) {
@Test
public void createColumnFamily() throws RocksDBException {
RocksDB db = null;
Options options = new Options();
options.setCreateIfMissing(true);
DBOptions dbOptions = new DBOptions();
dbOptions.setCreateIfMissing(true);
Options options = null;
try {
db = RocksDB.open(options, db_path);
} catch (RocksDBException e) {
assert(false);
}
// Test listColumnFamilies
List<byte[]> columnFamilyNames;
try {
columnFamilyNames = RocksDB.listColumnFamilies(options, db_path);
if (columnFamilyNames != null && columnFamilyNames.size() > 0) {
assert(columnFamilyNames.size() == 1);
assert(new String(columnFamilyNames.get(0)).equals("default"));
} else {
assert(false);
}
} catch (RocksDBException e) {
assert(false);
}
options = new Options();
options.setCreateIfMissing(true);
// Test createColumnFamily
try {
DBOptions dbOptions = new DBOptions();
dbOptions.setCreateIfMissing(true);
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath());
db.createColumnFamily(new ColumnFamilyDescriptor("new_cf",
new ColumnFamilyOptions()));
} catch (RocksDBException e) {
assert(false);
}
if (db != null) {
db.close();
}
// Test listColumnFamilies after create "new_cf"
try {
columnFamilyNames = RocksDB.listColumnFamilies(options, db_path);
if (columnFamilyNames != null && columnFamilyNames.size() > 0) {
assert(columnFamilyNames.size() == 2);
assert(new String(columnFamilyNames.get(0)).equals("default"));
assert(new String(columnFamilyNames.get(1)).equals("new_cf"));
} else {
assert(false);
List<byte[]> columnFamilyNames;
columnFamilyNames = RocksDB.listColumnFamilies(options, dbFolder.getRoot().getAbsolutePath());
assertThat(columnFamilyNames).isNotNull();
assertThat(columnFamilyNames.size()).isGreaterThan(0);
assertThat(columnFamilyNames.size()).isEqualTo(2);
assertThat(new String(columnFamilyNames.get(0))).isEqualTo("default");
assertThat(new String(columnFamilyNames.get(1))).isEqualTo("new_cf");
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
} catch (RocksDBException e) {
assert(false);
}
}
// Test open database with column family names
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor("default"));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
@Test
public void openWithColumnFamilies() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
db = RocksDB.open(dbOptions, db_path, cfNames, columnFamilyHandleList);
assert(columnFamilyHandleList.size() == 2);
options = new DBOptions();
options.setCreateIfMissing(true);
options.setCreateMissingColumnFamilies(true);
// Test open database with column family names
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
assertThat(columnFamilyHandleList.size()).isEqualTo(2);
db.put("dfkey1".getBytes(), "dfvalue".getBytes());
db.put(columnFamilyHandleList.get(0), "dfkey2".getBytes(),
"dfvalue".getBytes());
@@ -90,57 +115,122 @@ public class ColumnFamilyTest {
String retVal = new String(db.get(columnFamilyHandleList.get(1),
"newcfkey1".getBytes()));
assert(retVal.equals("newcfvalue"));
assert( (db.get(columnFamilyHandleList.get(1),
"dfkey1".getBytes())) == null);
assertThat(retVal).isEqualTo("newcfvalue");
assertThat((db.get(columnFamilyHandleList.get(1),
"dfkey1".getBytes()))).isNull();
db.remove(columnFamilyHandleList.get(1), "newcfkey1".getBytes());
assert( (db.get(columnFamilyHandleList.get(1),
"newcfkey1".getBytes())) == null);
db.remove("dfkey2".getBytes());
assert( (db.get(columnFamilyHandleList.get(0),
"dfkey2".getBytes())) == null);
} catch (RocksDBException e) {
assert(false);
assertThat((db.get(columnFamilyHandleList.get(1),
"newcfkey1".getBytes()))).isNull();
db.remove(columnFamilyHandleList.get(0), new WriteOptions(),
"dfkey2".getBytes());
assertThat(db.get(columnFamilyHandleList.get(0), new ReadOptions(),
"dfkey2".getBytes())).isNull();
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
// Test create write to and drop ColumnFamily
@Test
public void getWithOutValueAndCf() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
options = new DBOptions();
options.setCreateIfMissing(true);
options.setCreateMissingColumnFamilies(true);
// Test open database with column family names
List<ColumnFamilyDescriptor> cfDescriptors =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfDescriptors.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfDescriptors, columnFamilyHandleList);
db.put(columnFamilyHandleList.get(0), new WriteOptions(),
"key1".getBytes(), "value".getBytes());
db.put("key2".getBytes(), "12345678".getBytes());
byte[] outValue = new byte[5];
// not found value
int getResult = db.get("keyNotFound".getBytes(), outValue);
assertThat(getResult).isEqualTo(RocksDB.NOT_FOUND);
// found value which fits in outValue
getResult = db.get(columnFamilyHandleList.get(0), "key1".getBytes(), outValue);
assertThat(getResult).isNotEqualTo(RocksDB.NOT_FOUND);
assertThat(outValue).isEqualTo("value".getBytes());
// found value which fits partially
getResult = db.get(columnFamilyHandleList.get(0), new ReadOptions(),
"key2".getBytes(), outValue);
assertThat(getResult).isNotEqualTo(RocksDB.NOT_FOUND);
assertThat(outValue).isEqualTo("12345".getBytes());
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test
public void createWriteDropColumnFamily() throws RocksDBException {
RocksDB db = null;
DBOptions opt = null;
ColumnFamilyHandle tmpColumnFamilyHandle = null;
try {
opt = new DBOptions();
opt.setCreateIfMissing(true);
opt.setCreateMissingColumnFamilies(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(opt, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
tmpColumnFamilyHandle = db.createColumnFamily(
new ColumnFamilyDescriptor("tmpCF", new ColumnFamilyOptions()));
db.put(tmpColumnFamilyHandle, "key".getBytes(), "value".getBytes());
db.dropColumnFamily(tmpColumnFamilyHandle);
tmpColumnFamilyHandle.dispose();
} catch (Exception e) {
assert(false);
} finally {
if (tmpColumnFamilyHandle != null) {
tmpColumnFamilyHandle.dispose();
}
if (db != null) {
db.close();
}
if (opt != null) {
opt.dispose();
}
}
}
// Put to disposed column family tmpColumnFamilyHandle must fail
@Test
public void writeBatch() throws RocksDBException {
RocksDB db = null;
DBOptions opt = null;
try {
db.put(tmpColumnFamilyHandle, "key".getBytes(), "value".getBytes());
assert(false);
} catch (RocksDBException e) {
assert(true);
}
opt = new DBOptions();
opt.setCreateIfMissing(true);
opt.setCreateMissingColumnFamilies(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
// Remove to disposed column family tmpColumnFamilyHandle must fail
try {
db.remove(tmpColumnFamilyHandle, "key".getBytes());
assert(false);
} catch (RocksDBException e) {
assert(true);
}
db = RocksDB.open(opt, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
// Get on a disposed column family tmpColumnFamilyHandle must fail
try {
db.get(tmpColumnFamilyHandle, "key".getBytes());
assert(false);
} catch (RocksDBException e) {
assert(true);
}
// Test WriteBatch
try {
WriteBatch writeBatch = new WriteBatch();
WriteOptions writeOpt = new WriteOptions();
writeBatch.put("key".getBytes(), "value".getBytes());
@@ -152,136 +242,325 @@ public class ColumnFamilyTest {
writeBatch.remove(columnFamilyHandleList.get(1), "xyz".getBytes());
db.write(writeOpt, writeBatch);
writeBatch.dispose();
assert(db.get(columnFamilyHandleList.get(1),
assertThat(db.get(columnFamilyHandleList.get(1),
"xyz".getBytes()) == null);
assert(new String(db.get(columnFamilyHandleList.get(1),
"newcfkey".getBytes())).equals("value"));
assert(new String(db.get(columnFamilyHandleList.get(1),
"newcfkey2".getBytes())).equals("value2"));
assert(new String(db.get("key".getBytes())).equals("value"));
} catch (Exception e) {
e.printStackTrace();
assert(false);
assertThat(new String(db.get(columnFamilyHandleList.get(1),
"newcfkey".getBytes()))).isEqualTo("value");
assertThat(new String(db.get(columnFamilyHandleList.get(1),
"newcfkey2".getBytes()))).isEqualTo("value2");
assertThat(new String(db.get("key".getBytes()))).isEqualTo("value");
} finally {
if (db != null) {
db.close();
}
if (opt != null) {
opt.dispose();
}
}
}
// Test iterator on column family
@Test
public void iteratorOnColumnFamily() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
RocksIterator rocksIterator = null;
try {
RocksIterator rocksIterator = db.newIterator(
options = new DBOptions();
options.setCreateIfMissing(true);
options.setCreateMissingColumnFamilies(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
db.put(columnFamilyHandleList.get(1), "newcfkey".getBytes(),
"value".getBytes());
db.put(columnFamilyHandleList.get(1), "newcfkey2".getBytes(),
"value2".getBytes());
rocksIterator = db.newIterator(
columnFamilyHandleList.get(1));
rocksIterator.seekToFirst();
Map<String, String> refMap = new HashMap<String, String>();
Map<String, String> refMap = new HashMap<>();
refMap.put("newcfkey", "value");
refMap.put("newcfkey2", "value2");
int i = 0;
while(rocksIterator.isValid()) {
while (rocksIterator.isValid()) {
i++;
refMap.get(new String(rocksIterator.key())).equals(
new String(rocksIterator.value()));
assertThat(refMap.get(new String(rocksIterator.key()))).
isEqualTo(new String(rocksIterator.value()));
rocksIterator.next();
}
assert(i == 2);
assertThat(i).isEqualTo(2);
rocksIterator.dispose();
} catch(Exception e) {
assert(false);
} finally {
if (rocksIterator != null) {
rocksIterator.dispose();
}
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
// Test property handling on column families
@Test
public void multiGet() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
assert(db.getProperty("rocksdb.estimate-num-keys") != null);
assert(db.getProperty("rocksdb.stats") != null);
assert(db.getProperty(columnFamilyHandleList.get(0),
"rocksdb.sstables") != null);
assert(db.getProperty(columnFamilyHandleList.get(1),
"rocksdb.estimate-num-keys") != null);
assert(db.getProperty(columnFamilyHandleList.get(1),
"rocksdb.stats") != null);
assert(db.getProperty(columnFamilyHandleList.get(1),
"rocksdb.sstables") != null);
} catch(Exception e) {
assert(false);
}
options = new DBOptions();
options.setCreateIfMissing(true);
options.setCreateMissingColumnFamilies(true);
List<ColumnFamilyDescriptor> cfDescriptors =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfDescriptors.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfDescriptors.add(new ColumnFamilyDescriptor("new_cf"));
// MultiGet test
List<ColumnFamilyHandle> cfCustomList = new ArrayList<ColumnFamilyHandle>();
try {
List<byte[]> keys = new ArrayList<byte[]>();
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfDescriptors, columnFamilyHandleList);
db.put(columnFamilyHandleList.get(0), "key".getBytes(), "value".getBytes());
db.put(columnFamilyHandleList.get(1), "newcfkey".getBytes(), "value".getBytes());
List<byte[]> keys = new ArrayList<>();
keys.add("key".getBytes());
keys.add("newcfkey".getBytes());
Map<byte[], byte[]> retValues = db.multiGet(columnFamilyHandleList,keys);
assert(retValues.size() == 2);
assert(new String(retValues.get(keys.get(0)))
.equals("value"));
assert(new String(retValues.get(keys.get(1)))
.equals("value"));
cfCustomList.add(columnFamilyHandleList.get(0));
cfCustomList.add(columnFamilyHandleList.get(0));
retValues = db.multiGet(cfCustomList, keys);
assert(retValues.size() == 1);
assert(new String(retValues.get(keys.get(0)))
.equals("value"));
} catch (RocksDBException e) {
assert(false);
Map<byte[], byte[]> retValues = db.multiGet(columnFamilyHandleList, keys);
assertThat(retValues.size()).isEqualTo(2);
assertThat(new String(retValues.get(keys.get(0))))
.isEqualTo("value");
assertThat(new String(retValues.get(keys.get(1))))
.isEqualTo("value");
retValues = db.multiGet(new ReadOptions(), columnFamilyHandleList, keys);
assertThat(retValues.size()).isEqualTo(2);
assertThat(new String(retValues.get(keys.get(0))))
.isEqualTo("value");
assertThat(new String(retValues.get(keys.get(1))))
.isEqualTo("value");
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
// Test multiget without correct number of column
// families
@Test
public void properties() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
List<byte[]> keys = new ArrayList<byte[]>();
keys.add("key".getBytes());
keys.add("newcfkey".getBytes());
cfCustomList.remove(1);
db.multiGet(cfCustomList, keys);
assert(false);
} catch (RocksDBException e) {
assert(false);
} catch (IllegalArgumentException e) {
assert(true);
options = new DBOptions();
options.setCreateIfMissing(true);
options.setCreateMissingColumnFamilies(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
assertThat(db.getProperty("rocksdb.estimate-num-keys")).
isNotNull();
assertThat(db.getLongProperty(columnFamilyHandleList.get(0),
"rocksdb.estimate-num-keys")).isGreaterThanOrEqualTo(0);
assertThat(db.getProperty("rocksdb.stats")).isNotNull();
assertThat(db.getProperty(columnFamilyHandleList.get(0),
"rocksdb.sstables")).isNotNull();
assertThat(db.getProperty(columnFamilyHandleList.get(1),
"rocksdb.estimate-num-keys")).isNotNull();
assertThat(db.getProperty(columnFamilyHandleList.get(1),
"rocksdb.stats")).isNotNull();
assertThat(db.getProperty(columnFamilyHandleList.get(1),
"rocksdb.sstables")).isNotNull();
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test
public void iterators() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
// iterate over default key/value pairs
options = new DBOptions();
options.setCreateIfMissing(true);
options.setCreateMissingColumnFamilies(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
List<RocksIterator> iterators =
db.newIterators(columnFamilyHandleList);
assert(iterators.size() == 2);
assertThat(iterators.size()).isEqualTo(2);
RocksIterator iter = iterators.get(0);
iter.seekToFirst();
Map<String,String> defRefMap = new HashMap<String, String>();
Map<String, String> defRefMap = new HashMap<>();
defRefMap.put("dfkey1", "dfvalue");
defRefMap.put("key", "value");
while (iter.isValid()) {
defRefMap.get(new String(iter.key())).equals(
new String(iter.value()));
assertThat(defRefMap.get(new String(iter.key()))).
isEqualTo(new String(iter.value()));
iter.next();
}
// iterate over new_cf key/value pairs
Map<String,String> cfRefMap = new HashMap<String, String>();
Map<String, String> cfRefMap = new HashMap<>();
cfRefMap.put("newcfkey", "value");
cfRefMap.put("newcfkey2", "value2");
iter = iterators.get(1);
iter.seekToFirst();
while (iter.isValid()) {
cfRefMap.get(new String(iter.key())).equals(
new String(iter.value()));
assertThat(cfRefMap.get(new String(iter.key()))).
isEqualTo(new String(iter.value()));
iter.next();
}
// free iterators
for (RocksIterator iterator : iterators) {
iterator.dispose();
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
assert(true);
} catch (RocksDBException e) {
assert(false);
}
System.out.println("Passed ColumnFamilyTest");
// free cf handles before database close
for (ColumnFamilyHandle columnFamilyHandle : columnFamilyHandleList) {
columnFamilyHandle.dispose();
}
// close database
db.close();
// be sure to dispose c++ pointers
options.dispose();
}
@Test(expected = RocksDBException.class)
public void failPutDisposedCF() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
options = new DBOptions();
options.setCreateIfMissing(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
db.dropColumnFamily(columnFamilyHandleList.get(1));
db.put(columnFamilyHandleList.get(1), "key".getBytes(), "value".getBytes());
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test(expected = RocksDBException.class)
public void failRemoveDisposedCF() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
options = new DBOptions();
options.setCreateIfMissing(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
db.dropColumnFamily(columnFamilyHandleList.get(1));
db.remove(columnFamilyHandleList.get(1), "key".getBytes());
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test(expected = RocksDBException.class)
public void failGetDisposedCF() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
options = new DBOptions();
options.setCreateIfMissing(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
db.dropColumnFamily(columnFamilyHandleList.get(1));
db.get(columnFamilyHandleList.get(1), "key".getBytes());
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test(expected = RocksDBException.class)
public void failMultiGetWithoutCorrectNumberOfCF() throws RocksDBException {
RocksDB db = null;
DBOptions options = null;
try {
options = new DBOptions();
options.setCreateIfMissing(true);
List<ColumnFamilyDescriptor> cfNames =
new ArrayList<>();
List<ColumnFamilyHandle> columnFamilyHandleList =
new ArrayList<>();
cfNames.add(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY));
cfNames.add(new ColumnFamilyDescriptor("new_cf"));
db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath(),
cfNames, columnFamilyHandleList);
List<byte[]> keys = new ArrayList<>();
keys.add("key".getBytes());
keys.add("newcfkey".getBytes());
List<ColumnFamilyHandle> cfCustomList = new ArrayList<>();
db.multiGet(cfCustomList, keys);
} finally {
if (db != null) {
db.close();
}
if (options != null) {
options.dispose();
}
}
}
}
@@ -5,30 +5,32 @@
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Test;
import org.rocksdb.ComparatorOptions;
import org.rocksdb.RocksDB;
import java.util.Random;
import static org.assertj.core.api.Assertions.assertThat;
public class ComparatorOptionsTest {
static {
RocksDB.loadLibrary();
}
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
public static void main(String[] args) {
@Test
public void comparatorOptions() {
final ComparatorOptions copt = new ComparatorOptions();
Random rand = new Random();
assertThat(copt).isNotNull();
{ // UseAdaptiveMutex test
copt.setUseAdaptiveMutex(true);
assert(copt.useAdaptiveMutex() == true);
assertThat(copt.useAdaptiveMutex()).isTrue();
copt.setUseAdaptiveMutex(false);
assert(copt.useAdaptiveMutex() == false);
assertThat(copt.useAdaptiveMutex()).isFalse();
}
copt.dispose();
System.out.println("Passed ComparatorOptionsTest");
}
}
+190 -7
View File
@@ -5,19 +5,28 @@
package org.rocksdb.test;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.rocksdb.*;
import java.io.IOException;
import java.nio.file.FileSystems;
import static org.assertj.core.api.Assertions.assertThat;
public class ComparatorTest {
private static final String db_path = "/tmp/comparator_db";
static {
RocksDB.loadLibrary();
}
@ClassRule
public static final RocksMemoryResource rocksMemoryResource =
new RocksMemoryResource();
public static void main(String[] args) throws IOException {
@Rule
public TemporaryFolder dbFolder = new TemporaryFolder();
@Test
public void javaComparator() throws IOException, RocksDBException {
final AbstractComparatorTest comparatorTest = new AbstractComparatorTest() {
@Override
@@ -38,8 +47,182 @@ public class ComparatorTest {
};
// test the round-tripability of keys written and read with the Comparator
comparatorTest.testRoundtrip(FileSystems.getDefault().getPath(db_path));
comparatorTest.testRoundtrip(FileSystems.getDefault().getPath(
dbFolder.getRoot().getAbsolutePath()));
}
System.out.println("Passed ComparatorTest");
@Test
public void javaComparatorCf() throws IOException, RocksDBException {
final AbstractComparatorTest comparatorTest = new AbstractComparatorTest() {
@Override
public AbstractComparator getAscendingIntKeyComparator() {
return new Comparator(new ComparatorOptions()) {
@Override
public String name() {
return "test.AscendingIntKeyComparator";
}
@Override
public int compare(final Slice a, final Slice b) {
return compareIntKeys(a.data(), b.data());
}
};
}
};
// test the round-tripability of keys written and read with the Comparator
comparatorTest.testRoundtripCf(FileSystems.getDefault().getPath(
dbFolder.getRoot().getAbsolutePath()));
}
@Test
public void builtinForwardComparator()
throws RocksDBException {
Options options = null;
RocksDB rocksDB = null;
RocksIterator rocksIterator = null;
try {
options = new Options();
options.setCreateIfMissing(true);
options.setComparator(BuiltinComparator.BYTEWISE_COMPARATOR);
rocksDB = RocksDB.open(options,
dbFolder.getRoot().getAbsolutePath());
rocksDB.put("abc1".getBytes(), "abc1".getBytes());
rocksDB.put("abc2".getBytes(), "abc2".getBytes());
rocksDB.put("abc3".getBytes(), "abc3".getBytes());
rocksIterator = rocksDB.newIterator();
// Iterate over keys using a iterator
rocksIterator.seekToFirst();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc1".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc1".getBytes());
rocksIterator.next();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc2".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc2".getBytes());
rocksIterator.next();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc3".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc3".getBytes());
rocksIterator.next();
assertThat(rocksIterator.isValid()).isFalse();
// Get last one
rocksIterator.seekToLast();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc3".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc3".getBytes());
// Seek for abc
rocksIterator.seek("abc".getBytes());
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc1".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc1".getBytes());
} finally {
if (rocksIterator != null) {
rocksIterator.dispose();
}
if (rocksDB != null) {
rocksDB.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test
public void builtinReverseComparator()
throws RocksDBException {
Options options = null;
RocksDB rocksDB = null;
RocksIterator rocksIterator = null;
try {
options = new Options();
options.setCreateIfMissing(true);
options.setComparator(
BuiltinComparator.REVERSE_BYTEWISE_COMPARATOR);
rocksDB = RocksDB.open(options,
dbFolder.getRoot().getAbsolutePath());
rocksDB.put("abc1".getBytes(), "abc1".getBytes());
rocksDB.put("abc2".getBytes(), "abc2".getBytes());
rocksDB.put("abc3".getBytes(), "abc3".getBytes());
rocksIterator = rocksDB.newIterator();
// Iterate over keys using a iterator
rocksIterator.seekToFirst();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc3".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc3".getBytes());
rocksIterator.next();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc2".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc2".getBytes());
rocksIterator.next();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc1".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc1".getBytes());
rocksIterator.next();
assertThat(rocksIterator.isValid()).isFalse();
// Get last one
rocksIterator.seekToLast();
assertThat(rocksIterator.isValid()).isTrue();
assertThat(rocksIterator.key()).isEqualTo(
"abc1".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc1".getBytes());
// Will be invalid because abc is after abc1
rocksIterator.seek("abc".getBytes());
assertThat(rocksIterator.isValid()).isFalse();
// Will be abc3 because the next one after abc999
// is abc3
rocksIterator.seek("abc999".getBytes());
assertThat(rocksIterator.key()).isEqualTo(
"abc3".getBytes());
assertThat(rocksIterator.value()).isEqualTo(
"abc3".getBytes());
} finally {
if (rocksIterator != null) {
rocksIterator.dispose();
}
if (rocksDB != null) {
rocksDB.close();
}
if (options != null) {
options.dispose();
}
}
}
@Test
public void builtinComparatorEnum(){
assertThat(BuiltinComparator.BYTEWISE_COMPARATOR.ordinal())
.isEqualTo(0);
assertThat(
BuiltinComparator.REVERSE_BYTEWISE_COMPARATOR.ordinal())
.isEqualTo(1);
assertThat(BuiltinComparator.values().length).isEqualTo(2);
assertThat(BuiltinComparator.valueOf("BYTEWISE_COMPARATOR")).
isEqualTo(BuiltinComparator.BYTEWISE_COMPARATOR);
}
}
@@ -0,0 +1,22 @@
// Copyright (c) 2014, 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.
package org.rocksdb.test;
import org.junit.Test;
import org.rocksdb.CompressionType;
public class CompressionOptionsTest
{
@Test
public void getCompressionType() {
for (CompressionType compressionType : CompressionType.values()) {
String libraryName = compressionType.getLibraryName();
compressionType.equals(CompressionType.getCompressionType(
libraryName));
}
}
}

Some files were not shown because too many files have changed in this diff Show More