Compare commits

..
Author SHA1 Message Date
Adam Retter 428d713260 Fix an issue with unnecessary capture in lambda expressions
Closes https://github.com/facebook/rocksdb/issues/3900
2018-05-25 16:27:17 +02:00
Yi Wu 7a99c04311 refactor constructor of LRUCacheShard
Summary:
Update LRUCacheShard constructor so that adding new params to it don't need to add extra SetXXX() methods.
Closes https://github.com/facebook/rocksdb/pull/3896

Differential Revision: D8128618

Pulled By: yiwu-arbug

fbshipit-source-id: 6afa715de1493a50de413678761a765e3af9b83b
2018-05-23 18:57:42 -07:00
Andrew Kryczka 01bcc34896 Introduce library-independent default compression level
Summary:
Previously we were using -1 as the default for every library, which was legacy from our zlib options. That worked for a while, but after zstd introduced https://github.com/facebook/zstd/commit/a146ee04ae5866b948be0c1911418e0436d80cb4, it started giving poor compression ratios by default in zstd.

This PR adds a constant to RocksDB public API, `CompressionOptions::kDefaultCompressionLevel`, which will get translated to the default value specific to the compression library being used in "util/compression.h". The constant uses a number that appears to be larger than any library's maximum compression level.
Closes https://github.com/facebook/rocksdb/pull/3895

Differential Revision: D8125780

Pulled By: ajkr

fbshipit-source-id: 2db157a89118cd4f94577c2f4a0a5ff31c8391c6
2018-05-23 18:42:08 -07:00
Yanqin Jin 4011012d9d Specify the underlying type of enums.
Summary:
Explicitly specify the underlying type of enums help developers understand the physical storage.
Closes https://github.com/facebook/rocksdb/pull/3892

Differential Revision: D8107027

Pulled By: riversand963

fbshipit-source-id: a00efecbba46df4a3c8eed0994a2d4972ad1a1d3
2018-05-23 16:12:59 -07:00
Zhongyi Xie 6c73a46693 Fix a backward compatibility problem with table_properties being nullptr
Summary:
Currently when ldb built from master tries to open a DB from version 2.2, there will be a segfault because table_properties didn't exist back then.
Closes https://github.com/facebook/rocksdb/pull/3890

Differential Revision: D8100914

Pulled By: miasantreble

fbshipit-source-id: b255e8aedc54695432be2e704839c857dabdd65a
2018-05-22 13:57:17 -07:00
Jacquin Mininger 4420cb49da Fix Issue #3771: Slice ctor checks for nullptr and creates empty string
Summary:
Fix Issue #3771   : Check for nullptr in Slice constructor
Slice ctor checks for nullptr and creates empty string if the string does not exist
Closes https://github.com/facebook/rocksdb/pull/3887

Differential Revision: D8098852

Pulled By: ajkr

fbshipit-source-id: 04471077defa9776ce7b8c389a61312ce31002fb
2018-05-22 13:41:56 -07:00
Andrew Kryczka 7db721b9a6 Avoid sleep in DBTest.GroupCommitTest to fix flakiness
Summary:
DBTest.GroupCommitTest would often fail when run under valgrind because its sleeps were insufficient to guarantee a group commit had multiple entries. Instead we can use sync point to force a leader to wait until a non-leader thread has enqueued its work, thus guaranteeing a leader can do group commit work for multiple threads.
Closes https://github.com/facebook/rocksdb/pull/3883

Differential Revision: D8079429

Pulled By: ajkr

fbshipit-source-id: 61dc50fad29d2c85547842f681288de60fa29049
2018-05-22 12:16:25 -07:00
Andrew Kryczka fcb31016e9 Avoid single-deleting merge operands in db_stress
Summary:
I repro'd some of the "unexpected value" failures showing up in our CI lately and they always happened on keys that have a mix of single deletes and merge operands. The `SingleDelete()` API comment mentions it's incompatible with `Merge()`, so this PR prevents `db_stress` from mixing them.
Closes https://github.com/facebook/rocksdb/pull/3878

Differential Revision: D8097346

Pulled By: ajkr

fbshipit-source-id: 357a48c6a31156f4f8db3ce565638ad924c437a1
2018-05-22 10:58:36 -07:00
Siying Dong 3db1ada3bf PersistRocksDBOptions() to use WritableFileWriter
Summary:
By using WritableFileWriter rather than WritableFile directly, we can buffer multiple Append() calls to one write() file system call, which will be expensive to underlying Env without its own write buffering.
Closes https://github.com/facebook/rocksdb/pull/3882

Differential Revision: D8080673

Pulled By: siying

fbshipit-source-id: e0db900cb3c178166aa738f3985db65e3ae2cf1b
2018-05-21 16:42:22 -07:00
Zhongyi Xie c3ebc75843 Move prefix_extractor to MutableCFOptions
Summary:
Currently it is not possible to change bloom filter config without restart the db, which is causing a lot of operational complexity for users.
This PR aims to make it possible to dynamically change bloom filter config.
Closes https://github.com/facebook/rocksdb/pull/3601

Differential Revision: D7253114

Pulled By: miasantreble

fbshipit-source-id: f22595437d3e0b86c95918c484502de2ceca120c
2018-05-21 14:43:11 -07:00
Yanqin Jin 263ef52b65 Update ColumnFamilyTest for multi-CF verification
Summary:
Change `keys_` from `set<string>` to `vector<set<string>>` so that each column
family's keys are stored in one set.

ajkr When you have a chance, can you PTAL? Thanks!
Closes https://github.com/facebook/rocksdb/pull/3871

Differential Revision: D8056447

Pulled By: riversand963

fbshipit-source-id: 650d0f9cad02b1bc005fc329ad76edbf053e6386
2018-05-21 11:57:42 -07:00
Andrew Kryczka 508a09fd62 Print histogram count and sum in statistics string
Summary:
Previously it only printed percentiles, even though our histogram keeps track of count and sum (and more). There have been many times we want to know more than the percentiles. For example, we currently want sum of "rocksdb.compression.times.nanos" and sum of "rocksdb.decompression.times.nanos", which would allow us to know the relative cost of compression vs decompression.

This PR adds count and sum to the string printed by `StatisticsImpl::ToString`. This is a bit risky as there are definitely parsers assuming the old format. I will mention it in HISTORY.md and hope for the best...
Closes https://github.com/facebook/rocksdb/pull/3863

Differential Revision: D8038831

Pulled By: ajkr

fbshipit-source-id: 0465b72e4b0cbf18ef965f4efe402601d16d5b5c
2018-05-21 11:12:47 -07:00
Andrew Kryczka 7b655214d2 Assert keys/values pinned by range deletion meta-block iterators
Summary:
`RangeDelAggregator` holds the pointers returned by `BlockIter::key()` and `BlockIter::value()` so requires the data to which they point is pinned. `BlockIter::key()` points into block memory and is guaranteed to be pinned if and only if prefix encoding is disabled (or, equivalently, restart interval is set to one). I think `BlockIter::value()` is always pinned. Added an assert for these and removed the wrong TODO about increasing restart interval, which would enable key prefix encoding and break the assertion.
Closes https://github.com/facebook/rocksdb/pull/3875

Differential Revision: D8063667

Pulled By: ajkr

fbshipit-source-id: 60b5ebcc0cdd610dd6aad9e74a23378793672c41
2018-05-21 09:57:00 -07:00
Andrew Kryczka e410501eeb Add missing test files to src.mk
Summary:
We only generate the header dependency (".cc.d") files for files mentioned in "src.mk". When we don't generate them, changes to header dependencies do not cause `make` to recompile the dependent ".o". Then it takes a while for developers (or maybe just me) to realize `make clean` is necessary.
Closes https://github.com/facebook/rocksdb/pull/3876

Differential Revision: D8065389

Pulled By: ajkr

fbshipit-source-id: 0f62eee7bcab15b0215791564e6ab3775d46996b
2018-05-21 09:43:29 -07:00
Zhongyi Xie ed4d3393fb fix a division by zero bug
Summary:
fixes the failing clang_analyze contrun test
Closes https://github.com/facebook/rocksdb/pull/3872

Differential Revision: D8059241

Pulled By: miasantreble

fbshipit-source-id: e8fc1838004fe16a823456188386b8b39429803b
2018-05-18 21:57:24 -07:00
Siying Dong 26da3676d9 class Block to store num_restarts_
Summary:
Right now, every Block::NewIterator() reads num_restarts_ from the block, which is already read in Block::Block(). This sometimes cause a CPU cache miss. Although fetching this cacheline can usually benefit follow-up block restart offset reading, as they are close to each other, it's almost free to get ride of this read by storing it in the Block class.
Closes https://github.com/facebook/rocksdb/pull/3869

Differential Revision: D8052493

Pulled By: siying

fbshipit-source-id: 9c72360f0c2d7329f3c198ce4eaedd2bc14b87c1
2018-05-18 12:56:55 -07:00
Yanqin Jin a0c7b4d526 Set the default value of max_manifest_file_size.
Summary:
In the past, the default value of max_manifest_file_size is uint64_t::MAX,
allowing a long running RocksDB process to grow its MANIFEST file to take up
the entire disk, as reported in [issue 3851](https://github.com/facebook/rocksdb/issues/3851). It is reasonable and common to provide a default non-max value for this option. Therefore, I set the value to 1GB.

siying miasantreble Please let me know whether this looks good to you. Thanks!
Closes https://github.com/facebook/rocksdb/pull/3867

Differential Revision: D8051524

Pulled By: riversand963

fbshipit-source-id: 50251f0804b1fa933a19a30d19d261ea8b9d2b72
2018-05-18 08:11:55 -07:00
Siying Dong 17af09fcce Implement key shortening functions in ReverseBytewiseComparator
Summary:
Right now ReverseBytewiseComparator::FindShortestSeparator() doesn't really shorten key, and ReverseBytewiseComparator::FindShortestSuccessor() seems to return wrong results. The code is confusing too as it uses BytewiseComparatorImpl::FindShortestSeparator() but the function actually won't do anything if the the first key is larger than the second.

Implement ReverseBytewiseComparator::FindShortestSeparator() and override ReverseBytewiseComparator::FindShortestSuccessor() to be empty.
Closes https://github.com/facebook/rocksdb/pull/3836

Differential Revision: D7959762

Pulled By: siying

fbshipit-source-id: 93acb621c16ce6f23e087ae4e19f7d84d1254683
2018-05-17 18:27:16 -07:00
Zhongyi Xie 1d7ca20f29 add override to virtual functions
Summary:
this will fix the failing clang_check test
Closes https://github.com/facebook/rocksdb/pull/3868

Differential Revision: D8050880

Pulled By: miasantreble

fbshipit-source-id: 749932e2e4025f835c961c068d601e522a126da6
2018-05-17 17:57:48 -07:00
Xin Tong aed7abbcca Reorder field based on esan data
Summary:
Running. TEST_TMPDIR=/dev/shm ./buck-out/gen/rocks/tools/rocks_db_bench --benchmarks=readwhilewriting --num=5000000 -benchmark_write_rate_limit=2000000 --threads=32

Collected esan data and reorder field. Accesses to 4th and 6th fields take majority of the access.  Group them. Overall, this struct takes 10%+ of the total accesses in the program. (637773011/6107964986)

==2433831==  class rocksdb::InlineSkipList
==2433831==   size = 48, count = 637773011, ratio = 112412, array access = 0
==2433831==   # 0: offset = 0,   size = 2,       count = 455137, type = i16
==2433831==   # 1: offset = 2,   size = 2,       count = 6,      type = i16
==2433831==   # 2: offset = 4,   size = 4,       count = 182303, type = i32
==2433831==   # 3: offset = 8,   size = 8,       count = 263953900, type = %"class.rocksdb::MemTableRep::KeyComparator"*
==2433831==   # 4: offset = 16,  size = 8,       count = 136409, type = %"class.rocksdb::Allocator"*
==2433831==   # 5: offset = 24,  size = 8,       count = 366628820, type = %"struct.rocksdb::InlineSkipList<const rocksdb::MemTableRep::KeyComparator &>::Node"*
==2433831==   # 6: offset = 32,  size = 4,       count = 6280031, type = %"struct.std::atomic" = type { %"struct.std::__atomic_base" }
==2433831==   # 7: offset = 40,  size = 8,       count = 136405, type = %"struct.rocksdb::InlineSkipList<const rocksdb::MemTableRep::KeyComparator &>::Splice"*
==2433831==EfficiencySanitizer: total struct field access count = 6107964986

Before re-ordering
[trentxintong@devbig460.frc2 ~/fbsource/fbcode]$ fgrep readwhilewriting
without-ro.log
readwhilewriting :       0.036 micros/op 27545605 ops/sec;   26.8 MB/s
(45954 of 5000000 found)
readwhilewriting :       0.036 micros/op 28024240 ops/sec;   27.2 MB/s
(43158 of 5000000 found)
readwhilewriting :       0.037 micros/op 27345145 ops/sec;   27.1 MB/s
(46725 of 5000000 found)
readwhilewriting :       0.037 micros/op 27072588 ops/sec;   27.3 MB/s
(42605 of 5000000 found)
readwhilewriting :       0.034 micros/op 29578781 ops/sec;   28.3 MB/s
(44294 of 5000000 found)
readwhilewriting :       0.035 micros/op 28528304 ops/sec;   27.7 MB/s
(44176 of 5000000 found)
readwhilewriting :       0.037 micros/op 27075497 ops/sec;   26.5 MB/s
(43763 of 5000000 found)
readwhilewriting :       0.036 micros/op 28024117 ops/sec;   27.1 MB/s
(40622 of 5000000 found)
readwhilewriting :       0.037 micros/op 27078709 ops/sec;   27.6 MB/s
(47774 of 5000000 found)
readwhilewriting :       0.034 micros/op 29020689 ops/sec;   28.1 MB/s
(45066 of 5000000 found)
AVERAGE()=27.37 MB/s

After re-ordering
[trentxintong@devbig460.frc2 ~/fbsource/fbcode]$ fgrep readwhilewriting
ro.log
readwhilewriting :       0.036 micros/op 27542409 ops/sec;   27.7 MB/s
(46163 of 5000000 found)
readwhilewriting :       0.036 micros/op 28021148 ops/sec;   28.2 MB/s
(46155 of 5000000 found)
readwhilewriting :       0.036 micros/op 28021035 ops/sec;   27.3 MB/s
(44039 of 5000000 found)
readwhilewriting :       0.036 micros/op 27538659 ops/sec;   27.5 MB/s
(46781 of 5000000 found)
readwhilewriting :       0.036 micros/op 28028604 ops/sec;   27.6 MB/s
(44689 of 5000000 found)
readwhilewriting :       0.036 micros/op 27541452 ops/sec;   27.3 MB/s
(43156 of 5000000 found)
readwhilewriting :       0.034 micros/op 29041338 ops/sec;   28.8 MB/s
(44895 of 5000000 found)
readwhilewriting :       0.036 micros/op 27784974 ops/sec;   26.3 MB/s
(39963 of 5000000 found)
readwhilewriting :       0.036 micros/op 27538892 ops/sec;   28.1 MB/s
(46570 of 5000000 found)
readwhilewriting :       0.038 micros/op 26622473 ops/sec;   27.0 MB/s
(43236 of 5000000 found)
AVERAGE()=27.58 MB/s
Closes https://github.com/facebook/rocksdb/pull/3855

Reviewed By: siying

Differential Revision: D8048781

Pulled By: trentxintong

fbshipit-source-id: bc9807a9845e2a92cb171ce1ecb5a2c8a51f1481
2018-05-17 17:57:48 -07:00
82 changed files with 864 additions and 1501 deletions

No files matched your search

+3 -34
View File
@@ -1,37 +1,7 @@
# Rocksdb Change Log
## Unreleased
### Public API Change
* Application using PessimisticTransactionDB is expected to rollback/commit recovered transactions before starting new ones. This assumption is used to skip concurrency control during recovery.
### Bug Fixes
* Fix a bug in WritePrepared txns where if the number of old snapshots goes beyond the snapshot cache size (128 default) the rest will not be checked when evicting a commit entry from the commit cache.
### New Features
* TransactionOptions::skip_concurrency_control allows pessimistic transactions to skip the overhead of concurrency control. Could be used for optimizing certain transactions or during recovery.
## 5.14.4 (8/31/2018)
### Bug Fixes
* Suppress leak warning for clang(LLVM) ASAN
## 5.14.3 (7/30/2018)
### New Features
* reduce file tail prefetch when not reading index/filter blocks.
## 5.14.2 (7/3/2018)
### Bug Fixes
* Change default value of `bytes_max_delete_chunk` to 0 in NewSstFileManager() as it doesn't work well with checkpoints.
* Set DEBUG_LEVEL=0 for RocksJava Mac Release build.
### New Features
* pin_top_level_index_and_filter (default true) in BlockBasedTableOptions can be used in combination with cache_index_and_filter_blocks to prefetch and pin the top-level index of partitioned index and filter blocks in cache. It has no impact when cache_index_and_filter_blocks is false.
## 5.14.1 (6/20/2018)
### Bug Fixes
* Fix block-based table reader pinning blocks throughout its lifetime, causing memory usage increase.
* Fix bug with prefix search in partition filters where a shared prefix would be ignored from the later partitions. The bug could report an eixstent key as missing. The bug could be triggered if prefix_extractor is set and partition filters is enabled.
### New Features
* Changes the format of index blocks by storing the key in their raw form rather than converting them to InternalKey. This saves 8 bytes per index key. The feature is backward compatbile but not forward compatible. It is disabled by default unless format_version 3 or above is used.
* For users of `Statistics` objects created via `CreateDBStatistics()`, the format of the string returned by its `ToString()` method has changed.
## 5.14.0 (5/16/2018)
### Public API Change
@@ -43,6 +13,7 @@
* Now, `DBOptions::use_direct_io_for_flush_and_compaction` only applies to background writes, and `DBOptions::use_direct_reads` applies to both user reads and background reads. This conforms with Linux's `open(2)` manpage, which advises against simultaneously reading a file in buffered and direct modes, due to possibly undefined behavior and degraded performance.
* Iterator::Valid() always returns false if !status().ok(). So, now when doing a Seek() followed by some Next()s, there's no need to check status() after every operation.
* Iterator::Seek()/SeekForPrev()/SeekToFirst()/SeekToLast() always resets status().
* Introduced `CompressionOptions::kDefaultCompressionLevel`, which is a generic way to tell RocksDB to use the compression library's default level. It is now the default value for `CompressionOptions::level`. Previously the level defaulted to -1, which gave poor compression ratios in ZSTD.
### New Features
* Introduce TTL for level compaction so that all files older than ttl go through the compaction process to get rid of old data.
@@ -59,7 +30,6 @@
* Fix `BackupableDBOptions::max_valid_backups_to_open` to not delete backup files when refcount cannot be accurately determined.
* Fix memory leak when pin_l0_filter_and_index_blocks_in_cache is used with partitioned filters
* Disable rollback of merge operands in WritePrepared transactions to work around an issue in MyRocks. It can be enabled back by setting TransactionDBOptions::rollback_merge_operands to true.
* Fix bug with prefix search in partition filters where a shared prefix would be ignored from the later partitions. The bug could report an eixstent key as missing. The bug could be triggered if prefix_extractor is set and partition filters is enabled.
* Fix wrong results by ReverseBytewiseComparator::FindShortSuccessor()
### Java API Changes
@@ -141,8 +111,7 @@
* `BackupableDBOptions::max_valid_backups_to_open == 0` now means no backups will be opened during BackupEngine initialization. Previously this condition disabled limiting backups opened.
* `DBOptions::preserve_deletes` is a new option that allows one to specify that DB should not drop tombstones for regular deletes if they have sequence number larger than what was set by the new API call `DB::SetPreserveDeletesSequenceNumber(SequenceNumber seqnum)`. Disabled by default.
* API call `DB::SetPreserveDeletesSequenceNumber(SequenceNumber seqnum)` was added, users who wish to preserve deletes are expected to periodically call this function to advance the cutoff seqnum (all deletes made before this seqnum can be dropped by DB). It's user responsibility to figure out how to advance the seqnum in the way so the tombstones are kept for the desired period of time, yet are eventually processed in time and don't eat up too much space.
* `ReadOptions::iter_start_seqnum` was added;
if set to something > 0 user will see 2 changes in iterators behavior 1) only keys written with sequence larger than this parameter would be returned and 2) the `Slice` returned by iter->key() now points to the memory that keep User-oriented representation of the internal key, rather than user key. New struct `FullKey` was added to represent internal keys, along with a new helper function `ParseFullKey(const Slice& internal_key, FullKey* result);`.
* `ReadOptions::iter_start_seqnum` was added; if set to something > 0 user will see 2 changes in iterators behavior 1) only keys written with sequence larger than this parameter would be returned and 2) the `Slice` returned by iter->key() now points to the memory that keep User-oriented representation of the internal key, rather than user key. New struct `FullKey` was added to represent internal keys, along with a new helper function `ParseFullKey(const Slice& internal_key, FullKey* result);`.
* Deprecate trash_dir param in NewSstFileManager, right now we will rename deleted files to <name>.trash instead of moving them to trash directory
* Allow setting a custom trash/DB size ratio limit in the SstFileManager, after which files that are to be scheduled for deletion are deleted immediately, regardless of any delete ratelimit.
* Return an error on write if write_options.sync = true and write_options.disableWAL = true to warn user of inconsistent options. Previously we will not write to WAL and not respecting the sync options in this case.
-4
View File
@@ -85,10 +85,6 @@ ifeq ($(MAKECMDGOALS),rocksdbjavastaticrelease)
DEBUG_LEVEL=0
endif
ifeq ($(MAKECMDGOALS),rocksdbjavastaticreleasedocker)
DEBUG_LEVEL=0
endif
ifeq ($(MAKECMDGOALS),rocksdbjavastaticpublish)
DEBUG_LEVEL=0
endif
+5 -5
View File
@@ -28,7 +28,7 @@ rocksdb_compiler_flags = [
# Added missing flags from output of build_detect_platform
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
"-DROCKSDB_BACKTRACE",
"-Wnarrowing",
"-Wshorten-64-to-32",
]
rocksdb_external_deps = [
@@ -556,13 +556,13 @@ ROCKS_TESTS = [
"serial",
],
[
"db_iter_stress_test",
"db/db_iter_stress_test.cc",
"db_iter_test",
"db/db_iter_test.cc",
"serial",
],
[
"db_iter_test",
"db/db_iter_test.cc",
"db_iter_stress_test",
"db/db_iter_stress_test.cc",
"serial",
],
[
+1 -1
View File
@@ -32,7 +32,7 @@ rocksdb_compiler_flags = [
# Added missing flags from output of build_detect_platform
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
"-DROCKSDB_BACKTRACE",
"-Wnarrowing",
"-Wshorten-64-to-32",
]
rocksdb_external_deps = [
+22 -21
View File
@@ -99,14 +99,20 @@ void LRUHandleTable::Resize() {
length_ = new_length;
}
LRUCacheShard::LRUCacheShard()
: capacity_(0), high_pri_pool_usage_(0), strict_capacity_limit_(false),
high_pri_pool_ratio_(0), high_pri_pool_capacity_(0), usage_(0),
LRUCacheShard::LRUCacheShard(size_t capacity, bool strict_capacity_limit,
double high_pri_pool_ratio)
: capacity_(0),
high_pri_pool_usage_(0),
strict_capacity_limit_(strict_capacity_limit),
high_pri_pool_ratio_(high_pri_pool_ratio),
high_pri_pool_capacity_(0),
usage_(0),
lru_usage_(0) {
// Make empty circular linked list
lru_.next = &lru_;
lru_.prev = &lru_;
lru_low_pri_ = &lru_;
SetCapacity(capacity);
}
LRUCacheShard::~LRUCacheShard() {}
@@ -244,17 +250,13 @@ void* LRUCacheShard::operator new(size_t size) {
return port::cacheline_aligned_alloc(size);
}
void* LRUCacheShard::operator new[](size_t size) {
return port::cacheline_aligned_alloc(size);
}
void* LRUCacheShard::operator new(size_t /*size*/, void* ptr) { return ptr; }
void LRUCacheShard::operator delete(void *memblock) {
port::cacheline_aligned_free(memblock);
}
void LRUCacheShard::operator delete[](void* memblock) {
port::cacheline_aligned_free(memblock);
}
void LRUCacheShard::operator delete(void* /*memblock*/, void* /*ptr*/) {}
void LRUCacheShard::SetCapacity(size_t capacity) {
autovector<LRUHandle*> last_reference_list;
@@ -473,15 +475,21 @@ LRUCache::LRUCache(size_t capacity, int num_shard_bits,
bool strict_capacity_limit, double high_pri_pool_ratio)
: ShardedCache(capacity, num_shard_bits, strict_capacity_limit) {
num_shards_ = 1 << num_shard_bits;
shards_ = new LRUCacheShard[num_shards_];
SetCapacity(capacity);
SetStrictCapacityLimit(strict_capacity_limit);
shards_ = reinterpret_cast<LRUCacheShard*>(
port::cacheline_aligned_alloc(sizeof(LRUCacheShard) * num_shards_));
size_t per_shard = (capacity + (num_shards_ - 1)) / num_shards_;
for (int i = 0; i < num_shards_; i++) {
shards_[i].SetHighPriorityPoolRatio(high_pri_pool_ratio);
new (&shards_[i])
LRUCacheShard(per_shard, strict_capacity_limit, high_pri_pool_ratio);
}
}
LRUCache::~LRUCache() { delete[] shards_; }
LRUCache::~LRUCache() {
for (int i = 0; i < num_shards_; i++) {
shards_[i].~LRUCacheShard();
}
port::cacheline_aligned_free(shards_);
}
CacheShard* LRUCache::GetShard(int shard) {
return reinterpret_cast<CacheShard*>(&shards_[shard]);
@@ -505,16 +513,9 @@ uint32_t LRUCache::GetHash(Handle* handle) const {
void LRUCache::DisownData() {
// Do not drop data if compile with ASAN to suppress leak warning.
#if defined(__clang__)
#if !defined(__has_feature) || !__has_feature(address_sanitizer)
shards_ = nullptr;
num_shards_ = 0;
#endif
#else // __clang__
#ifndef __SANITIZE_ADDRESS__
shards_ = nullptr;
#endif // !__SANITIZE_ADDRESS__
#endif // __clang__
}
size_t LRUCache::TEST_GetLRUSize() {
+7 -3
View File
@@ -156,7 +156,8 @@ class LRUHandleTable {
// A single shard of sharded cache.
class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
public:
LRUCacheShard();
LRUCacheShard(size_t capacity, bool strict_capacity_limit,
double high_pri_pool_ratio);
virtual ~LRUCacheShard();
// Separate from constructor so caller can easily make an array of LRUCache
@@ -206,13 +207,16 @@ class ALIGN_AS(CACHE_LINE_SIZE) LRUCacheShard : public CacheShard {
double GetHighPriPoolRatio();
// Overloading to aligned it to cache line size
// They are used by tests.
void* operator new(size_t);
void* operator new[](size_t);
// placement new
void* operator new(size_t, void*);
void operator delete(void *);
void operator delete[](void*);
// placement delete, does nothing.
void operator delete(void*, void*);
private:
void LRU_Remove(LRUHandle* e);
+4 -14
View File
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
#include "port/port.h"
#include "util/testharness.h"
namespace rocksdb {
@@ -17,19 +18,8 @@ class LRUCacheTest : public testing::Test {
~LRUCacheTest() {}
void NewCache(size_t capacity, double high_pri_pool_ratio = 0.0) {
cache_.reset(
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4316) // We've validated the alignment with the new operators
#endif
new LRUCacheShard()
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
);
cache_->SetCapacity(capacity);
cache_->SetStrictCapacityLimit(false);
cache_->SetHighPriorityPoolRatio(high_pri_pool_ratio);
cache_.reset(new LRUCacheShard(capacity, false /*strict_capcity_limit*/,
high_pri_pool_ratio));
}
void Insert(const std::string& key,
@@ -114,7 +104,7 @@ TEST_F(LRUCacheTest, BasicLRU) {
ValidateLRUList({"e", "z", "d", "u", "v"});
}
TEST_F(LRUCacheTest, MidPointInsertion) {
TEST_F(LRUCacheTest, EntriesWithPriority) {
// Allocate 2 cache entries to high-pri pool.
NewCache(5, 0.45);
-5
View File
@@ -1969,11 +1969,6 @@ void rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
options->rep.pin_l0_filter_and_index_blocks_in_cache = v;
}
void rocksdb_block_based_options_set_pin_top_level_index_and_filter(
rocksdb_block_based_table_options_t* options, unsigned char v) {
options->rep.pin_top_level_index_and_filter = v;
}
void rocksdb_options_set_block_based_table_factory(
rocksdb_options_t *opt,
rocksdb_block_based_table_options_t* table_options) {
+112 -162
View File
@@ -57,9 +57,9 @@ class EnvCounter : public EnvWrapper {
std::atomic<int> num_new_writable_file_;
};
class ColumnFamilyTestBase : public testing::Test {
class ColumnFamilyTest : public testing::Test {
public:
ColumnFamilyTestBase(uint32_t format) : rnd_(139), format_(format) {
ColumnFamilyTest() : rnd_(139) {
env_ = new EnvCounter(Env::Default());
dbname_ = test::TmpDir() + "/column_family_test";
db_options_.create_if_missing = true;
@@ -68,7 +68,7 @@ class ColumnFamilyTestBase : public testing::Test {
DestroyDB(dbname_, Options(db_options_, column_family_options_));
}
virtual ~ColumnFamilyTestBase() {
~ColumnFamilyTest() {
std::vector<ColumnFamilyDescriptor> column_families;
for (auto h : handles_) {
ColumnFamilyDescriptor cfdescriptor;
@@ -81,12 +81,6 @@ class ColumnFamilyTestBase : public testing::Test {
delete env_;
}
BlockBasedTableOptions GetBlockBasedTableOptions() {
BlockBasedTableOptions options;
options.format_version = format_;
return options;
}
// Return the value to associate with the specified key
Slice Value(int k, std::string* storage) {
if (k == 0) {
@@ -305,6 +299,9 @@ class ColumnFamilyTestBase : public testing::Test {
}
void PutRandomData(int cf, int num, int key_value_size, bool save = false) {
if (cf >= static_cast<int>(keys_.size())) {
keys_.resize(cf + 1);
}
for (int i = 0; i < num; ++i) {
// 10 bytes for key, rest is value
if (!save) {
@@ -312,7 +309,7 @@ class ColumnFamilyTestBase : public testing::Test {
RandomString(&rnd_, key_value_size - 10)));
} else {
std::string key = test::RandomKey(&rnd_, 11);
keys_.insert(key);
keys_[cf].insert(key);
ASSERT_OK(Put(cf, key, RandomString(&rnd_, key_value_size - 10)));
}
}
@@ -512,29 +509,16 @@ class ColumnFamilyTestBase : public testing::Test {
std::vector<ColumnFamilyHandle*> handles_;
std::vector<std::string> names_;
std::set<std::string> keys_;
std::vector<std::set<std::string>> keys_;
ColumnFamilyOptions column_family_options_;
DBOptions db_options_;
std::string dbname_;
DB* db_ = nullptr;
EnvCounter* env_;
Random rnd_;
uint32_t format_;
};
class ColumnFamilyTest
: public ColumnFamilyTestBase,
virtual public ::testing::WithParamInterface<uint32_t> {
public:
ColumnFamilyTest() : ColumnFamilyTestBase(GetParam()) {}
};
INSTANTIATE_TEST_CASE_P(FormatDef, ColumnFamilyTest,
testing::Values(test::kDefaultFormatVersion));
INSTANTIATE_TEST_CASE_P(FormatLatest, ColumnFamilyTest,
testing::Values(test::kLatestFormatVersion));
TEST_P(ColumnFamilyTest, DontReuseColumnFamilyID) {
TEST_F(ColumnFamilyTest, DontReuseColumnFamilyID) {
for (int iter = 0; iter < 3; ++iter) {
Open();
CreateColumnFamilies({"one", "two", "three"});
@@ -553,8 +537,7 @@ TEST_P(ColumnFamilyTest, DontReuseColumnFamilyID) {
Reopen();
}
CreateColumnFamilies({"three2"});
// ID 3 that was used for dropped column family "three" should not be
// reused
// ID 3 that was used for dropped column family "three" should not be reused
auto cfh3 = reinterpret_cast<ColumnFamilyHandleImpl*>(handles_[3]);
ASSERT_EQ(4U, cfh3->GetID());
Close();
@@ -563,7 +546,7 @@ TEST_P(ColumnFamilyTest, DontReuseColumnFamilyID) {
}
#ifndef ROCKSDB_LITE
TEST_P(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
TEST_F(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
Open();
rocksdb::SyncPoint::GetInstance()->LoadDependency(
@@ -586,13 +569,10 @@ TEST_P(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
}
#endif // !ROCKSDB_LITE
class FlushEmptyCFTestWithParam
: public ColumnFamilyTestBase,
virtual public testing::WithParamInterface<std::tuple<uint32_t, bool>> {
class FlushEmptyCFTestWithParam : public ColumnFamilyTest,
public testing::WithParamInterface<bool> {
public:
FlushEmptyCFTestWithParam()
: ColumnFamilyTestBase(std::get<0>(GetParam())),
allow_2pc_(std::get<1>(GetParam())) {}
FlushEmptyCFTestWithParam() { allow_2pc_ = GetParam(); }
// Required if inheriting from testing::WithParamInterface<>
static void SetUpTestCase() {}
@@ -717,16 +697,10 @@ TEST_P(FlushEmptyCFTestWithParam, FlushEmptyCFTest2) {
db_options_.env = env_;
}
INSTANTIATE_TEST_CASE_P(
FormatDef, FlushEmptyCFTestWithParam,
testing::Values(std::make_tuple(test::kDefaultFormatVersion, true),
std::make_tuple(test::kDefaultFormatVersion, false)));
INSTANTIATE_TEST_CASE_P(
FormatLatest, FlushEmptyCFTestWithParam,
testing::Values(std::make_tuple(test::kLatestFormatVersion, true),
std::make_tuple(test::kLatestFormatVersion, false)));
INSTANTIATE_TEST_CASE_P(FlushEmptyCFTestWithParam, FlushEmptyCFTestWithParam,
::testing::Bool());
TEST_P(ColumnFamilyTest, AddDrop) {
TEST_F(ColumnFamilyTest, AddDrop) {
Open();
CreateColumnFamilies({"one", "two", "three"});
ASSERT_EQ("NOT_FOUND", Get(1, "fodor"));
@@ -752,7 +726,7 @@ TEST_P(ColumnFamilyTest, AddDrop) {
std::vector<std::string>({"default", "four", "three"}));
}
TEST_P(ColumnFamilyTest, BulkAddDrop) {
TEST_F(ColumnFamilyTest, BulkAddDrop) {
constexpr int kNumCF = 1000;
ColumnFamilyOptions cf_options;
WriteOptions write_options;
@@ -790,7 +764,7 @@ TEST_P(ColumnFamilyTest, BulkAddDrop) {
ASSERT_TRUE(families == std::vector<std::string>({"default"}));
}
TEST_P(ColumnFamilyTest, DropTest) {
TEST_F(ColumnFamilyTest, DropTest) {
// first iteration - dont reopen DB before dropping
// second iteration - reopen DB before dropping
for (int iter = 0; iter < 2; ++iter) {
@@ -814,7 +788,7 @@ TEST_P(ColumnFamilyTest, DropTest) {
}
}
TEST_P(ColumnFamilyTest, WriteBatchFailure) {
TEST_F(ColumnFamilyTest, WriteBatchFailure) {
Open();
CreateColumnFamiliesAndReopen({"one", "two"});
WriteBatch batch;
@@ -832,7 +806,7 @@ TEST_P(ColumnFamilyTest, WriteBatchFailure) {
Close();
}
TEST_P(ColumnFamilyTest, ReadWrite) {
TEST_F(ColumnFamilyTest, ReadWrite) {
Open();
CreateColumnFamiliesAndReopen({"one", "two"});
ASSERT_OK(Put(0, "foo", "v1"));
@@ -856,7 +830,7 @@ TEST_P(ColumnFamilyTest, ReadWrite) {
Close();
}
TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
TEST_F(ColumnFamilyTest, IgnoreRecoveredLog) {
std::string backup_logs = dbname_ + "/backup_logs";
// delete old files in backup_logs directory
@@ -932,7 +906,7 @@ TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
}
#ifndef ROCKSDB_LITE // TEST functions used are not supported
TEST_P(ColumnFamilyTest, FlushTest) {
TEST_F(ColumnFamilyTest, FlushTest) {
Open();
CreateColumnFamiliesAndReopen({"one", "two"});
ASSERT_OK(Put(0, "foo", "v1"));
@@ -980,7 +954,7 @@ TEST_P(ColumnFamilyTest, FlushTest) {
}
// Makes sure that obsolete log files get deleted
TEST_P(ColumnFamilyTest, LogDeletionTest) {
TEST_F(ColumnFamilyTest, LogDeletionTest) {
db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max();
column_family_options_.arena_block_size = 4 * 1024;
column_family_options_.write_buffer_size = 128000; // 128KB
@@ -1048,7 +1022,7 @@ TEST_P(ColumnFamilyTest, LogDeletionTest) {
}
#endif // !ROCKSDB_LITE
TEST_P(ColumnFamilyTest, CrashAfterFlush) {
TEST_F(ColumnFamilyTest, CrashAfterFlush) {
std::unique_ptr<FaultInjectionTestEnv> fault_env(
new FaultInjectionTestEnv(env_));
db_options_.env = fault_env.get();
@@ -1080,7 +1054,7 @@ TEST_P(ColumnFamilyTest, CrashAfterFlush) {
db_options_.env = env_;
}
TEST_P(ColumnFamilyTest, OpenNonexistentColumnFamily) {
TEST_F(ColumnFamilyTest, OpenNonexistentColumnFamily) {
ASSERT_OK(TryOpen({"default"}));
Close();
ASSERT_TRUE(TryOpen({"default", "dne"}).IsInvalidArgument());
@@ -1088,7 +1062,7 @@ TEST_P(ColumnFamilyTest, OpenNonexistentColumnFamily) {
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported
// Makes sure that obsolete log files get deleted
TEST_P(ColumnFamilyTest, DifferentWriteBufferSizes) {
TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) {
// disable flushing stale column families
db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max();
Open();
@@ -1194,7 +1168,7 @@ TEST_P(ColumnFamilyTest, DifferentWriteBufferSizes) {
#endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // Cuckoo is not supported in lite
TEST_P(ColumnFamilyTest, MemtableNotSupportSnapshot) {
TEST_F(ColumnFamilyTest, MemtableNotSupportSnapshot) {
db_options_.allow_concurrent_memtable_write = false;
Open();
auto* s1 = dbfull()->GetSnapshot();
@@ -1232,7 +1206,7 @@ static TestComparator third_comparator;
static TestComparator fourth_comparator;
// Test that we can retrieve the comparator from a created CF
TEST_P(ColumnFamilyTest, GetComparator) {
TEST_F(ColumnFamilyTest, GetComparator) {
Open();
// Add a column family with no comparator specified
CreateColumnFamilies({"first"});
@@ -1251,7 +1225,7 @@ TEST_P(ColumnFamilyTest, GetComparator) {
Close();
}
TEST_P(ColumnFamilyTest, DifferentMergeOperators) {
TEST_F(ColumnFamilyTest, DifferentMergeOperators) {
Open();
CreateColumnFamilies({"first", "second"});
ColumnFamilyOptions default_cf, first, second;
@@ -1282,7 +1256,7 @@ TEST_P(ColumnFamilyTest, DifferentMergeOperators) {
}
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported
TEST_P(ColumnFamilyTest, DifferentCompactionStyles) {
TEST_F(ColumnFamilyTest, DifferentCompactionStyles) {
Open();
CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two;
@@ -1294,7 +1268,7 @@ TEST_P(ColumnFamilyTest, DifferentCompactionStyles) {
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = static_cast<uint64_t>(1) << 60;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1354,7 +1328,7 @@ TEST_P(ColumnFamilyTest, DifferentCompactionStyles) {
#ifndef ROCKSDB_LITE
// Sync points not supported in RocksDB Lite
TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
TEST_F(ColumnFamilyTest, MultipleManualCompactions) {
Open();
CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two;
@@ -1366,7 +1340,7 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1443,17 +1417,15 @@ TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
CompactAll(2);
AssertFilesPerLevel("0,1", 2);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
Close();
}
TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
TEST_F(ColumnFamilyTest, AutomaticAndManualCompactions) {
Open();
CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two;
@@ -1465,8 +1437,7 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1540,16 +1511,14 @@ TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
CompactAll(2);
AssertFilesPerLevel("0,1", 2);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
TEST_F(ColumnFamilyTest, ManualAndAutomaticCompactions) {
Open();
CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two;
@@ -1561,8 +1530,7 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1639,16 +1607,14 @@ TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
CompactAll(2);
AssertFilesPerLevel("0,1", 2);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
TEST_F(ColumnFamilyTest, SameCFManualManualCompactions) {
Open();
CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one;
@@ -1660,8 +1626,7 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1741,16 +1706,14 @@ TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
ASSERT_LE(NumTableFilesAtLevel(0, 1), 2);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
Open();
CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one;
@@ -1762,8 +1725,7 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1834,16 +1796,14 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
ASSERT_LE(NumTableFilesAtLevel(0, 1), 2);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
Open();
CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one;
@@ -1855,8 +1815,7 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1927,13 +1886,11 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
AssertFilesPerLevel("0,1", 1);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
// In this test, we generate enough files to trigger automatic compactions.
@@ -1942,7 +1899,7 @@ TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
// This will wait because the automatic compaction has files it needs.
// Once the conflict is hit, the automatic compaction starts and ends
// Then the manual will run and end.
TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
TEST_F(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
Open();
CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one;
@@ -1954,8 +1911,7 @@ TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -2019,13 +1975,11 @@ TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
// VERIFY compaction "one"
AssertFilesPerLevel("1", 1);
// Compare against saved keys
std::set<std::string>::iterator key_iter = keys_.begin();
while (key_iter != keys_.end()) {
std::set<std::string>::iterator key_iter = keys_[1].begin();
while (key_iter != keys_[1].end()) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++;
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
#endif // !ROCKSDB_LITE
@@ -2042,7 +1996,7 @@ std::string IterStatus(Iterator* iter) {
}
} // anonymous namespace
TEST_P(ColumnFamilyTest, NewIteratorsTest) {
TEST_F(ColumnFamilyTest, NewIteratorsTest) {
// iter == 0 -- no tailing
// iter == 2 -- tailing
for (int iter = 0; iter < 2; ++iter) {
@@ -2089,7 +2043,7 @@ TEST_P(ColumnFamilyTest, NewIteratorsTest) {
#endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // ReadOnlyDB is not supported
TEST_P(ColumnFamilyTest, ReadOnlyDBTest) {
TEST_F(ColumnFamilyTest, ReadOnlyDBTest) {
Open();
CreateColumnFamiliesAndReopen({"one", "two", "three", "four"});
ASSERT_OK(Put(0, "a", "b"));
@@ -2141,7 +2095,7 @@ TEST_P(ColumnFamilyTest, ReadOnlyDBTest) {
#endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported in lite
TEST_P(ColumnFamilyTest, DontRollEmptyLogs) {
TEST_F(ColumnFamilyTest, DontRollEmptyLogs) {
Open();
CreateColumnFamiliesAndReopen({"one", "two", "three", "four"});
@@ -2165,7 +2119,7 @@ TEST_P(ColumnFamilyTest, DontRollEmptyLogs) {
#endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // WaitForCompaction() is not supported in lite
TEST_P(ColumnFamilyTest, FlushStaleColumnFamilies) {
TEST_F(ColumnFamilyTest, FlushStaleColumnFamilies) {
Open();
CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two;
@@ -2200,7 +2154,7 @@ TEST_P(ColumnFamilyTest, FlushStaleColumnFamilies) {
}
#endif // !ROCKSDB_LITE
TEST_P(ColumnFamilyTest, CreateMissingColumnFamilies) {
TEST_F(ColumnFamilyTest, CreateMissingColumnFamilies) {
Status s = TryOpen({"one", "two"});
ASSERT_TRUE(!s.ok());
db_options_.create_missing_column_families = true;
@@ -2209,7 +2163,7 @@ TEST_P(ColumnFamilyTest, CreateMissingColumnFamilies) {
Close();
}
TEST_P(ColumnFamilyTest, SanitizeOptions) {
TEST_F(ColumnFamilyTest, SanitizeOptions) {
DBOptions db_options;
for (int s = kCompactionStyleLevel; s <= kCompactionStyleUniversal; ++s) {
for (int l = 0; l <= 2; l++) {
@@ -2258,7 +2212,7 @@ TEST_P(ColumnFamilyTest, SanitizeOptions) {
}
}
TEST_P(ColumnFamilyTest, ReadDroppedColumnFamily) {
TEST_F(ColumnFamilyTest, ReadDroppedColumnFamily) {
// iter 0 -- drop CF, don't reopen
// iter 1 -- delete CF, reopen
for (int iter = 0; iter < 2; ++iter) {
@@ -2330,7 +2284,7 @@ TEST_P(ColumnFamilyTest, ReadDroppedColumnFamily) {
}
}
TEST_P(ColumnFamilyTest, FlushAndDropRaceCondition) {
TEST_F(ColumnFamilyTest, FlushAndDropRaceCondition) {
db_options_.create_missing_column_families = true;
Open({"default", "one"});
ColumnFamilyOptions options;
@@ -2396,13 +2350,12 @@ TEST_P(ColumnFamilyTest, FlushAndDropRaceCondition) {
// skipped as persisting options is not supported in ROCKSDB_LITE
namespace {
std::atomic<int> test_stage(0);
std::atomic<bool> ordered_by_writethread(false);
const int kMainThreadStartPersistingOptionsFile = 1;
const int kChildThreadFinishDroppingColumnFamily = 2;
const int kChildThreadWaitingMainThreadPersistOptions = 3;
void DropSingleColumnFamily(ColumnFamilyTest* cf_test, int cf_id,
std::vector<Comparator*>* comparators) {
while (test_stage < kMainThreadStartPersistingOptionsFile &&
!ordered_by_writethread) {
while (test_stage < kMainThreadStartPersistingOptionsFile) {
Env::Default()->SleepForMicroseconds(100);
}
cf_test->DropColumnFamilies({cf_id});
@@ -2414,7 +2367,7 @@ void DropSingleColumnFamily(ColumnFamilyTest* cf_test, int cf_id,
}
} // namespace
TEST_P(ColumnFamilyTest, CreateAndDropRace) {
TEST_F(ColumnFamilyTest, CreateAndDropRace) {
const int kCfCount = 5;
std::vector<ColumnFamilyOptions> cf_opts;
std::vector<Comparator*> comparators;
@@ -2435,8 +2388,7 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
// will be blocked until some other thread update the test_stage.
if (main_thread_id == current_thread_id) {
test_stage = kMainThreadStartPersistingOptionsFile;
while (test_stage < kChildThreadFinishDroppingColumnFamily &&
!ordered_by_writethread) {
while (test_stage < kChildThreadFinishDroppingColumnFamily) {
Env::Default()->SleepForMicroseconds(100);
}
}
@@ -2447,7 +2399,11 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
// This means a thread doing DropColumnFamily() is waiting for
// other thread to finish persisting options.
// In such case, we update the test_stage to unblock the main thread.
ordered_by_writethread = true;
test_stage = kChildThreadWaitingMainThreadPersistOptions;
// Note that based on the test setting, this must not be the
// main thread.
ASSERT_NE(main_thread_id, std::this_thread::get_id());
});
// Create a database with four column families
@@ -2458,8 +2414,7 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
// Start a thread that will drop the first column family
// and its comparator
rocksdb::port::Thread drop_cf_thread(DropSingleColumnFamily, this, 1,
&comparators);
rocksdb::port::Thread drop_cf_thread(DropSingleColumnFamily, this, 1, &comparators);
DropColumnFamilies({2});
@@ -2471,13 +2426,10 @@ TEST_P(ColumnFamilyTest, CreateAndDropRace) {
delete comparator;
}
}
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
#endif // !ROCKSDB_LITE
TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
TEST_F(ColumnFamilyTest, WriteStallSingleColumnFamily) {
const uint64_t kBaseRate = 800000u;
db_options_.delayed_write_rate = kBaseRate;
db_options_.max_background_compactions = 6;
@@ -2659,7 +2611,7 @@ TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
}
TEST_P(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) {
TEST_F(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) {
db_options_.max_background_compactions = 6;
Open({"default"});
ColumnFamilyData* cfd =
@@ -2723,7 +2675,7 @@ TEST_P(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) {
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
}
TEST_P(ColumnFamilyTest, WriteStallTwoColumnFamilies) {
TEST_F(ColumnFamilyTest, WriteStallTwoColumnFamilies) {
const uint64_t kBaseRate = 810000u;
db_options_.delayed_write_rate = kBaseRate;
Open();
@@ -2798,7 +2750,7 @@ TEST_P(ColumnFamilyTest, WriteStallTwoColumnFamilies) {
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
}
TEST_P(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
TEST_F(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
db_options_.max_background_compactions = 6;
column_family_options_.soft_pending_compaction_bytes_limit = 200;
column_family_options_.hard_pending_compaction_bytes_limit = 2000;
@@ -2863,7 +2815,7 @@ TEST_P(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
}
TEST_P(ColumnFamilyTest, CreateAndDestoryOptions) {
TEST_F(ColumnFamilyTest, CreateAndDestoryOptions) {
std::unique_ptr<ColumnFamilyOptions> cfo(new ColumnFamilyOptions());
ColumnFamilyHandle* cfh;
Open();
@@ -2875,29 +2827,8 @@ TEST_P(ColumnFamilyTest, CreateAndDestoryOptions) {
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
}
TEST_P(ColumnFamilyTest, CreateDropAndDestroy) {
ColumnFamilyHandle* cfh;
Open();
ASSERT_OK(db_->CreateColumnFamily(ColumnFamilyOptions(), "yoyo", &cfh));
ASSERT_OK(db_->Put(WriteOptions(), cfh, "foo", "bar"));
ASSERT_OK(db_->Flush(FlushOptions(), cfh));
ASSERT_OK(db_->DropColumnFamily(cfh));
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
}
#ifndef ROCKSDB_LITE
TEST_P(ColumnFamilyTest, CreateDropAndDestroyWithoutFileDeletion) {
ColumnFamilyHandle* cfh;
Open();
ASSERT_OK(db_->CreateColumnFamily(ColumnFamilyOptions(), "yoyo", &cfh));
ASSERT_OK(db_->Put(WriteOptions(), cfh, "foo", "bar"));
ASSERT_OK(db_->Flush(FlushOptions(), cfh));
ASSERT_OK(db_->DisableFileDeletions());
ASSERT_OK(db_->DropColumnFamily(cfh));
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh));
}
TEST_P(ColumnFamilyTest, FlushCloseWALFiles) {
TEST_F(ColumnFamilyTest, FlushCloseWALFiles) {
SpecialEnv env(Env::Default());
db_options_.env = &env;
db_options_.max_background_flushes = 1;
@@ -2939,7 +2870,7 @@ TEST_P(ColumnFamilyTest, FlushCloseWALFiles) {
#endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported
TEST_P(ColumnFamilyTest, IteratorCloseWALFile1) {
TEST_F(ColumnFamilyTest, IteratorCloseWALFile1) {
SpecialEnv env(Env::Default());
db_options_.env = &env;
db_options_.max_background_flushes = 1;
@@ -2984,7 +2915,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile1) {
Close();
}
TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
TEST_F(ColumnFamilyTest, IteratorCloseWALFile2) {
SpecialEnv env(Env::Default());
// Allow both of flush and purge job to schedule.
env.SetBackgroundThreads(2, Env::HIGH);
@@ -3041,7 +2972,7 @@ TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
#endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // TEST functions are not supported in lite
TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
TEST_F(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
SpecialEnv env(Env::Default());
// Allow both of flush and purge job to schedule.
env.SetBackgroundThreads(2, Env::HIGH);
@@ -3118,7 +3049,7 @@ TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
// Disable on windows because SyncWAL requires env->IsSyncThreadSafe()
// to return true which is not so in unbuffered mode.
#ifndef OS_WIN
TEST_P(ColumnFamilyTest, LogSyncConflictFlush) {
TEST_F(ColumnFamilyTest, LogSyncConflictFlush) {
Open();
CreateColumnFamiliesAndReopen({"one", "two"});
@@ -3153,7 +3084,7 @@ TEST_P(ColumnFamilyTest, LogSyncConflictFlush) {
// test is being used to ensure a roll of wal files.
// Basic idea is to test that WAL truncation is being detected and not
// ignored
TEST_P(ColumnFamilyTest, DISABLED_LogTruncationTest) {
TEST_F(ColumnFamilyTest, DISABLED_LogTruncationTest) {
Open();
CreateColumnFamiliesAndReopen({"one", "two"});
@@ -3223,7 +3154,7 @@ TEST_P(ColumnFamilyTest, DISABLED_LogTruncationTest) {
env_->DeleteDir(backup_logs);
}
TEST_P(ColumnFamilyTest, DefaultCfPathsTest) {
TEST_F(ColumnFamilyTest, DefaultCfPathsTest) {
Open();
// Leave cf_paths for one column families to be empty.
// Files should be generated according to db_paths for that
@@ -3250,7 +3181,7 @@ TEST_P(ColumnFamilyTest, DefaultCfPathsTest) {
ASSERT_EQ(1, GetSstFileCount(dbname_));
}
TEST_P(ColumnFamilyTest, MultipleCFPathsTest) {
TEST_F(ColumnFamilyTest, MultipleCFPathsTest) {
Open();
// Configure Column family specific paths.
ColumnFamilyOptions cf_opt1, cf_opt2;
@@ -3261,19 +3192,38 @@ TEST_P(ColumnFamilyTest, MultipleCFPathsTest) {
CreateColumnFamilies({"one", "two"}, {cf_opt1, cf_opt2});
Reopen({ColumnFamilyOptions(), cf_opt1, cf_opt2});
PutRandomData(1, 100, 100);
PutRandomData(1, 100, 100, true /* save */);
Flush(1);
// Check that files are generated in appropriate paths.
ASSERT_EQ(1, GetSstFileCount(cf_opt1.cf_paths[0].path));
ASSERT_EQ(0, GetSstFileCount(dbname_));
PutRandomData(2, 100, 100);
PutRandomData(2, 100, 100, true /* save */);
Flush(2);
ASSERT_EQ(1, GetSstFileCount(cf_opt2.cf_paths[0].path));
ASSERT_EQ(0, GetSstFileCount(dbname_));
// Re-open and verify the keys.
Reopen({ColumnFamilyOptions(), cf_opt1, cf_opt2});
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
for (int cf = 1; cf != 3; ++cf) {
ReadOptions read_options;
read_options.readahead_size = 0;
auto it = dbi->NewIterator(read_options, handles_[cf]);
for (it->SeekToFirst(); it->Valid(); it->Next()) {
Slice key(it->key());
ASSERT_NE(keys_[cf].end(), keys_[cf].find(key.ToString()));
}
delete it;
for (const auto& key : keys_[cf]) {
ASSERT_NE("NOT_FOUND", Get(cf, key));
}
}
}
} // namespace rocksdb
int main(int argc, char** argv) {
+12 -28
View File
@@ -251,25 +251,18 @@ class TwoStrComparator : public Comparator {
};
} // namespace
class ComparatorDBTest
: public testing::Test,
virtual public ::testing::WithParamInterface<uint32_t> {
class ComparatorDBTest : public testing::Test {
private:
std::string dbname_;
Env* env_;
DB* db_;
Options last_options_;
std::unique_ptr<const Comparator> comparator_guard;
uint32_t format_;
public:
ComparatorDBTest() : env_(Env::Default()), db_(nullptr) {
comparator = BytewiseComparator();
dbname_ = test::TmpDir() + "/comparator_db_test";
BlockBasedTableOptions toptions;
toptions.format_version = GetParam();
last_options_.table_factory.reset(
rocksdb::NewBlockBasedTableFactory(toptions));
EXPECT_OK(DestroyDB(dbname_, last_options_));
}
@@ -281,12 +274,8 @@ class ComparatorDBTest
DB* GetDB() { return db_; }
void SetOwnedComparator(const Comparator* cmp, bool owner = true) {
if (owner) {
comparator_guard.reset(cmp);
} else {
comparator_guard.reset();
}
void SetOwnedComparator(const Comparator* cmp) {
comparator_guard.reset(cmp);
comparator = cmp;
last_options_.comparator = cmp;
}
@@ -315,12 +304,7 @@ class ComparatorDBTest
}
};
INSTANTIATE_TEST_CASE_P(FormatDef, ComparatorDBTest,
testing::Values(test::kDefaultFormatVersion));
INSTANTIATE_TEST_CASE_P(FormatLatest, ComparatorDBTest,
testing::Values(test::kLatestFormatVersion));
TEST_P(ComparatorDBTest, Bytewise) {
TEST_F(ComparatorDBTest, Bytewise) {
for (int rand_seed = 301; rand_seed < 306; rand_seed++) {
DestroyAndReopen();
Random rnd(rand_seed);
@@ -330,7 +314,7 @@ TEST_P(ComparatorDBTest, Bytewise) {
}
}
TEST_P(ComparatorDBTest, SimpleSuffixReverseComparator) {
TEST_F(ComparatorDBTest, SimpleSuffixReverseComparator) {
SetOwnedComparator(new test::SimpleSuffixReverseComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -356,8 +340,8 @@ TEST_P(ComparatorDBTest, SimpleSuffixReverseComparator) {
}
}
TEST_P(ComparatorDBTest, Uint64Comparator) {
SetOwnedComparator(test::Uint64Comparator(), false /* owner */);
TEST_F(ComparatorDBTest, Uint64Comparator) {
SetOwnedComparator(test::Uint64Comparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
Options* opt = GetOptions();
@@ -380,7 +364,7 @@ TEST_P(ComparatorDBTest, Uint64Comparator) {
}
}
TEST_P(ComparatorDBTest, DoubleComparator) {
TEST_F(ComparatorDBTest, DoubleComparator) {
SetOwnedComparator(new DoubleComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -405,7 +389,7 @@ TEST_P(ComparatorDBTest, DoubleComparator) {
}
}
TEST_P(ComparatorDBTest, HashComparator) {
TEST_F(ComparatorDBTest, HashComparator) {
SetOwnedComparator(new HashComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -424,7 +408,7 @@ TEST_P(ComparatorDBTest, HashComparator) {
}
}
TEST_P(ComparatorDBTest, TwoStrComparator) {
TEST_F(ComparatorDBTest, TwoStrComparator) {
SetOwnedComparator(new TwoStrComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -450,7 +434,7 @@ TEST_P(ComparatorDBTest, TwoStrComparator) {
}
}
TEST_P(ComparatorDBTest, FindShortestSeparator) {
TEST_F(ComparatorDBTest, FindShortestSeparator) {
std::string s1 = "abc1xyz";
std::string s2 = "abc3xy";
@@ -484,7 +468,7 @@ TEST_P(ComparatorDBTest, FindShortestSeparator) {
ASSERT_TRUE(s1 > s2);
}
TEST_P(ComparatorDBTest, SeparatorSuccessorRandomizeTest) {
TEST_F(ComparatorDBTest, SeparatorSuccessorRandomizeTest) {
// Char list for boundary cases.
std::array<unsigned char, 6> char_list{{0, 1, 2, 253, 254, 255}};
Random rnd(301);
+1
View File
@@ -211,6 +211,7 @@ Status DBImpl::WriteImpl(const WriteOptions& write_options,
// and protects against concurrent loggers and concurrent writes
// into memtables
TEST_SYNC_POINT("DBImpl::WriteImpl:BeforeLeaderEnters");
last_batch_group_size_ =
write_thread_.EnterAsBatchGroupLeader(&w, &write_group);
+10 -9
View File
@@ -173,7 +173,7 @@ struct StressTestIterator : public InternalIterator {
}
}
void SeekToFirst() {
void SeekToFirst() override {
if (MaybeFail()) return;
MaybeMutate();
@@ -181,7 +181,7 @@ struct StressTestIterator : public InternalIterator {
iter = 0;
SkipForward();
}
void SeekToLast() {
void SeekToLast() override {
if (MaybeFail()) return;
MaybeMutate();
@@ -190,7 +190,7 @@ struct StressTestIterator : public InternalIterator {
SkipBackward();
}
void Seek(const Slice& target) {
void Seek(const Slice& target) override {
if (MaybeFail()) return;
MaybeMutate();
@@ -202,7 +202,7 @@ struct StressTestIterator : public InternalIterator {
iter = (int)(it - data->entries.begin());
SkipForward();
}
void SeekForPrev(const Slice& target) {
void SeekForPrev(const Slice& target) override {
if (MaybeFail()) return;
MaybeMutate();
@@ -216,14 +216,14 @@ struct StressTestIterator : public InternalIterator {
SkipBackward();
}
void Next() {
void Next() override {
assert(Valid());
if (MaybeFail()) return;
MaybeMutate();
++iter;
SkipForward();
}
void Prev() {
void Prev() override {
assert(Valid());
if (MaybeFail()) return;
MaybeMutate();
@@ -231,11 +231,11 @@ struct StressTestIterator : public InternalIterator {
SkipBackward();
}
Slice key() const {
Slice key() const override {
assert(Valid());
return data->entries[iter].ikey;
}
Slice value() const {
Slice value() const override {
assert(Valid());
return data->entries[iter].value;
}
@@ -404,13 +404,14 @@ TEST_F(DBIteratorStressTest, StressTest) {
Random64 rnd(826909345792864532ll);
auto gen_key = [&](int max_key) {
assert(max_key > 0);
int len = 0;
int a = max_key;
while (a) {
a /= 10;
++len;
}
std::string s = ToString(rnd.Next() % (uint64_t)max_key);
std::string s = ToString(rnd.Next() % static_cast<uint64_t>(max_key));
s.insert(0, len - (int)s.size(), '0');
return s;
};
+4 -6
View File
@@ -36,9 +36,7 @@ class TestIterator : public InternalIterator {
valid_(false),
sequence_number_(0),
iter_(0),
cmp(comparator) {
data_.reserve(16);
}
cmp(comparator) {}
void AddPut(std::string argkey, std::string argvalue) {
Add(argkey, kTypeValue, argvalue);
@@ -2662,7 +2660,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace1) {
// MergeIterator::Prev() realized the mem table iterator is at its end
// and before an SeekToLast() is called.
rocksdb::SyncPoint::GetInstance()->SetCallBack(
"MergeIterator::Prev:BeforePrev",
"MergeIterator::Prev:BeforeSeekToLast",
[&](void* /*arg*/) { internal_iter2_->Add("z", kTypeValue, "7", 12u); });
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
@@ -2698,7 +2696,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace2) {
// mem table after MergeIterator::Prev() realized the mem tableiterator is at
// its end and before an SeekToLast() is called.
rocksdb::SyncPoint::GetInstance()->SetCallBack(
"MergeIterator::Prev:BeforePrev", [&](void* /*arg*/) {
"MergeIterator::Prev:BeforeSeekToLast", [&](void* /*arg*/) {
internal_iter2_->Add("z", kTypeValue, "7", 12u);
internal_iter2_->Add("z", kTypeValue, "7", 11u);
});
@@ -2736,7 +2734,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace3) {
// mem table after MergeIterator::Prev() realized the mem table iterator is at
// its end and before an SeekToLast() is called.
rocksdb::SyncPoint::GetInstance()->SetCallBack(
"MergeIterator::Prev:BeforePrev", [&](void* /*arg*/) {
"MergeIterator::Prev:BeforeSeekToLast", [&](void* /*arg*/) {
internal_iter2_->Add("z", kTypeValue, "7", 16u, true);
internal_iter2_->Add("z", kTypeValue, "7", 15u, true);
internal_iter2_->Add("z", kTypeValue, "7", 14u, true);
-78
View File
@@ -2044,43 +2044,6 @@ TEST_P(DBIteratorTest, CreationFailure) {
delete iter;
}
TEST_P(DBIteratorTest, UpperBoundWithChangeDirection) {
Options options = CurrentOptions();
options.max_sequential_skip_in_iterations = 3;
DestroyAndReopen(options);
// write a bunch of kvs to the database.
ASSERT_OK(Put("a", "1"));
ASSERT_OK(Put("y", "1"));
ASSERT_OK(Put("y1", "1"));
ASSERT_OK(Put("y2", "1"));
ASSERT_OK(Put("y3", "1"));
ASSERT_OK(Put("z", "1"));
ASSERT_OK(Flush());
ASSERT_OK(Put("a", "1"));
ASSERT_OK(Put("z", "1"));
ASSERT_OK(Put("bar", "1"));
ASSERT_OK(Put("foo", "1"));
std::string upper_bound = "x";
Slice ub_slice(upper_bound);
ReadOptions ro;
ro.iterate_upper_bound = &ub_slice;
ro.max_skippable_internal_keys = 1000;
Iterator* iter = NewIterator(ro);
iter->Seek("foo");
ASSERT_TRUE(iter->Valid());
ASSERT_EQ("foo", iter->key().ToString());
iter->Prev();
ASSERT_TRUE(iter->Valid());
ASSERT_OK(iter->status());
ASSERT_EQ("bar", iter->key().ToString());
delete iter;
}
TEST_P(DBIteratorTest, TableFilter) {
ASSERT_OK(Put("a", "1"));
dbfull()->Flush(FlushOptions());
@@ -2147,47 +2110,6 @@ TEST_P(DBIteratorTest, TableFilter) {
}
}
TEST_P(DBIteratorTest, UpperBoundWithPrevReseek) {
Options options = CurrentOptions();
options.max_sequential_skip_in_iterations = 3;
DestroyAndReopen(options);
// write a bunch of kvs to the database.
ASSERT_OK(Put("a", "1"));
ASSERT_OK(Put("y", "1"));
ASSERT_OK(Put("z", "1"));
ASSERT_OK(Flush());
ASSERT_OK(Put("a", "1"));
ASSERT_OK(Put("z", "1"));
ASSERT_OK(Put("bar", "1"));
ASSERT_OK(Put("foo", "1"));
ASSERT_OK(Put("foo", "2"));
ASSERT_OK(Put("foo", "3"));
ASSERT_OK(Put("foo", "4"));
ASSERT_OK(Put("foo", "5"));
const Snapshot* snapshot = db_->GetSnapshot();
ASSERT_OK(Put("foo", "6"));
std::string upper_bound = "x";
Slice ub_slice(upper_bound);
ReadOptions ro;
ro.snapshot = snapshot;
ro.iterate_upper_bound = &ub_slice;
Iterator* iter = NewIterator(ro);
iter->SeekForPrev("goo");
ASSERT_TRUE(iter->Valid());
ASSERT_EQ("foo", iter->key().ToString());
iter->Prev();
ASSERT_TRUE(iter->Valid());
ASSERT_EQ("bar", iter->key().ToString());
delete iter;
db_->ReleaseSnapshot(snapshot);
}
TEST_P(DBIteratorTest, SkipStatistics) {
Options options = CurrentOptions();
options.statistics = rocksdb::CreateDBStatistics();
+4 -3
View File
@@ -242,11 +242,12 @@ TEST_F(DBOptionsTest, WritableFileMaxBufferSize) {
ASSERT_EQ(unmatch_cnt, 0);
ASSERT_GE(match_cnt, 11);
buffer_size = 512 * 1024;
match_cnt = 0;
unmatch_cnt = 0;
ASSERT_OK(
dbfull()->SetDBOptions({{"writable_file_max_buffer_size", "524288"}}));
buffer_size = 512 * 1024;
match_cnt = 0;
unmatch_cnt = 0; // SetDBOptions() will create a WriteableFileWriter
ASSERT_EQ(buffer_size,
dbfull()->GetDBOptions().writable_file_max_buffer_size);
i = 0;
+13 -15
View File
@@ -177,16 +177,17 @@ void ParseTablePropertiesString(std::string tp_string, TableProperties* tp) {
std::replace(tp_string.begin(), tp_string.end(), ';', ' ');
std::replace(tp_string.begin(), tp_string.end(), '=', ' ');
ResetTableProperties(tp);
sscanf(tp_string.c_str(),
"# data blocks %" SCNu64 " # entries %" SCNu64 " raw key size %" SCNu64
" raw average key size %lf "
" raw value size %" SCNu64
" raw average value size %lf "
" data block size %" SCNu64 " index block size (user-key? %" SCNu64
") %" SCNu64 " filter block size %" SCNu64,
" data block size %" SCNu64 " index block size %" SCNu64
" filter block size %" SCNu64,
&tp->num_data_blocks, &tp->num_entries, &tp->raw_key_size,
&dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size,
&tp->index_key_is_user_key, &tp->index_size, &tp->filter_size);
&tp->index_size, &tp->filter_size);
}
void VerifySimilar(uint64_t a, uint64_t b, double bias) {
@@ -223,8 +224,7 @@ void GetExpectedTableProperties(TableProperties* expected_tp,
const int kKeySize, const int kValueSize,
const int kKeysPerTable, const int kTableCount,
const int kBloomBitsPerKey,
const size_t kBlockSize,
const bool index_key_is_user_key) {
const size_t kBlockSize) {
const int kKeyCount = kTableCount * kKeysPerTable;
const int kAvgSuccessorSize = kKeySize / 5;
const int kEncodingSavePerKey = kKeySize / 4;
@@ -238,8 +238,7 @@ void GetExpectedTableProperties(TableProperties* expected_tp,
expected_tp->data_size =
kTableCount * (kKeysPerTable * (kKeySize + 8 + kValueSize));
expected_tp->index_size =
expected_tp->num_data_blocks *
(kAvgSuccessorSize + (index_key_is_user_key ? 0 : 8));
expected_tp->num_data_blocks * (kAvgSuccessorSize + 8);
expected_tp->filter_size =
kTableCount * (kKeysPerTable * kBloomBitsPerKey / 8);
}
@@ -316,14 +315,14 @@ TEST_F(DBPropertiesTest, AggregatedTableProperties) {
}
std::string property;
db_->GetProperty(DB::Properties::kAggregatedTableProperties, &property);
TableProperties output_tp;
ParseTablePropertiesString(property, &output_tp);
bool index_key_is_user_key = output_tp.index_key_is_user_key > 0;
TableProperties expected_tp;
GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize,
kKeysPerTable, kTableCount, kBloomBitsPerKey,
table_options.block_size, index_key_is_user_key);
table_options.block_size);
TableProperties output_tp;
ParseTablePropertiesString(property, &output_tp);
VerifyTableProperties(expected_tp, output_tp);
}
@@ -490,7 +489,6 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
}
db_->GetProperty(DB::Properties::kAggregatedTableProperties, &tp_string);
ParseTablePropertiesString(tp_string, &tp);
bool index_key_is_user_key = tp.index_key_is_user_key > 0;
ASSERT_EQ(sum_tp.data_size, tp.data_size);
ASSERT_EQ(sum_tp.index_size, tp.index_size);
ASSERT_EQ(sum_tp.filter_size, tp.filter_size);
@@ -499,9 +497,9 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
ASSERT_EQ(sum_tp.num_data_blocks, tp.num_data_blocks);
ASSERT_EQ(sum_tp.num_entries, tp.num_entries);
if (table > 3) {
GetExpectedTableProperties(
&expected_tp, kKeySize, kValueSize, kKeysPerTable, table,
kBloomBitsPerKey, table_options.block_size, index_key_is_user_key);
GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize,
kKeysPerTable, table, kBloomBitsPerKey,
table_options.block_size);
// Gives larger bias here as index block size, filter block size,
// and data block size become much harder to estimate in this test.
VerifyTableProperties(tp, expected_tp, 0.5, 0.4, 0.4, 0.25);
+6 -8
View File
@@ -2153,10 +2153,14 @@ TEST_F(DBTest, GroupCommitTest) {
do {
Options options = CurrentOptions();
options.env = env_;
env_->log_write_slowdown_.store(100);
options.statistics = rocksdb::CreateDBStatistics();
Reopen(options);
rocksdb::SyncPoint::GetInstance()->LoadDependency(
{{"WriteThread::JoinBatchGroup:BeganWaiting",
"DBImpl::WriteImpl:BeforeLeaderEnters"}});
rocksdb::SyncPoint::GetInstance()->EnableProcessing();
// Start threads
GCThread thread[kGCNumThreads];
for (int id = 0; id < kGCNumThreads; id++) {
@@ -2165,13 +2169,7 @@ TEST_F(DBTest, GroupCommitTest) {
thread[id].done = false;
env_->StartThread(GCThreadBody, &thread[id]);
}
for (int id = 0; id < kGCNumThreads; id++) {
while (thread[id].done == false) {
env_->SleepForMicroseconds(100000);
}
}
env_->log_write_slowdown_.store(0);
env_->WaitForJoin();
ASSERT_GT(TestGetTickerCount(options, WRITE_DONE_BY_OTHER), 0);
-11
View File
@@ -428,17 +428,6 @@ Options DBTestBase::GetOptions(
options.prefix_extractor.reset(NewNoopTransform());
break;
}
case kBlockBasedTableWithPartitionedIndexFormat3: {
table_options.format_version = 3;
// Format 3 changes the binary index format. Since partitioned index is a
// super-set of simple indexes, we are also using kTwoLevelIndexSearch to
// test this format.
table_options.index_type = BlockBasedTableOptions::kTwoLevelIndexSearch;
// The top-level index in partition filters are also affected by format 3.
table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
table_options.partition_filters = true;
break;
}
case kBlockBasedTableWithIndexRestartInterval: {
table_options.index_block_restart_interval = 8;
break;
+7 -14
View File
@@ -694,20 +694,13 @@ class DBTestBase : public testing::Test {
kConcurrentSkipList = 29,
kPipelinedWrite = 30,
kConcurrentWALWrites = 31,
kDirectIO,
kLevelSubcompactions,
kBlockBasedTableWithIndexRestartInterval,
kBlockBasedTableWithPartitionedIndex,
kBlockBasedTableWithPartitionedIndexFormat3,
kPartitionedFilterWithNewTableReaderForCompactions,
// This must be the last line
kEnd,
// TODO: This option although been there for a while was disable due to a
// mistake. Enabling it makes somem tests to fail. We should enable it and
// fix the unit tests.
kUniversalSubcompactions,
kEnd = 32,
kDirectIO = 33,
kLevelSubcompactions = 34,
kUniversalSubcompactions = 35,
kBlockBasedTableWithIndexRestartInterval = 36,
kBlockBasedTableWithPartitionedIndex = 37,
kPartitionedFilterWithNewTableReaderForCompactions = 38,
};
public:
+4
View File
@@ -195,6 +195,10 @@ Status RangeDelAggregator::AddTombstones(
input->SeekToFirst();
bool first_iter = true;
while (input->Valid()) {
// The tombstone map holds slices into the iterator's memory. This assert
// ensures pinning the iterator also pins the keys/values.
assert(input->IsKeyPinned() && input->IsValuePinned());
if (first_iter) {
if (rep_ == nullptr) {
InitRep({upper_bound_});
+2 -2
View File
@@ -20,7 +20,7 @@ namespace rocksdb {
// Tag numbers for serialized VersionEdit. These numbers are written to
// disk and should not be changed.
enum Tag {
enum Tag : uint32_t {
kComparator = 1,
kLogNumber = 2,
kNextFileNumber = 3,
@@ -42,7 +42,7 @@ enum Tag {
kMaxColumnFamily = 203,
};
enum CustomTag {
enum CustomTag : uint32_t {
kTerminate = 1, // The end of customized fields
kNeedCompaction = 2,
// Since Manifest is not entirely currently forward-compatible, and the only
+1
View File
@@ -318,6 +318,7 @@ void WriteThread::JoinBatchGroup(Writer* w) {
* 3.2) an existing memtable writer group leader tell us to finish memtable
* writes in parallel.
*/
TEST_SYNC_POINT_CALLBACK("WriteThread::JoinBatchGroup:BeganWaiting", w);
AwaitState(w, STATE_GROUP_LEADER | STATE_MEMTABLE_WRITER_LEADER |
STATE_PARALLEL_MEMTABLE_WRITER | STATE_COMPLETED,
&jbg_ctx);
-1
View File
@@ -138,7 +138,6 @@
block_restart_interval=16
cache_index_and_filter_blocks=false
pin_l0_filter_and_index_blocks_in_cache=false
pin_top_level_index_and_filter=false
index_type=kBinarySearch
hash_index_allow_collision=true
flush_block_policy_factory=FlushBlockBySizePolicyFactory
+9 -1
View File
@@ -87,6 +87,14 @@ struct CompactionOptionsFIFO {
// Compression options for different compression algorithms like Zlib
struct CompressionOptions {
// RocksDB's generic default compression level. Internally it'll be translated
// to the default compression level specific to the library being used (see
// comment above `ColumnFamilyOptions::compression`).
//
// The default value is the max 16-bit int as it'll be written out in OPTIONS
// file, which should be portable.
const static int kDefaultCompressionLevel = 32767;
int window_bits;
int level;
int strategy;
@@ -120,7 +128,7 @@ struct CompressionOptions {
CompressionOptions()
: window_bits(-14),
level(-1),
level(kDefaultCompressionLevel),
strategy(0),
max_dict_bytes(0),
zstd_max_train_bytes(0) {}
-3
View File
@@ -692,9 +692,6 @@ rocksdb_block_based_options_set_cache_index_and_filter_blocks_with_high_priority
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
rocksdb_block_based_table_options_t*, unsigned char);
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_pin_top_level_index_and_filter(
rocksdb_block_based_table_options_t*, unsigned char);
extern ROCKSDB_LIBRARY_API void rocksdb_options_set_block_based_table_factory(
rocksdb_options_t* opt, rocksdb_block_based_table_options_t* table_options);
+14 -3
View File
@@ -198,11 +198,21 @@ struct ColumnFamilyOptions : public AdvancedColumnFamilyOptions {
// 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.
//
// If you do not set `compression_opts.level`, or set it to
// `CompressionOptions::kDefaultCompressionLevel`, we will attempt to pick the
// default corresponding to `compression` as follows:
//
// - kZSTD: 3
// - kZlibCompression: Z_DEFAULT_COMPRESSION (currently -1)
// - kLZ4HCCompression: 0
// - For all others, we do not specify a compression level
CompressionType compression;
// Compression algorithm that will be used for the bottommost level that
@@ -271,7 +281,7 @@ struct ColumnFamilyOptions : public AdvancedColumnFamilyOptions {
// later in the vector.
// Note that, if a path is supplied to multiple column
// families, it would have files and total size from all
// the column families combined. User should privision for the
// the column families combined. User should provision for the
// total size(from all the column families) in such cases.
//
// If left empty, db_paths will be used.
@@ -558,8 +568,9 @@ struct DBOptions {
// manifest file is rolled over on reaching this limit.
// The older manifest file be deleted.
// The default value is MAX_INT so that roll-over does not take place.
uint64_t max_manifest_file_size = std::numeric_limits<uint64_t>::max();
// The default value is 1GB so that the manifest file can grow, but not
// reach the limit of storage capacity.
uint64_t max_manifest_file_size = 1024 * 1024 * 1024;
// Number of shards used for table cache.
int table_cache_numshardbits = 6;
+3 -1
View File
@@ -43,7 +43,9 @@ class Slice {
// Create a slice that refers to s[0,strlen(s)-1]
/* implicit */
Slice(const char* s) : data_(s), size_(strlen(s)) { }
Slice(const char* s) : data_(s) {
size_ = (s == nullptr) ? 0 : strlen(s);
}
// Create a single slice from SliceParts using buf as storage.
// buf must exist as long as the returned Slice exists.
+2 -3
View File
@@ -98,13 +98,12 @@ class SstFileManager {
// DeleteScheduler immediately
// @param bytes_max_delete_chunk: if a single file is larger than delete chunk,
// ftruncate the file by this size each time, rather than dropping the whole
// file. 0 means to always delete the whole file. NOTE this options may not
// work well with checkpoints, which relies on file system hard links.
// file. 0 means to always delete the whole file.
extern SstFileManager* NewSstFileManager(
Env* env, std::shared_ptr<Logger> info_log = nullptr,
std::string trash_dir = "", int64_t rate_bytes_per_sec = 0,
bool delete_existing_trash = true, Status* status = nullptr,
double max_trash_db_ratio = 0.25,
uint64_t bytes_max_delete_chunk = 0);
uint64_t bytes_max_delete_chunk = 64 * 1024 * 1024);
} // namespace rocksdb
+2
View File
@@ -619,6 +619,8 @@ struct HistogramData {
// zero-initialize new members since old Statistics::histogramData()
// implementations won't write them.
double max = 0.0;
uint64_t count = 0;
uint64_t sum = 0;
};
enum StatsLevel {
+2 -12
View File
@@ -77,13 +77,6 @@ struct BlockBasedTableOptions {
// evicted from cache when the table reader is freed.
bool pin_l0_filter_and_index_blocks_in_cache = false;
// If cache_index_and_filter_blocks is true and the below is true, then
// the top-level index of partitioned filter and index blocks are stored in
// the cache, but a reference is held in the "table reader" object so the
// blocks are pinned and only evicted from cache when the table reader is
// freed. This is not limited to l0 in LSM tree.
bool pin_top_level_index_and_filter = true;
// The index type that will be used for this table.
enum IndexType : char {
// A space efficient index block that is optimized for
@@ -221,11 +214,8 @@ struct BlockBasedTableOptions {
// encode compressed blocks with LZ4, BZip2 and Zlib compression. If you
// don't plan to run RocksDB before version 3.10, you should probably use
// this.
// 3 -- Can be read by RocksDB's versions since 5.15. Changes the way we
// encode the keys in index blocks. If you don't plan to run RocksDB before
// version 5.15, you should probably use this.
// This option only affects newly written tables. When reading existing
// tables, the information about version is read from the footer.
// This option only affects newly written tables. When reading existing tables,
// the information about version is read from the footer.
uint32_t format_version = 2;
// Store index blocks on disk in compressed format. Changing this option to
-4
View File
@@ -33,7 +33,6 @@ struct TablePropertiesNames {
static const std::string kIndexSize;
static const std::string kIndexPartitions;
static const std::string kTopLevelIndexSize;
static const std::string kIndexKeyIsUserKey;
static const std::string kFilterSize;
static const std::string kRawKeySize;
static const std::string kRawValueSize;
@@ -135,9 +134,6 @@ struct TableProperties {
uint64_t index_partitions = 0;
// Size of the top-level index if kTwoLevelIndexSearch is used
uint64_t top_level_index_size = 0;
// Whether the index key is user key. Otherwise it includes 8 byte of sequence
// number added by internal key format.
uint64_t index_key_is_user_key = 0;
// the size of filter block.
uint64_t filter_size = 0;
// total raw key size
+3 -15
View File
@@ -137,15 +137,6 @@ struct TransactionOptions {
// The maximum number of bytes used for the write batch. 0 means no limit.
size_t max_write_batch_size = 0;
// Skip Concurrency Control. This could be as an optimization if the
// application knows that the transaction would not have any conflict with
// concurrent transactions. It could also be used during recovery if (i)
// application guarantees no conflict between prepared transactions in the WAL
// (ii) application guarantees that recovered transactions will be rolled
// back/commit before new transactions start.
// Default: false
bool skip_concurrency_control = false;
};
// The per-write optimizations that do not involve transactions. TransactionDB
@@ -178,15 +169,12 @@ struct DeadlockInfo {
struct DeadlockPath {
std::vector<DeadlockInfo> path;
bool limit_exceeded;
int64_t deadlock_time;
explicit DeadlockPath(
std::vector<DeadlockInfo> path_entry, const int64_t& dl_time)
: path(path_entry), limit_exceeded(false), deadlock_time(dl_time) {}
explicit DeadlockPath(std::vector<DeadlockInfo> path_entry)
: path(path_entry), limit_exceeded(false) {}
// empty path, limit exceeded constructor and default constructor
explicit DeadlockPath(const int64_t& dl_time = 0, bool limit = false)
: path(0), limit_exceeded(limit), deadlock_time(dl_time) {}
explicit DeadlockPath(bool limit = false) : path(0), limit_exceeded(limit) {}
bool empty() { return path.empty() && !limit_exceeded; }
};
+1 -1
View File
@@ -6,7 +6,7 @@
#define ROCKSDB_MAJOR 5
#define ROCKSDB_MINOR 14
#define ROCKSDB_PATCH 4
#define ROCKSDB_PATCH 0
// Do not use these. We made the mistake of declaring macros starting with
// double underscore. Now we have to live with our choice. We'll deprecate these
+1 -1
View File
@@ -3230,7 +3230,7 @@ Java_org_rocksdb_ColumnFamilyOptions_setCompactionFilterFactoryHandle(
JNIEnv* /*env*/, jobject /*jobj*/, jlong jopt_handle,
jlong jcompactionfilterfactory_handle) {
auto* cff_factory =
reinterpret_cast<std::shared_ptr<rocksdb::CompactionFilterFactoryJniCallback>*>(
reinterpret_cast<std::shared_ptr<rocksdb::CompactionFilterFactory>*>(
jcompactionfilterfactory_handle);
reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jopt_handle)
->compaction_filter_factory = *cff_factory;
+34 -49
View File
@@ -4292,12 +4292,25 @@ class JniUtil {
* @param bytes The bytes to copy
*
* @return the Java byte[] or nullptr if an exception occurs
*
* @throws RocksDBException thrown
* if memory size to copy exceeds general java specific array size limitation.
*/
static jbyteArray copyBytes(JNIEnv* env, std::string bytes) {
return createJavaByteArrayWithSizeCheck(env, bytes.c_str(), bytes.size());
const jsize jlen = static_cast<jsize>(bytes.size());
jbyteArray jbytes = env->NewByteArray(jlen);
if(jbytes == nullptr) {
// exception thrown: OutOfMemoryError
return nullptr;
}
env->SetByteArrayRegion(jbytes, 0, jlen,
const_cast<jbyte*>(reinterpret_cast<const jbyte*>(bytes.c_str())));
if(env->ExceptionCheck()) {
// exception thrown: ArrayIndexOutOfBoundsException
env->DeleteLocalRef(jbytes);
return nullptr;
}
return jbytes;
}
/**
@@ -4460,47 +4473,6 @@ class JniUtil {
return jbyte_strings;
}
/**
* Copies bytes to a new jByteArray with the check of java array size limitation.
*
* @param bytes pointer to memory to copy to a new jByteArray
* @param size number of bytes to copy
*
* @return the Java byte[] or nullptr if an exception occurs
*
* @throws RocksDBException thrown
* if memory size to copy exceeds general java array size limitation to avoid overflow.
*/
static jbyteArray createJavaByteArrayWithSizeCheck(JNIEnv* env, const char* bytes, const size_t size) {
// Limitation for java array size is vm specific
// In general it cannot exceed Integer.MAX_VALUE (2^31 - 1)
// Current HotSpot VM limitation for array size is Integer.MAX_VALUE - 5 (2^31 - 1 - 5)
// It means that the next call to env->NewByteArray can still end with
// OutOfMemoryError("Requested array size exceeds VM limit") coming from VM
static const size_t MAX_JARRAY_SIZE = (static_cast<size_t>(1)) << 31;
if(size > MAX_JARRAY_SIZE) {
rocksdb::RocksDBExceptionJni::ThrowNew(env, "Requested array size exceeds VM limit");
return nullptr;
}
const jsize jlen = static_cast<jsize>(size);
jbyteArray jbytes = env->NewByteArray(jlen);
if(jbytes == nullptr) {
// exception thrown: OutOfMemoryError
return nullptr;
}
env->SetByteArrayRegion(jbytes, 0, jlen,
const_cast<jbyte*>(reinterpret_cast<const jbyte*>(bytes)));
if(env->ExceptionCheck()) {
// exception thrown: ArrayIndexOutOfBoundsException
env->DeleteLocalRef(jbytes);
return nullptr;
}
return jbytes;
}
/**
* Copies bytes from a rocksdb::Slice to a jByteArray
@@ -4509,12 +4481,25 @@ class JniUtil {
* @param bytes The bytes to copy
*
* @return the Java byte[] or nullptr if an exception occurs
*
* @throws RocksDBException thrown
* if memory size to copy exceeds general java specific array size limitation.
*/
static jbyteArray copyBytes(JNIEnv* env, const Slice& bytes) {
return createJavaByteArrayWithSizeCheck(env, bytes.data(), bytes.size());
const jsize jlen = static_cast<jsize>(bytes.size());
jbyteArray jbytes = env->NewByteArray(jlen);
if(jbytes == nullptr) {
// exception thrown: OutOfMemoryError
return nullptr;
}
env->SetByteArrayRegion(jbytes, 0, jlen,
const_cast<jbyte*>(reinterpret_cast<const jbyte*>(bytes.data())));
if(env->ExceptionCheck()) {
// exception thrown: ArrayIndexOutOfBoundsException
env->DeleteLocalRef(jbytes);
return nullptr;
}
return jbytes;
}
/*
+1 -1
View File
@@ -138,7 +138,7 @@ jobject Java_org_rocksdb_SstFileManager_getTrackedFiles(JNIEnv* env,
const rocksdb::HashMapJni::FnMapKV<const std::string, const uint64_t>
fn_map_kv =
[env](
[env, &tracked_files](
const std::pair<const std::string, const uint64_t>& pair) {
const jstring jtracked_file_path =
env->NewStringUTF(pair.first.c_str());
+1 -1
View File
@@ -48,7 +48,7 @@ void Java_org_rocksdb_Transaction_setSnapshotOnNextOperation__JJ(
jlong jtxn_notifier_handle) {
auto* txn = reinterpret_cast<rocksdb::Transaction*>(jhandle);
auto* txn_notifier =
reinterpret_cast<std::shared_ptr<rocksdb::TransactionNotifierJniCallback>*>(
reinterpret_cast<std::shared_ptr<rocksdb::TransactionNotifier>*>(
jtxn_notifier_handle);
txn->SetSnapshotOnNextOperation(*txn_notifier);
}
+9 -1
View File
@@ -307,14 +307,22 @@ jobject Java_org_rocksdb_TransactionDB_getLockStatusData(JNIEnv* env,
return nullptr;
}
<<<<<<< Updated upstream
const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo>
fn_map_kv =
[env](
[env, txn_db, &lock_status_data](
const std::pair<const int32_t, const rocksdb::KeyLockInfo>&
pair) {
const jobject jlong_column_family_id =
rocksdb::LongJni::valueOf(env, pair.first);
if (jlong_column_family_id == nullptr) {
=======
const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo> fn_map_kv =
[env](const std::pair<const int32_t, const rocksdb::KeyLockInfo>& pair) {
const jobject jlong_column_family_id =
rocksdb::LongJni::valueOf(env, pair.first);
if (jlong_column_family_id == nullptr) {
>>>>>>> Stashed changes
// an error occurred
return std::unique_ptr<std::pair<jobject, jobject>>(nullptr);
}
@@ -28,10 +28,8 @@ public class ColumnFamilyHandle extends RocksObject {
* Gets the name of the Column Family.
*
* @return The name of the Column Family.
*
* @throws RocksDBException if an error occurs whilst retrieving the name.
*/
public byte[] getName() throws RocksDBException {
public byte[] getName() {
return getName(nativeHandle_);
}
@@ -73,22 +71,14 @@ public class ColumnFamilyHandle extends RocksObject {
}
final ColumnFamilyHandle that = (ColumnFamilyHandle) o;
try {
return rocksDB_.nativeHandle_ == that.rocksDB_.nativeHandle_ &&
getID() == that.getID() &&
Arrays.equals(getName(), that.getName());
} catch (RocksDBException e) {
throw new RuntimeException("Cannot compare column family handles", e);
}
return rocksDB_.nativeHandle_ == that.rocksDB_.nativeHandle_ &&
getID() == that.getID() &&
Arrays.equals(getName(), that.getName());
}
@Override
public int hashCode() {
try {
return Objects.hash(getName(), getID(), rocksDB_.nativeHandle_);
} catch (RocksDBException e) {
throw new RuntimeException("Cannot calculate hash code of column family handle", e);
}
return Objects.hash(getName(), getID(), rocksDB_.nativeHandle_);
}
/**
@@ -106,7 +96,7 @@ public class ColumnFamilyHandle extends RocksObject {
}
}
private native byte[] getName(final long handle) throws RocksDBException;
private native byte[] getName(final long handle);
private native int getID(final long handle);
private native ColumnFamilyDescriptor getDescriptor(final long handle) throws RocksDBException;
@Override protected final native void disposeInternal(final long handle);
@@ -65,11 +65,8 @@ public class WriteBatch extends AbstractWriteBatch {
* Retrieve the serialized version of this batch.
*
* @return the serialized representation of this write batch.
*
* @throws RocksDBException if an error occurs whilst retrieving
* the serialized batch data.
*/
public byte[] data() throws RocksDBException {
public byte[] data() {
return data(nativeHandle_);
}
@@ -256,7 +253,7 @@ public class WriteBatch extends AbstractWriteBatch {
final int serializedLength);
private native void iterate(final long handle, final long handlerHandle)
throws RocksDBException;
private native byte[] data(final long nativeHandle) throws RocksDBException;
private native byte[] data(final long nativeHandle);
private native long getDataSize(final long nativeHandle);
private native boolean hasPut(final long nativeHandle);
private native boolean hasDelete(final long nativeHandle);
@@ -4,11 +4,9 @@
// (found in the LICENSE.Apache file in the root directory).
package org.rocksdb;
import org.junit.Assume;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import java.util.*;
@@ -145,39 +143,6 @@ public class RocksDBTest {
}
}
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void getOutOfArrayMaxSizeValue() throws RocksDBException {
final int numberOfValueSplits = 10;
final int splitSize = Integer.MAX_VALUE / numberOfValueSplits;
Runtime runtime = Runtime.getRuntime();
long neededMemory = ((long)(splitSize)) * (((long)numberOfValueSplits) + 3);
boolean isEnoughMemory = runtime.maxMemory() - runtime.totalMemory() > neededMemory;
Assume.assumeTrue(isEnoughMemory);
final byte[] valueSplit = new byte[splitSize];
final byte[] key = "key".getBytes();
thrown.expect(RocksDBException.class);
thrown.expectMessage("Requested array size exceeds VM limit");
// merge (numberOfValueSplits + 1) valueSplit's to get value size exceeding Integer.MAX_VALUE
try (final StringAppendOperator stringAppendOperator = new StringAppendOperator();
final Options opt = new Options()
.setCreateIfMissing(true)
.setMergeOperator(stringAppendOperator);
final RocksDB db = RocksDB.open(opt, dbFolder.getRoot().getAbsolutePath())) {
db.put(key, valueSplit);
for (int i = 0; i < numberOfValueSplits; i++) {
db.merge(key, valueSplit);
}
db.get(key);
}
}
@Test
public void multiGet() throws RocksDBException, InterruptedException {
try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
+2 -3
View File
@@ -184,10 +184,9 @@ class InlineSkipList {
const uint16_t kBranching_;
const uint32_t kScaledInverseBranching_;
Allocator* const allocator_; // Allocator used for allocations of nodes
// Immutable after construction
Comparator const compare_;
Allocator* const allocator_; // Allocator used for allocations of nodes
Node* const head_;
// Modified only by Insert(). Read racily by readers, but stale
@@ -587,8 +586,8 @@ InlineSkipList<Comparator>::InlineSkipList(const Comparator cmp,
: kMaxHeight_(static_cast<uint16_t>(max_height)),
kBranching_(static_cast<uint16_t>(branching_factor)),
kScaledInverseBranching_((Random::kMaxNext + 1) / kBranching_),
compare_(cmp),
allocator_(allocator),
compare_(cmp),
head_(AllocateNode(0, max_height)),
max_height_(1),
seq_splice_(AllocateSplice()) {
+2
View File
@@ -235,6 +235,8 @@ void HistogramStat::Data(HistogramData * const data) const {
data->max = static_cast<double>(max());
data->average = Average();
data->standard_deviation = StandardDeviation();
data->count = num();
data->sum = sum();
}
void HistogramImpl::Clear() {
+10 -4
View File
@@ -169,11 +169,17 @@ std::string StatisticsImpl::ToString() const {
char buffer[kTmpStrBufferSize];
HistogramData hData;
getHistogramImplLocked(h.first)->Data(&hData);
snprintf(
// don't handle failures - buffer should always be big enough and arguments
// should be provided correctly
int ret = snprintf(
buffer, kTmpStrBufferSize,
"%s statistics Percentiles :=> 50 : %f 95 : %f 99 : %f 100 : %f\n",
h.second.c_str(), hData.median, hData.percentile95,
hData.percentile99, hData.max);
"%s P50 : %f P95 : %f P99 : %f P100 : %f COUNT : %" PRIu64 " SUM : %"
PRIu64 "\n", h.second.c_str(), hData.median, hData.percentile95,
hData.percentile99, hData.max, hData.count, hData.sum);
if (ret < 0 || ret >= kTmpStrBufferSize) {
assert(false);
continue;
}
res.append(buffer);
}
}
+8 -4
View File
@@ -17,6 +17,7 @@
#include "rocksdb/convenience.h"
#include "rocksdb/db.h"
#include "util/cast_util.h"
#include "util/file_reader_writer.h"
#include "util/string_util.h"
#include "util/sync_point.h"
@@ -41,12 +42,16 @@ Status PersistRocksDBOptions(const DBOptions& db_opt,
return Status::InvalidArgument(
"cf_names.size() and cf_opts.size() must be the same");
}
std::unique_ptr<WritableFile> writable;
std::unique_ptr<WritableFile> wf;
Status s = env->NewWritableFile(file_name, &writable, EnvOptions());
Status s = env->NewWritableFile(file_name, &wf, EnvOptions());
if (!s.ok()) {
return s;
}
unique_ptr<WritableFileWriter> writable;
writable.reset(new WritableFileWriter(std::move(wf), EnvOptions(),
nullptr /* statistics */));
std::string options_file_content;
writable->Append(option_file_header + "[" +
@@ -93,8 +98,7 @@ Status PersistRocksDBOptions(const DBOptions& db_opt,
writable->Append(options_file_content + "\n");
}
}
writable->Flush();
writable->Fsync();
writable->Sync(true /* use_fsync */);
writable->Close();
return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
-1
View File
@@ -140,7 +140,6 @@ TEST_F(OptionsSettableTest, BlockBasedTableOptionsAllFieldsSettable) {
"cache_index_and_filter_blocks=1;"
"cache_index_and_filter_blocks_with_high_priority=true;"
"pin_l0_filter_and_index_blocks_in_cache=1;"
"pin_top_level_index_and_filter=1;"
"index_type=kHashSearch;"
"checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;"
"block_cache=1M;block_cache_compressed=1k;block_size=1024;"
+21 -1
View File
@@ -250,6 +250,8 @@ MAIN_SOURCES = \
cache/cache_bench.cc \
cache/cache_test.cc \
db/column_family_test.cc \
db/compact_files_test.cc \
db/compaction_iterator_test.cc \
db/compaction_job_stats_test.cc \
db/compaction_job_test.cc \
db/compaction_picker_test.cc \
@@ -257,6 +259,7 @@ MAIN_SOURCES = \
db/corruption_test.cc \
db/cuckoo_table_db_test.cc \
db/db_basic_test.cc \
db/db_blob_index_test.cc \
db/db_block_cache_test.cc \
db/db_bloom_filter_test.cc \
db/db_compaction_filter_test.cc \
@@ -273,33 +276,50 @@ MAIN_SOURCES = \
db/db_memtable_test.cc \
db/db_merge_operator_test.cc \
db/db_options_test.cc \
db/db_properties_test.cc \
db/db_range_del_test.cc \
db/db_sst_test.cc \
db/db_statistics_test.cc \
db/db_table_properties_test.cc \
db/db_tailing_iter_test.cc \
db/db_test.cc \
db/db_test2.cc \
db/db_universal_compaction_test.cc \
db/db_wal_test.cc \
db/db_write_test.cc \
db/dbformat_test.cc \
db/deletefile_test.cc \
db/obsolete_files_test.cc \
db/env_timed_test.cc \
db/external_sst_file_basic_test.cc \
db/external_sst_file_test.cc \
db/fault_injection_test.cc \
db/file_indexer_test.cc \
db/file_reader_writer_test.cc \
db/filename_test.cc \
db/flush_job_test.cc \
db/hash_table_test.cc \
db/hash_test.cc \
db/heap_test.cc \
db/listener_test.cc \
db/log_test.cc \
db/lru_cache_test.cc \
db/manual_compaction_test.cc \
db/memtable_list_test.cc \
db/merge_helper_test.cc \
db/merge_test.cc \
db/obsolete_files_test.cc \
db/options_settable_test.cc \
db/options_file_test.cc \
db/partitioned_filter_block_test.cc \
db/perf_context_test.cc \
db/persistent_cache_test.cc \
db/plain_table_db_test.cc \
db/prefix_test.cc \
db/redis_test.cc \
db/repair_test.cc \
db/range_del_aggregator_test.cc \
db/table_properties_collector_test.cc \
db/util_merge_operators_test.cc \
db/version_builder_test.cc \
db/version_edit_test.cc \
db/version_set_test.cc \
+13 -42
View File
@@ -87,11 +87,7 @@ void BlockIter::Prev() {
const Slice current_key(key_ptr, current_prev_entry.key_size);
current_ = current_prev_entry.offset;
if (key_includes_seq_) {
key_.SetInternalKey(current_key, false /* copy */);
} else {
key_.SetUserKey(current_key, false /* copy */);
}
key_.SetInternalKey(current_key, false /* copy */);
value_ = current_prev_entry.value;
return;
@@ -140,10 +136,6 @@ void BlockIter::Prev() {
}
void BlockIter::Seek(const Slice& target) {
Slice seek_key = target;
if (!key_includes_seq_) {
seek_key = ExtractUserKey(target);
}
PERF_TIMER_GUARD(block_seek_nanos);
if (data_ == nullptr) { // Not init yet
return;
@@ -153,7 +145,7 @@ void BlockIter::Seek(const Slice& target) {
if (prefix_index_) {
ok = PrefixSeek(target, &index);
} else {
ok = BinarySeek(seek_key, 0, num_restarts_ - 1, &index);
ok = BinarySeek(target, 0, num_restarts_ - 1, &index);
}
if (!ok) {
@@ -163,7 +155,7 @@ void BlockIter::Seek(const Slice& target) {
// Linear search (within restart block) for first key >= target
while (true) {
if (!ParseNextKey() || Compare(key_, seek_key) >= 0) {
if (!ParseNextKey() || Compare(key_.GetInternalKey(), target) >= 0) {
return;
}
}
@@ -171,28 +163,24 @@ void BlockIter::Seek(const Slice& target) {
void BlockIter::SeekForPrev(const Slice& target) {
PERF_TIMER_GUARD(block_seek_nanos);
Slice seek_key = target;
if (!key_includes_seq_) {
seek_key = ExtractUserKey(target);
}
if (data_ == nullptr) { // Not init yet
return;
}
uint32_t index = 0;
bool ok = BinarySeek(seek_key, 0, num_restarts_ - 1, &index);
bool ok = BinarySeek(target, 0, num_restarts_ - 1, &index);
if (!ok) {
return;
}
SeekToRestartPoint(index);
// Linear search (within restart block) for first key >= seek_key
// Linear search (within restart block) for first key >= target
while (ParseNextKey() && Compare(key_, seek_key) < 0) {
while (ParseNextKey() && Compare(key_.GetInternalKey(), target) < 0) {
}
if (!Valid()) {
SeekToLast();
} else {
while (Valid() && Compare(key_, seek_key) > 0) {
while (Valid() && Compare(key_.GetInternalKey(), target) > 0) {
Prev();
}
}
@@ -245,11 +233,7 @@ bool BlockIter::ParseNextKey() {
if (shared == 0) {
// If this key dont share any bytes with prev key then we dont need
// to decode it and can use it's address in the block directly.
if (key_includes_seq_) {
key_.SetInternalKey(Slice(p, non_shared), false /* copy */);
} else {
key_.SetUserKey(Slice(p, non_shared), false /* copy */);
}
key_.SetInternalKey(Slice(p, non_shared), false /* copy */);
key_pinned_ = true;
} else {
// This key share `shared` bytes with prev key, we need to decode it
@@ -396,10 +380,6 @@ bool BlockIter::BinaryBlockIndexSeek(const Slice& target, uint32_t* block_ids,
bool BlockIter::PrefixSeek(const Slice& target, uint32_t* index) {
assert(prefix_index_);
Slice seek_key = target;
if (!key_includes_seq_) {
seek_key = ExtractUserKey(target);
}
uint32_t* block_ids = nullptr;
uint32_t num_blocks = prefix_index_->GetBlocks(target, &block_ids);
@@ -407,7 +387,7 @@ bool BlockIter::PrefixSeek(const Slice& target, uint32_t* index) {
current_ = restarts_;
return false;
} else {
return BinaryBlockIndexSeek(seek_key, block_ids, 0, num_blocks - 1, index);
return BinaryBlockIndexSeek(target, block_ids, 0, num_blocks - 1, index);
}
}
@@ -442,9 +422,8 @@ Block::Block(BlockContents&& contents, SequenceNumber _global_seqno,
}
}
BlockIter* Block::NewIterator(const Comparator* cmp, const Comparator* ucmp,
BlockIter* iter, bool total_order_seek,
Statistics* stats, bool key_includes_seq) {
BlockIter* Block::NewIterator(const Comparator* cmp, BlockIter* iter,
bool total_order_seek, Statistics* stats) {
BlockIter* ret_iter;
if (iter != nullptr) {
ret_iter = iter;
@@ -462,9 +441,9 @@ BlockIter* Block::NewIterator(const Comparator* cmp, const Comparator* ucmp,
} else {
BlockPrefixIndex* prefix_index_ptr =
total_order_seek ? nullptr : prefix_index_.get();
ret_iter->Initialize(cmp, ucmp, data_, restart_offset_, num_restarts_,
ret_iter->Initialize(cmp, data_, restart_offset_, num_restarts_,
prefix_index_ptr, global_seqno_,
read_amp_bitmap_.get(), key_includes_seq);
read_amp_bitmap_.get());
if (read_amp_bitmap_) {
if (read_amp_bitmap_->GetStatistics() != stats) {
@@ -483,17 +462,9 @@ void Block::SetBlockPrefixIndex(BlockPrefixIndex* prefix_index) {
size_t Block::ApproximateMemoryUsage() const {
size_t usage = usable_size();
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
usage += malloc_usable_size((void*)this);
#else
usage += sizeof(*this);
#endif // ROCKSDB_MALLOC_USABLE_SIZE
if (prefix_index_) {
usage += prefix_index_->ApproximateMemoryUsage();
}
if (read_amp_bitmap_) {
usage += read_amp_bitmap_->ApproximateMemoryUsage();
}
return usage;
}
+19 -53
View File
@@ -104,13 +104,6 @@ class BlockReadAmpBitmap {
uint32_t GetBytesPerBit() { return 1 << bytes_per_bit_pow_; }
size_t ApproximateMemoryUsage() const {
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
return malloc_usable_size((void*)this);
#endif // ROCKSDB_MALLOC_USABLE_SIZE
return sizeof(*this);
}
private:
// Get the current value of bit at `bit_idx` and set it to 1
inline bool GetAndSet(uint32_t bit_idx) {
@@ -149,8 +142,14 @@ class Block {
size_t size() const { return size_; }
const char* data() const { return data_; }
bool cachable() const { return contents_.cachable; }
// The additional memory space taken by the block data.
size_t usable_size() const { return contents_.usable_size(); }
size_t usable_size() const {
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
if (contents_.allocation.get() != nullptr) {
return malloc_usable_size(contents_.allocation.get());
}
#endif // ROCKSDB_MALLOC_USABLE_SIZE
return size_;
}
uint32_t NumRestarts() const;
CompressionType compression_type() const {
return contents_.compression_type;
@@ -163,9 +162,6 @@ class Block {
// the iterator will simply be set as "invalid", rather than returning
// the key that is just pass the target key.
//
// If comparator is InternalKeyComparator, user_comparator is its user
// comparator; they are equal otherwise.
//
// If iter is null, return new Iterator
// If iter is not null, update this one and return it as Iterator*
//
@@ -173,11 +169,9 @@ class Block {
// This option only applies for index block. For data block, hash_index_
// and prefix_index_ are null, so this option does not matter.
BlockIter* NewIterator(const Comparator* comparator,
const Comparator* user_comparator,
BlockIter* iter = nullptr,
bool total_order_seek = true,
Statistics* stats = nullptr,
bool key_includes_seq = true);
Statistics* stats = nullptr);
void SetBlockPrefixIndex(BlockPrefixIndex* prefix_index);
// Report an approximation of how much memory has been used.
@@ -209,7 +203,6 @@ class BlockIter final : public InternalIterator {
// and status() is OK.
BlockIter()
: comparator_(nullptr),
user_comparator_(nullptr),
data_(nullptr),
restarts_(0),
num_restarts_(0),
@@ -218,30 +211,26 @@ class BlockIter final : public InternalIterator {
status_(Status::OK()),
prefix_index_(nullptr),
key_pinned_(false),
key_includes_seq_(true),
global_seqno_(kDisableGlobalSequenceNumber),
read_amp_bitmap_(nullptr),
last_bitmap_offset_(0) {}
BlockIter(const Comparator* comparator, const Comparator* user_comparator,
const char* data, uint32_t restarts, uint32_t num_restarts,
BlockPrefixIndex* prefix_index, SequenceNumber global_seqno,
BlockReadAmpBitmap* read_amp_bitmap, bool key_includes_seq)
BlockIter(const Comparator* comparator, const char* data, uint32_t restarts,
uint32_t num_restarts, BlockPrefixIndex* prefix_index,
SequenceNumber global_seqno, BlockReadAmpBitmap* read_amp_bitmap)
: BlockIter() {
Initialize(comparator, user_comparator, data, restarts, num_restarts,
prefix_index, global_seqno, read_amp_bitmap, key_includes_seq);
Initialize(comparator, data, restarts, num_restarts, prefix_index,
global_seqno, read_amp_bitmap);
}
void Initialize(const Comparator* comparator,
const Comparator* user_comparator, const char* data,
void Initialize(const Comparator* comparator, const char* data,
uint32_t restarts, uint32_t num_restarts,
BlockPrefixIndex* prefix_index, SequenceNumber global_seqno,
BlockReadAmpBitmap* read_amp_bitmap, bool key_includes_seq) {
BlockReadAmpBitmap* read_amp_bitmap) {
assert(data_ == nullptr); // Ensure it is called only once
assert(num_restarts > 0); // Ensure the param is valid
comparator_ = comparator;
user_comparator_ = user_comparator;
data_ = data;
restarts_ = restarts;
num_restarts_ = num_restarts;
@@ -251,11 +240,10 @@ class BlockIter final : public InternalIterator {
global_seqno_ = global_seqno;
read_amp_bitmap_ = read_amp_bitmap;
last_bitmap_offset_ = current_ + 1;
key_includes_seq_ = key_includes_seq;
}
// Makes Valid() return false, status() return `s`, and Seek()/Prev()/etc do
// nothing. Calls cleanup functions.
// nothing.
void Invalidate(Status s) {
// Assert that the BlockIter is never deleted while Pinning is Enabled.
assert(!pinned_iters_mgr_ ||
@@ -265,9 +253,6 @@ class BlockIter final : public InternalIterator {
current_ = restarts_;
status_ = s;
// Call cleanup callbacks.
Cleanable::Reset();
// Clear prev entries cache.
prev_entries_keys_buff_.clear();
prev_entries_.clear();
@@ -278,7 +263,7 @@ class BlockIter final : public InternalIterator {
virtual Status status() const override { return status_; }
virtual Slice key() const override {
assert(Valid());
return key_includes_seq_ ? key_.GetInternalKey() : key_.GetUserKey();
return key_.GetInternalKey();
}
virtual Slice value() const override {
assert(Valid());
@@ -327,11 +312,7 @@ class BlockIter final : public InternalIterator {
}
private:
// Note: The type could be changed to InternalKeyComparator but we see a weird
// performance drop by that.
const Comparator* comparator_;
// Same as comparator_ if comparator_ is not InernalKeyComparator
const Comparator* user_comparator_;
const char* data_; // underlying block contents
uint32_t restarts_; // Offset of restart array (list of fixed32)
uint32_t num_restarts_; // Number of uint32_t entries in restart array
@@ -344,11 +325,8 @@ class BlockIter final : public InternalIterator {
Status status_;
BlockPrefixIndex* prefix_index_;
bool key_pinned_;
// Key is in InternalKey format
bool key_includes_seq_;
SequenceNumber global_seqno_;
public:
// read-amp bitmap
BlockReadAmpBitmap* read_amp_bitmap_;
// last `current_` value we report to read-amp bitmp
@@ -379,19 +357,7 @@ class BlockIter final : public InternalIterator {
int32_t prev_entries_idx_ = -1;
inline int Compare(const Slice& a, const Slice& b) const {
if (key_includes_seq_) {
return comparator_->Compare(a, b);
} else {
return user_comparator_->Compare(a, b);
}
}
inline int Compare(const IterKey& ikey, const Slice& b) const {
if (key_includes_seq_) {
return comparator_->Compare(ikey.GetInternalKey(), b);
} else {
return user_comparator_->Compare(ikey.GetUserKey(), b);
}
return comparator_->Compare(a, b);
}
// Return the offset in data_ just past the end of the current entry.
+1 -3
View File
@@ -643,7 +643,7 @@ Status BlockBasedTableBuilder::InsertBlockInCache(const Slice& block_contents,
(end - r->compressed_cache_key_prefix));
// Insert into compressed block cache.
block_cache_compressed->Insert(key, block, block->ApproximateMemoryUsage(),
block_cache_compressed->Insert(key, block, block->usable_size(),
&DeleteCachedBlock);
// Invalidate OS cache.
@@ -763,8 +763,6 @@ Status BlockBasedTableBuilder::Finish() {
r->props.top_level_index_size =
r->p_index_builder_->EstimateTopLevelIndexSize(r->offset);
}
r->props.index_key_is_user_key =
!r->index_builder->seperator_is_key_plus_seq();
r->props.creation_time = r->creation_time;
r->props.oldest_key_time = r->oldest_key_time;
-3
View File
@@ -151,9 +151,6 @@ std::string BlockBasedTableFactory::GetPrintableTableOptions() const {
" pin_l0_filter_and_index_blocks_in_cache: %d\n",
table_options_.pin_l0_filter_and_index_blocks_in_cache);
ret.append(buffer);
snprintf(buffer, kBufferSize, " pin_top_level_index_and_filter: %d\n",
table_options_.pin_top_level_index_and_filter);
ret.append(buffer);
snprintf(buffer, kBufferSize, " index_type: %d\n",
table_options_.index_type);
ret.append(buffer);
-4
View File
@@ -158,10 +158,6 @@ static std::unordered_map<std::string, OptionTypeInfo>
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
{"block_align",
{offsetof(struct BlockBasedTableOptions, block_align),
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
{"pin_top_level_index_and_filter",
{offsetof(struct BlockBasedTableOptions,
pin_top_level_index_and_filter),
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}}};
#endif // !ROCKSDB_LITE
} // namespace rocksdb
+155 -264
View File
@@ -176,8 +176,9 @@ Cache::Handle* GetEntryFromCache(Cache* block_cache, const Slice& key,
// For hash based index, return true if prefix_extractor and
// prefix_extractor_block mismatch, false otherwise. This flag will be used
// as total_order_seek via NewIndexIterator
bool PrefixExtractorChanged(const TableProperties* table_properties,
const SliceTransform* prefix_extractor) {
bool PrefixExtractorChanged(
std::shared_ptr<const TableProperties> table_properties,
const SliceTransform* prefix_extractor) {
// BlockBasedTableOptions::kHashSearch requires prefix_extractor to be set.
// Turn off hash index in prefix_extractor is not set; if prefix_extractor
// is set but prefix_extractor_block is not set, also disable hash index
@@ -211,7 +212,7 @@ class PartitionIndexReader : public IndexReader, public Cleanable {
const InternalKeyComparator* icomparator,
IndexReader** index_reader,
const PersistentCacheOptions& cache_options,
const int level, const bool index_key_includes_seq) {
const int level) {
std::unique_ptr<Block> index_block;
auto s = ReadBlockFromFile(
file, prefetch_buffer, footer, ReadOptions(), index_handle,
@@ -220,9 +221,9 @@ class PartitionIndexReader : public IndexReader, public Cleanable {
kDisableGlobalSequenceNumber, 0 /* read_amp_bytes_per_bit */);
if (s.ok()) {
*index_reader = new PartitionIndexReader(
table, icomparator, std::move(index_block), ioptions.statistics,
level, index_key_includes_seq);
*index_reader =
new PartitionIndexReader(table, icomparator, std::move(index_block),
ioptions.statistics, level);
}
return s;
@@ -236,21 +237,15 @@ class PartitionIndexReader : public IndexReader, public Cleanable {
if (!partition_map_.empty()) {
return NewTwoLevelIterator(
new BlockBasedTable::PartitionedIndexIteratorState(
table_, &partition_map_, index_key_includes_seq_),
index_block_->NewIterator(icomparator_,
icomparator_->user_comparator(), nullptr,
true, nullptr, index_key_includes_seq_));
table_, partition_map_.size() ? &partition_map_ : nullptr),
index_block_->NewIterator(icomparator_, nullptr, true));
} else {
auto ro = ReadOptions();
ro.fill_cache = fill_cache;
bool kIsIndex = true;
return new BlockBasedTableIterator(
table_, ro, *icomparator_,
index_block_->NewIterator(icomparator_,
icomparator_->user_comparator(), nullptr,
true, nullptr, index_key_includes_seq_),
false,
/* prefix_extractor */ nullptr, kIsIndex, index_key_includes_seq_);
index_block_->NewIterator(icomparator_, nullptr, true), false,
/* prefix_extractor */ nullptr);
}
// TODO(myabandeh): Update TwoLevelIterator to be able to make use of
// on-stack BlockIter while the state is on heap. Currentlly it assumes
@@ -263,8 +258,7 @@ class PartitionIndexReader : public IndexReader, public Cleanable {
auto rep = table_->rep_;
BlockIter biter;
BlockHandle handle;
index_block_->NewIterator(icomparator_, icomparator_->user_comparator(),
&biter, true, nullptr, index_key_includes_seq_);
index_block_->NewIterator(icomparator_, &biter, true);
// Index partitions are assumed to be consecuitive. Prefetch them all.
// Read the first block offset
biter.SeekToFirst();
@@ -346,32 +340,23 @@ class PartitionIndexReader : public IndexReader, public Cleanable {
virtual size_t ApproximateMemoryUsage() const override {
assert(index_block_);
size_t usage = index_block_->ApproximateMemoryUsage();
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
usage += malloc_usable_size((void*)this);
#else
usage += sizeof(*this);
#endif // ROCKSDB_MALLOC_USABLE_SIZE
// TODO(myabandeh): more accurate estimate of partition_map_ mem usage
return usage;
return index_block_->ApproximateMemoryUsage();
}
private:
PartitionIndexReader(BlockBasedTable* table,
const InternalKeyComparator* icomparator,
std::unique_ptr<Block>&& index_block, Statistics* stats,
const int /*level*/, const bool index_key_includes_seq)
const int /*level*/)
: IndexReader(icomparator, stats),
table_(table),
index_block_(std::move(index_block)),
index_key_includes_seq_(index_key_includes_seq) {
index_block_(std::move(index_block)) {
assert(index_block_ != nullptr);
}
BlockBasedTable* table_;
std::unique_ptr<Block> index_block_;
std::unordered_map<uint64_t, BlockBasedTable::CachableEntry<Block>>
partition_map_;
const bool index_key_includes_seq_;
};
// Index that allows binary search lookup for the first key of each block.
@@ -389,8 +374,7 @@ class BinarySearchIndexReader : public IndexReader {
const ImmutableCFOptions& ioptions,
const InternalKeyComparator* icomparator,
IndexReader** index_reader,
const PersistentCacheOptions& cache_options,
const bool index_key_includes_seq) {
const PersistentCacheOptions& cache_options) {
std::unique_ptr<Block> index_block;
auto s = ReadBlockFromFile(
file, prefetch_buffer, footer, ReadOptions(), index_handle,
@@ -400,8 +384,7 @@ class BinarySearchIndexReader : public IndexReader {
if (s.ok()) {
*index_reader = new BinarySearchIndexReader(
icomparator, std::move(index_block), ioptions.statistics,
index_key_includes_seq);
icomparator, std::move(index_block), ioptions.statistics);
}
return s;
@@ -410,9 +393,7 @@ class BinarySearchIndexReader : public IndexReader {
virtual InternalIterator* NewIterator(BlockIter* iter = nullptr,
bool /*dont_care*/ = true,
bool /*dont_care*/ = true) override {
return index_block_->NewIterator(icomparator_,
icomparator_->user_comparator(), iter,
true, nullptr, index_key_includes_seq_);
return index_block_->NewIterator(icomparator_, iter, true);
}
virtual size_t size() const override { return index_block_->size(); }
@@ -422,26 +403,17 @@ class BinarySearchIndexReader : public IndexReader {
virtual size_t ApproximateMemoryUsage() const override {
assert(index_block_);
size_t usage = index_block_->ApproximateMemoryUsage();
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
usage += malloc_usable_size((void*)this);
#else
usage += sizeof(*this);
#endif // ROCKSDB_MALLOC_USABLE_SIZE
return usage;
return index_block_->ApproximateMemoryUsage();
}
private:
BinarySearchIndexReader(const InternalKeyComparator* icomparator,
std::unique_ptr<Block>&& index_block,
Statistics* stats, const bool index_key_includes_seq)
: IndexReader(icomparator, stats),
index_block_(std::move(index_block)),
index_key_includes_seq_(index_key_includes_seq) {
Statistics* stats)
: IndexReader(icomparator, stats), index_block_(std::move(index_block)) {
assert(index_block_ != nullptr);
}
std::unique_ptr<Block> index_block_;
const bool index_key_includes_seq_;
};
// Index that leverages an internal hash table to quicken the lookup for a given
@@ -457,8 +429,7 @@ class HashIndexReader : public IndexReader {
InternalIterator* meta_index_iter,
IndexReader** index_reader,
bool /*hash_index_allow_collision*/,
const PersistentCacheOptions& cache_options,
const bool index_key_includes_seq) {
const PersistentCacheOptions& cache_options) {
std::unique_ptr<Block> index_block;
auto s = ReadBlockFromFile(
file, prefetch_buffer, footer, ReadOptions(), index_handle,
@@ -476,7 +447,7 @@ class HashIndexReader : public IndexReader {
auto new_index_reader =
new HashIndexReader(icomparator, std::move(index_block),
ioptions.statistics, index_key_includes_seq);
ioptions.statistics);
*index_reader = new_index_reader;
// Get prefixes block
@@ -533,9 +504,7 @@ class HashIndexReader : public IndexReader {
virtual InternalIterator* NewIterator(BlockIter* iter = nullptr,
bool total_order_seek = true,
bool /*dont_care*/ = true) override {
return index_block_->NewIterator(
icomparator_, icomparator_->user_comparator(), iter, total_order_seek,
nullptr, index_key_includes_seq_);
return index_block_->NewIterator(icomparator_, iter, total_order_seek);
}
virtual size_t size() const override { return index_block_->size(); }
@@ -545,23 +514,14 @@ class HashIndexReader : public IndexReader {
virtual size_t ApproximateMemoryUsage() const override {
assert(index_block_);
size_t usage = index_block_->ApproximateMemoryUsage();
usage += prefixes_contents_.usable_size();
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
usage += malloc_usable_size((void*)this);
#else
usage += sizeof(*this);
#endif // ROCKSDB_MALLOC_USABLE_SIZE
return usage;
return index_block_->ApproximateMemoryUsage() +
prefixes_contents_.data.size();
}
private:
HashIndexReader(const InternalKeyComparator* icomparator,
std::unique_ptr<Block>&& index_block, Statistics* stats,
const bool index_key_includes_seq)
: IndexReader(icomparator, stats),
index_block_(std::move(index_block)),
index_key_includes_seq_(index_key_includes_seq) {
std::unique_ptr<Block>&& index_block, Statistics* stats)
: IndexReader(icomparator, stats), index_block_(std::move(index_block)) {
assert(index_block_ != nullptr);
}
@@ -570,7 +530,6 @@ class HashIndexReader : public IndexReader {
std::unique_ptr<Block> index_block_;
BlockContents prefixes_contents_;
const bool index_key_includes_seq_;
};
// Helper function to setup the cache key's prefix for the Table.
@@ -720,17 +679,8 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
std::unique_ptr<FilePrefetchBuffer> prefetch_buffer;
// prefetch both index and filters, down to all partitions
const bool prefetch_all = prefetch_index_and_filter_in_cache || level == 0;
const bool preload_all = !table_options.cache_index_and_filter_blocks;
// Before read footer, readahead backwards to prefetch data. Do more readahead
// if we're going to read index/filter.
// TODO: This may incorrectly select small readahead in case partitioned
// index/filter is enabled and top-level partition pinning is enabled. That's
// because we need to issue readahead before we read the properties, at which
// point we don't yet know the index type.
const size_t kTailPrefetchSize =
prefetch_all || preload_all ? 512 * 1024 : 4 * 1024;
// Before read footer, readahead backwards to prefetch data
const size_t kTailPrefetchSize = 512 * 1024;
size_t prefetch_off;
size_t prefetch_len;
if (file_size < kTailPrefetchSize) {
@@ -926,43 +876,23 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
rep->ioptions.info_log);
}
BlockBasedTableOptions::IndexType index_type = new_table->UpdateIndexType();
// prefetch the first level of index
const bool prefetch_index =
prefetch_all ||
(table_options.pin_top_level_index_and_filter &&
index_type == BlockBasedTableOptions::kTwoLevelIndexSearch);
// prefetch the first level of filter
const bool prefetch_filter =
prefetch_all || (table_options.pin_top_level_index_and_filter &&
rep->filter_type == Rep::FilterType::kPartitionedFilter);
// Partition fitlers cannot be enabled without partition indexes
assert(!prefetch_filter || prefetch_index);
// pin both index and filters, down to all partitions
const bool pin_all =
const bool pin =
rep->table_options.pin_l0_filter_and_index_blocks_in_cache && level == 0;
// pin the first level of index
const bool pin_index =
pin_all || (table_options.pin_top_level_index_and_filter &&
index_type == BlockBasedTableOptions::kTwoLevelIndexSearch);
// pin the first level of filter
const bool pin_filter =
pin_all || (table_options.pin_top_level_index_and_filter &&
rep->filter_type == Rep::FilterType::kPartitionedFilter);
// pre-fetching of blocks is turned on
// Will use block cache for index/filter blocks access
// Always prefetch index and filter for level 0
if (table_options.cache_index_and_filter_blocks) {
assert(table_options.block_cache != nullptr);
if (prefetch_index) {
if (prefetch_index_and_filter_in_cache || level == 0) {
assert(table_options.block_cache != nullptr);
// Hack: Call NewIndexIterator() to implicitly add index to the
// block_cache
CachableEntry<IndexReader> index_entry;
bool prefix_extractor_changed = false;
// check prefix_extractor match only if hash based index is used
if (rep->index_type == BlockBasedTableOptions::kHashSearch) {
prefix_extractor_changed = PrefixExtractorChanged(
rep->table_properties.get(), prefix_extractor);
prefix_extractor_changed =
PrefixExtractorChanged(rep->table_properties, prefix_extractor);
}
unique_ptr<InternalIterator> iter(new_table->NewIndexIterator(
ReadOptions(), prefix_extractor_changed, nullptr, &index_entry));
@@ -972,29 +902,27 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
// On success it should give us ownership of the `CachableEntry` by
// populating `index_entry`.
assert(index_entry.value != nullptr);
if (prefetch_all) {
index_entry.value->CacheDependencies(pin_all);
}
if (pin_index) {
index_entry.value->CacheDependencies(pin);
if (pin) {
rep->index_entry = std::move(index_entry);
} else {
index_entry.Release(table_options.block_cache.get());
}
}
}
if (s.ok() && prefetch_filter) {
// Hack: Call GetFilter() to implicitly add filter to the block_cache
auto filter_entry = new_table->GetFilter(prefix_extractor);
if (filter_entry.value != nullptr && prefetch_all) {
filter_entry.value->CacheDependencies(pin_all, prefix_extractor);
}
// if pin_filter is true then save it in rep_->filter_entry; it will be
// released in the destructor only, hence it will be pinned in the
// cache while this reader is alive
if (pin_filter) {
rep->filter_entry = filter_entry;
} else {
filter_entry.Release(table_options.block_cache.get());
// Hack: Call GetFilter() to implicitly add filter to the block_cache
auto filter_entry = new_table->GetFilter(prefix_extractor);
if (filter_entry.value != nullptr) {
filter_entry.value->CacheDependencies(pin, prefix_extractor);
}
// if pin_l0_filter_and_index_blocks_in_cache is true, and this is
// a level0 file, then save it in rep_->filter_entry; it will be
// released in the destructor only, hence it will be pinned in the
// cache while this reader is alive
if (pin) {
rep->filter_entry = filter_entry;
} else {
filter_entry.Release(table_options.block_cache.get());
}
}
}
} else {
@@ -1010,7 +938,7 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
// are hence follow the configuration for pin and prefetch regardless of
// the value of cache_index_and_filter_blocks
if (prefetch_index_and_filter_in_cache || level == 0) {
rep->index_reader->CacheDependencies(pin_all);
rep->index_reader->CacheDependencies(pin);
}
// Set filter block
@@ -1023,7 +951,7 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
// Refer to the comment above about paritioned indexes always being
// cached
if (filter && (prefetch_index_and_filter_in_cache || level == 0)) {
filter->CacheDependencies(pin_all, prefix_extractor);
filter->CacheDependencies(pin, prefix_extractor);
}
}
} else {
@@ -1098,8 +1026,7 @@ Status BlockBasedTable::ReadMetaBlock(Rep* rep,
*meta_block = std::move(meta);
// meta block uses bytewise comparator.
iter->reset(meta_block->get()->NewIterator(BytewiseComparator(),
BytewiseComparator()));
iter->reset(meta_block->get()->NewIterator(BytewiseComparator()));
return Status::OK();
}
@@ -1168,34 +1095,40 @@ Status BlockBasedTable::GetDataBlockFromCache(
assert(block->value->compression_type() == kNoCompression);
if (block_cache != nullptr && block->value->cachable() &&
read_options.fill_cache) {
size_t charge = block->value->ApproximateMemoryUsage();
s = block_cache->Insert(block_cache_key, block->value, charge,
&DeleteCachedEntry<Block>,
&(block->cache_handle));
block_cache->TEST_mark_as_data_block(block_cache_key, charge);
s = block_cache->Insert(
block_cache_key, block->value, block->value->usable_size(),
&DeleteCachedEntry<Block>, &(block->cache_handle));
block_cache->TEST_mark_as_data_block(block_cache_key,
block->value->usable_size());
if (s.ok()) {
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, charge);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE,
block->value->usable_size());
} else {
RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE,
block->value->usable_size());
}
if (is_index) {
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_INDEX_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
get_context->RecordCounters(BLOCK_CACHE_INDEX_BYTES_INSERT,
block->value->usable_size());
} else {
RecordTick(statistics, BLOCK_CACHE_INDEX_ADD);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT,
block->value->usable_size());
}
} else {
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_DATA_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_DATA_BYTES_INSERT, charge);
get_context->RecordCounters(BLOCK_CACHE_DATA_BYTES_INSERT,
block->value->usable_size());
} else {
RecordTick(statistics, BLOCK_CACHE_DATA_ADD);
RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT, charge);
RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT,
block->value->usable_size());
}
}
} else {
@@ -1248,7 +1181,7 @@ Status BlockBasedTable::PutDataBlockToCache(
if (block_cache_compressed != nullptr && raw_block != nullptr &&
raw_block->cachable()) {
s = block_cache_compressed->Insert(compressed_block_cache_key, raw_block,
raw_block->ApproximateMemoryUsage(),
raw_block->usable_size(),
&DeleteCachedEntry<Block>);
if (s.ok()) {
// Avoid the following code to delete this cached block.
@@ -1263,35 +1196,41 @@ Status BlockBasedTable::PutDataBlockToCache(
// insert into uncompressed block cache
assert((block->value->compression_type() == kNoCompression));
if (block_cache != nullptr && block->value->cachable()) {
size_t charge = block->value->ApproximateMemoryUsage();
s = block_cache->Insert(block_cache_key, block->value, charge,
&DeleteCachedEntry<Block>, &(block->cache_handle),
priority);
block_cache->TEST_mark_as_data_block(block_cache_key, charge);
s = block_cache->Insert(
block_cache_key, block->value, block->value->usable_size(),
&DeleteCachedEntry<Block>, &(block->cache_handle), priority);
block_cache->TEST_mark_as_data_block(block_cache_key,
block->value->usable_size());
if (s.ok()) {
assert(block->cache_handle != nullptr);
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, charge);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE,
block->value->usable_size());
} else {
RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE,
block->value->usable_size());
}
if (is_index) {
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_INDEX_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
get_context->RecordCounters(BLOCK_CACHE_INDEX_BYTES_INSERT,
block->value->usable_size());
} else {
RecordTick(statistics, BLOCK_CACHE_INDEX_ADD);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT,
block->value->usable_size());
}
} else {
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_DATA_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_DATA_BYTES_INSERT, charge);
get_context->RecordCounters(BLOCK_CACHE_DATA_BYTES_INSERT,
block->value->usable_size());
} else {
RecordTick(statistics, BLOCK_CACHE_DATA_ADD);
RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT, charge);
RecordTick(statistics, BLOCK_CACHE_DATA_BYTES_INSERT,
block->value->usable_size());
}
}
assert(reinterpret_cast<Block*>(
@@ -1344,9 +1283,7 @@ FilterBlockReader* BlockBasedTable::ReadFilter(
return new PartitionedFilterBlockReader(
rep->prefix_filtering ? prefix_extractor : nullptr,
rep->whole_key_filtering, std::move(block), nullptr,
rep->ioptions.statistics, rep->internal_comparator, this,
rep_->table_properties == nullptr ||
!rep_->table_properties->index_key_is_user_key);
rep->ioptions.statistics, rep->internal_comparator, this);
}
case Rep::FilterType::kBlockFilter:
@@ -1428,23 +1365,24 @@ BlockBasedTable::CachableEntry<FilterBlockReader> BlockBasedTable::GetFilter(
filter = ReadFilter(prefetch_buffer, filter_blk_handle,
is_a_filter_partition, prefix_extractor);
if (filter != nullptr) {
size_t usage = filter->ApproximateMemoryUsage();
Status s = block_cache->Insert(
key, filter, usage, &DeleteCachedFilterEntry, &cache_handle,
key, filter, filter->size(), &DeleteCachedFilterEntry, &cache_handle,
rep_->table_options.cache_index_and_filter_blocks_with_high_priority
? Cache::Priority::HIGH
: Cache::Priority::LOW);
if (s.ok()) {
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, usage);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, filter->size());
get_context->RecordCounters(BLOCK_CACHE_FILTER_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_FILTER_BYTES_INSERT, usage);
get_context->RecordCounters(BLOCK_CACHE_FILTER_BYTES_INSERT,
filter->size());
} else {
RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, usage);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, filter->size());
RecordTick(statistics, BLOCK_CACHE_FILTER_ADD);
RecordTick(statistics, BLOCK_CACHE_FILTER_BYTES_INSERT, usage);
RecordTick(statistics, BLOCK_CACHE_FILTER_BYTES_INSERT,
filter->size());
}
} else {
RecordTick(statistics, BLOCK_CACHE_ADD_FAILURES);
@@ -1510,27 +1448,27 @@ InternalIterator* BlockBasedTable::NewIndexIterator(
TEST_SYNC_POINT("BlockBasedTable::NewIndexIterator::thread1:1");
TEST_SYNC_POINT("BlockBasedTable::NewIndexIterator::thread2:3");
TEST_SYNC_POINT("BlockBasedTable::NewIndexIterator::thread1:4");
size_t charge = 0;
if (s.ok()) {
assert(index_reader != nullptr);
charge = index_reader->ApproximateMemoryUsage();
s = block_cache->Insert(
key, index_reader, charge, &DeleteCachedIndexEntry, &cache_handle,
key, index_reader, index_reader->usable_size(),
&DeleteCachedIndexEntry, &cache_handle,
rep_->table_options.cache_index_and_filter_blocks_with_high_priority
? Cache::Priority::HIGH
: Cache::Priority::LOW);
}
if (s.ok()) {
size_t usable_size = index_reader->usable_size();
if (get_context != nullptr) {
get_context->RecordCounters(BLOCK_CACHE_ADD, 1);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, charge);
get_context->RecordCounters(BLOCK_CACHE_BYTES_WRITE, usable_size);
} else {
RecordTick(statistics, BLOCK_CACHE_ADD);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, charge);
RecordTick(statistics, BLOCK_CACHE_BYTES_WRITE, usable_size);
}
RecordTick(statistics, BLOCK_CACHE_INDEX_ADD);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, charge);
RecordTick(statistics, BLOCK_CACHE_INDEX_BYTES_INSERT, usable_size);
} else {
if (index_reader != nullptr) {
delete index_reader;
@@ -1564,15 +1502,14 @@ InternalIterator* BlockBasedTable::NewIndexIterator(
BlockIter* BlockBasedTable::NewDataBlockIterator(
Rep* rep, const ReadOptions& ro, const Slice& index_value,
BlockIter* input_iter, bool is_index, bool key_includes_seq,
GetContext* get_context) {
BlockIter* input_iter, bool is_index, GetContext* get_context) {
BlockHandle handle;
Slice input = index_value;
// We intentionally allow extra stuff in index_value so that we
// can add more features in the future.
Status s = handle.DecodeFrom(&input);
return NewDataBlockIterator(rep, ro, handle, input_iter, is_index,
key_includes_seq, get_context, s);
get_context, s);
}
// Convert an index iterator value (i.e., an encoded BlockHandle)
@@ -1581,8 +1518,7 @@ BlockIter* BlockBasedTable::NewDataBlockIterator(
// If input_iter is not null, update this iter and return it
BlockIter* BlockBasedTable::NewDataBlockIterator(
Rep* rep, const ReadOptions& ro, const BlockHandle& handle,
BlockIter* input_iter, bool is_index, bool key_includes_seq,
GetContext* get_context, Status s) {
BlockIter* input_iter, bool is_index, GetContext* get_context, Status s) {
PERF_TIMER_GUARD(new_table_block_iter_nanos);
const bool no_io = (ro.read_tier == kBlockCacheTier);
@@ -1615,12 +1551,11 @@ BlockIter* BlockBasedTable::NewDataBlockIterator(
{
StopWatch sw(rep->ioptions.env, rep->ioptions.statistics,
READ_BLOCK_GET_MICROS);
s = ReadBlockFromFile(
rep->file.get(), nullptr /* prefetch_buffer */, rep->footer, ro,
handle, &block_value, rep->ioptions, rep->blocks_maybe_compressed,
compression_dict, rep->persistent_cache_options,
is_index ? kDisableGlobalSequenceNumber : rep->global_seqno,
rep->table_options.read_amp_bytes_per_bit);
s = ReadBlockFromFile(rep->file.get(), nullptr /* prefetch_buffer */,
rep->footer, ro, handle, &block_value, rep->ioptions,
rep->blocks_maybe_compressed, compression_dict,
rep->persistent_cache_options, rep->global_seqno,
rep->table_options.read_amp_bytes_per_bit);
}
if (s.ok()) {
block.value = block_value.release();
@@ -1629,9 +1564,8 @@ BlockIter* BlockBasedTable::NewDataBlockIterator(
if (s.ok()) {
assert(block.value != nullptr);
iter = block.value->NewIterator(
&rep->internal_comparator, rep->internal_comparator.user_comparator(),
iter, true, rep->ioptions.statistics, key_includes_seq);
iter = block.value->NewIterator(&rep->internal_comparator, iter, true,
rep->ioptions.statistics);
if (block.cache_handle != nullptr) {
iter->RegisterCleanup(&ReleaseCachedEntry, block_cache,
block.cache_handle);
@@ -1657,9 +1591,8 @@ BlockIter* BlockBasedTable::NewDataBlockIterator(
static_cast<int>(kExtraCacheKeyPrefix + kMaxVarint64Length));
Slice unique_key =
Slice(cache_key, static_cast<size_t>(end - cache_key));
s = block_cache->Insert(unique_key, nullptr,
block.value->ApproximateMemoryUsage(), nullptr,
&cache_handle);
s = block_cache->Insert(unique_key, nullptr, block.value->usable_size(),
nullptr, &cache_handle);
if (s.ok()) {
if (cache_handle != nullptr) {
iter->RegisterCleanup(&ForceReleaseCachedEntry, block_cache,
@@ -1720,8 +1653,7 @@ Status BlockBasedTable::MaybeLoadDataBlockToCache(
rep->file.get(), prefetch_buffer, rep->footer, ro, handle,
&raw_block, rep->ioptions,
block_cache_compressed == nullptr && rep->blocks_maybe_compressed,
compression_dict, rep->persistent_cache_options,
is_index ? kDisableGlobalSequenceNumber : rep->global_seqno,
compression_dict, rep->persistent_cache_options, rep->global_seqno,
rep->table_options.read_amp_bytes_per_bit);
}
@@ -1745,11 +1677,8 @@ Status BlockBasedTable::MaybeLoadDataBlockToCache(
BlockBasedTable::PartitionedIndexIteratorState::PartitionedIndexIteratorState(
BlockBasedTable* table,
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map,
bool index_key_includes_seq)
: table_(table),
block_map_(block_map),
index_key_includes_seq_(index_key_includes_seq) {}
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map)
: table_(table), block_map_(block_map) {}
const size_t BlockBasedTableIterator::kMaxReadaheadSize = 256 * 1024;
@@ -1772,9 +1701,8 @@ BlockBasedTable::PartitionedIndexIteratorState::NewSecondaryIterator(
assert(block_cache);
RecordTick(rep->ioptions.statistics, BLOCK_CACHE_BYTES_READ,
block_cache->GetUsage(block->second.cache_handle));
return block->second.value->NewIterator(
&rep->internal_comparator, rep->internal_comparator.user_comparator(),
nullptr, true, rep->ioptions.statistics, index_key_includes_seq_);
return block->second.value->NewIterator(&rep->internal_comparator, nullptr,
true, rep->ioptions.statistics);
}
// Create an empty iterator
return new BlockIter();
@@ -1842,10 +1770,7 @@ bool BlockBasedTable::PrefixMayMatch(const Slice& internal_key,
// and we're not really sure that we're past the end
// of the file
may_match = iiter->status().IsIncomplete();
} else if ((rep_->table_properties &&
rep_->table_properties->index_key_is_user_key
? iiter->key()
: ExtractUserKey(iiter->key()))
} else if (ExtractUserKey(iiter->key())
.starts_with(ExtractUserKey(internal_prefix))) {
// we need to check for this subtle case because our only
// guarantee is that "the key is a string >= last key in that data
@@ -1911,11 +1836,7 @@ void BlockBasedTableIterator::Seek(const Slice& target) {
FindKeyForward();
assert(!data_block_iter_.Valid() ||
(key_includes_seq_ &&
icomp_.Compare(target, data_block_iter_.key()) <= 0) ||
(!key_includes_seq_ &&
icomp_.user_comparator()->Compare(ExtractUserKey(target),
data_block_iter_.key()) <= 0));
icomp_.Compare(target, data_block_iter_.key()) <= 0);
}
void BlockBasedTableIterator::SeekForPrev(const Slice& target) {
@@ -2031,8 +1952,7 @@ void BlockBasedTableIterator::InitDataBlock() {
}
BlockBasedTable::NewDataBlockIterator(rep, read_options_, data_block_handle,
&data_block_iter_, is_index_,
key_includes_seq_,
&data_block_iter_, false,
/* get_context */ nullptr, s);
block_iter_points_to_real_block_ = true;
}
@@ -2103,26 +2023,25 @@ InternalIterator* BlockBasedTable::NewIterator(
const ReadOptions& read_options, const SliceTransform* prefix_extractor,
Arena* arena, bool skip_filters) {
bool prefix_extractor_changed =
PrefixExtractorChanged(rep_->table_properties.get(), prefix_extractor);
const bool kIsNotIndex = false;
PrefixExtractorChanged(rep_->table_properties, prefix_extractor);
if (arena == nullptr) {
return new BlockBasedTableIterator(
this, read_options, rep_->internal_comparator,
NewIndexIterator(
read_options,
prefix_extractor_changed &&
rep_->index_type == BlockBasedTableOptions::kHashSearch),
rep_->index_type == BlockBasedTableOptions::kHashSearch),
!skip_filters && !read_options.total_order_seek &&
prefix_extractor != nullptr && !prefix_extractor_changed,
prefix_extractor, kIsNotIndex);
prefix_extractor != nullptr && !prefix_extractor_changed,
prefix_extractor);
} else {
auto* mem = arena->AllocateAligned(sizeof(BlockBasedTableIterator));
return new (mem) BlockBasedTableIterator(
this, read_options, rep_->internal_comparator,
NewIndexIterator(read_options, prefix_extractor_changed),
!skip_filters && !read_options.total_order_seek &&
prefix_extractor != nullptr && !prefix_extractor_changed,
prefix_extractor, kIsNotIndex);
prefix_extractor != nullptr && !prefix_extractor_changed,
prefix_extractor);
}
}
@@ -2142,8 +2061,7 @@ InternalIterator* BlockBasedTable::NewRangeTombstoneIterator(
assert(block_cache != nullptr);
if (block_cache->Ref(rep_->range_del_entry.cache_handle)) {
auto iter = rep_->range_del_entry.value->NewIterator(
&rep_->internal_comparator,
rep_->internal_comparator.user_comparator(), nullptr /* iter */,
&rep_->internal_comparator, nullptr /* iter */,
true /* total_order_seek */, rep_->ioptions.statistics);
iter->RegisterCleanup(&ReleaseCachedEntry, block_cache,
rep_->range_del_entry.cache_handle);
@@ -2189,7 +2107,6 @@ Status BlockBasedTable::Get(const ReadOptions& read_options, const Slice& key,
GetContext* get_context,
const SliceTransform* prefix_extractor,
bool skip_filters) {
assert(key.size() >= 8); // key must be internal key
Status s;
const bool no_io = read_options.read_tier == kBlockCacheTier;
CachableEntry<FilterBlockReader> filter_entry;
@@ -2211,8 +2128,8 @@ Status BlockBasedTable::Get(const ReadOptions& read_options, const Slice& key,
// BlockPrefixIndex. Only do this check when index_type is kHashSearch.
bool prefix_extractor_changed = false;
if (rep_->index_type == BlockBasedTableOptions::kHashSearch) {
prefix_extractor_changed = PrefixExtractorChanged(
rep_->table_properties.get(), prefix_extractor);
prefix_extractor_changed =
PrefixExtractorChanged(rep_->table_properties, prefix_extractor);
}
auto iiter = NewIndexIterator(read_options, prefix_extractor_changed,
&iiter_on_stack, /* index_entry */ nullptr,
@@ -2298,7 +2215,6 @@ Status BlockBasedTable::Get(const ReadOptions& read_options, const Slice& key,
Status BlockBasedTable::Prefetch(const Slice* const begin,
const Slice* const end) {
auto& comparator = rep_->internal_comparator;
auto user_comparator = comparator.user_comparator();
// pre-condition
if (begin && end && comparator.Compare(*begin, *end) > 0) {
return Status::InvalidArgument(*begin, *end);
@@ -2322,12 +2238,8 @@ Status BlockBasedTable::Prefetch(const Slice* const begin,
for (begin ? iiter->Seek(*begin) : iiter->SeekToFirst(); iiter->Valid();
iiter->Next()) {
Slice block_handle = iiter->value();
const bool is_user_key = rep_->table_properties &&
rep_->table_properties->index_key_is_user_key > 0;
if (end &&
((!is_user_key && comparator.Compare(iiter->key(), *end) >= 0) ||
(is_user_key &&
user_comparator->Compare(iiter->key(), ExtractUserKey(*end)) >= 0))) {
if (end && comparator.Compare(iiter->key(), *end) >= 0) {
if (prefetching_boundary_page) {
break;
}
@@ -2442,11 +2354,18 @@ bool BlockBasedTable::TEST_KeyInCache(const ReadOptions& options,
return in_cache;
}
BlockBasedTableOptions::IndexType BlockBasedTable::UpdateIndexType() {
// REQUIRES: The following fields of rep_ should have already been populated:
// 1. file
// 2. index_handle,
// 3. options
// 4. internal_comparator
// 5. index_type
Status BlockBasedTable::CreateIndexReader(
FilePrefetchBuffer* prefetch_buffer, IndexReader** index_reader,
InternalIterator* preloaded_meta_index_iter, int level) {
// Some old version of block-based tables don't have index type present in
// table properties. If that's the case we can safely use the kBinarySearch.
BlockBasedTableOptions::IndexType index_type_on_file =
BlockBasedTableOptions::kBinarySearch;
auto index_type_on_file = BlockBasedTableOptions::kBinarySearch;
if (rep_->table_properties) {
auto& props = rep_->table_properties->user_collected_properties;
auto pos = props.find(BlockBasedTablePropertyNames::kIndexType);
@@ -2457,19 +2376,6 @@ BlockBasedTableOptions::IndexType BlockBasedTable::UpdateIndexType() {
rep_->index_type = index_type_on_file;
}
}
return index_type_on_file;
}
// REQUIRES: The following fields of rep_ should have already been populated:
// 1. file
// 2. index_handle,
// 3. options
// 4. internal_comparator
// 5. index_type
Status BlockBasedTable::CreateIndexReader(
FilePrefetchBuffer* prefetch_buffer, IndexReader** index_reader,
InternalIterator* preloaded_meta_index_iter, int level) {
auto index_type_on_file = UpdateIndexType();
auto file = rep_->file.get();
const InternalKeyComparator* icomparator = &rep_->internal_comparator;
@@ -2486,16 +2392,12 @@ Status BlockBasedTable::CreateIndexReader(
return PartitionIndexReader::Create(
this, file, prefetch_buffer, footer, footer.index_handle(),
rep_->ioptions, icomparator, index_reader,
rep_->persistent_cache_options, level,
rep_->table_properties == nullptr ||
rep_->table_properties->index_key_is_user_key == 0);
rep_->persistent_cache_options, level);
}
case BlockBasedTableOptions::kBinarySearch: {
return BinarySearchIndexReader::Create(
file, prefetch_buffer, footer, footer.index_handle(), rep_->ioptions,
icomparator, index_reader, rep_->persistent_cache_options,
rep_->table_properties == nullptr ||
rep_->table_properties->index_key_is_user_key == 0);
icomparator, index_reader, rep_->persistent_cache_options);
}
case BlockBasedTableOptions::kHashSearch: {
std::unique_ptr<Block> meta_guard;
@@ -2513,9 +2415,7 @@ Status BlockBasedTable::CreateIndexReader(
return BinarySearchIndexReader::Create(
file, prefetch_buffer, footer, footer.index_handle(),
rep_->ioptions, icomparator, index_reader,
rep_->persistent_cache_options,
rep_->table_properties == nullptr ||
rep_->table_properties->index_key_is_user_key == 0);
rep_->persistent_cache_options);
}
meta_index_iter = meta_iter_guard.get();
}
@@ -2524,9 +2424,7 @@ Status BlockBasedTable::CreateIndexReader(
rep_->internal_prefix_transform.get(), footer, file, prefetch_buffer,
rep_->ioptions, icomparator, footer.index_handle(), meta_index_iter,
index_reader, rep_->hash_index_allow_collision,
rep_->persistent_cache_options,
rep_->table_properties == nullptr ||
rep_->table_properties->index_key_is_user_key == 0);
rep_->persistent_cache_options);
}
default: {
std::string error_message =
@@ -2811,23 +2709,16 @@ Status BlockBasedTable::DumpIndexBlock(WritableFile* out_file) {
break;
}
Slice key = blockhandles_iter->key();
Slice user_key;
InternalKey ikey;
if (rep_->table_properties &&
rep_->table_properties->index_key_is_user_key != 0) {
user_key = key;
} else {
ikey.DecodeFrom(key);
user_key = ikey.user_key();
}
ikey.DecodeFrom(key);
out_file->Append(" HEX ");
out_file->Append(user_key.ToString(true).c_str());
out_file->Append(ikey.user_key().ToString(true).c_str());
out_file->Append(": ");
out_file->Append(blockhandles_iter->value().ToString(true).c_str());
out_file->Append("\n");
std::string str_key = user_key.ToString();
std::string str_key = ikey.user_key().ToString();
std::string res_key("");
char cspace = ' ';
for (size_t i = 0; i < str_key.size(); i++) {
@@ -2965,7 +2856,7 @@ void DeleteCachedFilterEntry(const Slice& /*key*/, void* value) {
FilterBlockReader* filter = reinterpret_cast<FilterBlockReader*>(value);
if (filter->statistics() != nullptr) {
RecordTick(filter->statistics(), BLOCK_CACHE_FILTER_BYTES_EVICT,
filter->ApproximateMemoryUsage());
filter->size());
}
delete filter;
}
@@ -2974,7 +2865,7 @@ void DeleteCachedIndexEntry(const Slice& /*key*/, void* value) {
IndexReader* index_reader = reinterpret_cast<IndexReader*>(value);
if (index_reader->statistics() != nullptr) {
RecordTick(index_reader->statistics(), BLOCK_CACHE_INDEX_BYTES_EVICT,
index_reader->ApproximateMemoryUsage());
index_reader->usable_size());
}
delete index_reader;
}
+8 -23
View File
@@ -217,13 +217,11 @@ class BlockBasedTable : public TableReader {
const Slice& index_value,
BlockIter* input_iter = nullptr,
bool is_index = false,
bool key_includes_seq = true,
GetContext* get_context = nullptr);
static BlockIter* NewDataBlockIterator(Rep* rep, const ReadOptions& ro,
const BlockHandle& block_hanlde,
BlockIter* input_iter = nullptr,
bool is_index = false,
bool key_includes_seq = true,
GetContext* get_context = nullptr,
Status s = Status());
@@ -325,9 +323,6 @@ class BlockBasedTable : public TableReader {
void ReadMeta(const Footer& footer);
// Figure the index type, update it in rep_, and also return it.
BlockBasedTableOptions::IndexType UpdateIndexType();
// Create a index reader based on the index type stored in the table.
// Optionally, user can pass a preloaded meta_index_iter for the index that
// need to access extra meta blocks for index construction. This parameter
@@ -383,15 +378,13 @@ class BlockBasedTable::PartitionedIndexIteratorState
public:
PartitionedIndexIteratorState(
BlockBasedTable* table,
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map,
const bool index_key_includes_seq);
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map = nullptr);
InternalIterator* NewSecondaryIterator(const Slice& index_value) override;
private:
// Don't own table_
BlockBasedTable* table_;
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map_;
bool index_key_includes_seq_;
};
// CachableEntry represents the entries that *may* be fetched from block cache.
@@ -436,7 +429,7 @@ struct BlockBasedTable::Rep {
const ImmutableCFOptions& ioptions;
const EnvOptions& env_options;
const BlockBasedTableOptions table_options;
const BlockBasedTableOptions& table_options;
const FilterPolicy* const filter_policy;
const InternalKeyComparator& internal_comparator;
Status status;
@@ -484,12 +477,11 @@ struct BlockBasedTable::Rep {
// block to extract prefix without knowing if a key is internal or not.
unique_ptr<SliceTransform> internal_prefix_transform;
// only used in level 0 files when pin_l0_filter_and_index_blocks_in_cache is
// true or in all levels when pin_top_level_index_and_filter is set in
// combination with partitioned index/filters: then we do use the LRU cache,
// but we always keep the filter & index block's handle checked out here (=we
// don't call Release()), plus the parsed out objects the LRU cache will never
// push flush them out, hence they're pinned
// only used in level 0 files:
// when pin_l0_filter_and_index_blocks_in_cache is true, we do use the
// LRU cache, but we always keep the filter & idndex block's handle checked
// out here (=we don't call Release()), plus the parsed out objects
// the LRU cache will never push flush them out, hence they're pinned
CachableEntry<FilterBlockReader> filter_entry;
CachableEntry<IndexReader> index_entry;
// range deletion meta-block is pinned through reader's lifetime when LRU
@@ -517,8 +509,7 @@ class BlockBasedTableIterator : public InternalIterator {
const ReadOptions& read_options,
const InternalKeyComparator& icomp,
InternalIterator* index_iter, bool check_filter,
const SliceTransform* prefix_extractor, bool is_index,
bool key_includes_seq = true)
const SliceTransform* prefix_extractor)
: table_(table),
read_options_(read_options),
icomp_(icomp),
@@ -526,8 +517,6 @@ class BlockBasedTableIterator : public InternalIterator {
pinned_iters_mgr_(nullptr),
block_iter_points_to_real_block_(false),
check_filter_(check_filter),
is_index_(is_index),
key_includes_seq_(key_includes_seq),
prefix_extractor_(prefix_extractor) {}
~BlockBasedTableIterator() { delete index_iter_; }
@@ -620,10 +609,6 @@ class BlockBasedTableIterator : public InternalIterator {
bool block_iter_points_to_real_block_;
bool is_out_of_bound_ = false;
bool check_filter_;
// If the blocks over which we iterate are index blocks
bool is_index_;
// If the keys in the blocks over which we iterate include 8 byte sequence
bool key_includes_seq_;
// TODO use block offset instead
std::string prev_index_value_;
const SliceTransform* prefix_extractor_;
+9 -10
View File
@@ -99,8 +99,7 @@ TEST_F(BlockTest, SimpleTest) {
// read contents of block sequentially
int count = 0;
InternalIterator *iter =
reader.NewIterator(options.comparator, options.comparator);
InternalIterator *iter = reader.NewIterator(options.comparator);
for (iter->SeekToFirst();iter->Valid(); count++, iter->Next()) {
// read kv from block
@@ -114,7 +113,7 @@ TEST_F(BlockTest, SimpleTest) {
delete iter;
// read block contents randomly
iter = reader.NewIterator(options.comparator, options.comparator);
iter = reader.NewIterator(options.comparator);
for (int i = 0; i < num_records; i++) {
// find a random key in the lookaside array
@@ -164,7 +163,7 @@ void CheckBlockContents(BlockContents contents, const int max_key,
NewFixedPrefixTransform(prefix_size));
std::unique_ptr<InternalIterator> regular_iter(
reader2.NewIterator(BytewiseComparator(), BytewiseComparator()));
reader2.NewIterator(BytewiseComparator()));
// Seek existent keys
for (size_t i = 0; i < keys.size(); i++) {
@@ -389,8 +388,8 @@ TEST_F(BlockTest, BlockWithReadAmpBitmap) {
// read contents of block sequentially
size_t read_bytes = 0;
BlockIter *iter = static_cast<BlockIter *>(reader.NewIterator(
options.comparator, options.comparator, nullptr, true, stats.get()));
BlockIter *iter = static_cast<BlockIter *>(
reader.NewIterator(options.comparator, nullptr, true, stats.get()));
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
iter->value();
read_bytes += iter->TEST_CurrentEntrySize();
@@ -422,8 +421,8 @@ TEST_F(BlockTest, BlockWithReadAmpBitmap) {
kBytesPerBit, stats.get());
size_t read_bytes = 0;
BlockIter *iter = static_cast<BlockIter *>(reader.NewIterator(
options.comparator, options.comparator, nullptr, true, stats.get()));
BlockIter *iter = static_cast<BlockIter *>(
reader.NewIterator(options.comparator, nullptr, true, stats.get()));
for (int i = 0; i < num_records; i++) {
Slice k(keys[i]);
@@ -458,8 +457,8 @@ TEST_F(BlockTest, BlockWithReadAmpBitmap) {
kBytesPerBit, stats.get());
size_t read_bytes = 0;
BlockIter *iter = static_cast<BlockIter *>(reader.NewIterator(
options.comparator, options.comparator, nullptr, true, stats.get()));
BlockIter *iter = static_cast<BlockIter *>(
reader.NewIterator(options.comparator, nullptr, true, stats.get()));
std::unordered_set<int> read_keys;
for (int i = 0; i < num_records; i++) {
int index = rnd.Uniform(num_records);
+1 -21
View File
@@ -10,13 +10,6 @@
#pragma once
#include <stdint.h>
#include <string>
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
#ifdef OS_FREEBSD
#include <malloc_np.h>
#else
#include <malloc.h>
#endif
#endif
#include "rocksdb/options.h"
#include "rocksdb/slice.h"
#include "rocksdb/status.h"
@@ -90,7 +83,7 @@ inline uint32_t GetCompressFormatForVersion(
}
inline bool BlockBasedTableSupportedVersion(uint32_t version) {
return version <= 3;
return version <= 2;
}
// Footer encapsulates the fixed information stored at the tail
@@ -206,19 +199,6 @@ struct BlockContents {
compression_type(_compression_type),
allocation(std::move(_data)) {}
// The additional memory space taken by the block data.
size_t usable_size() const {
if (allocation.get() != nullptr) {
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
return malloc_usable_size(allocation.get());
#else
return sizeof(*allocation.get());
#endif // ROCKSDB_MALLOC_USABLE_SIZE
} else {
return 0; // no extra memory is occupied by the data
}
}
BlockContents(BlockContents&& other) ROCKSDB_NOEXCEPT {
*this = std::move(other);
}
+1 -23
View File
@@ -5,14 +5,6 @@
#include "table/full_filter_block.h"
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
#ifdef OS_FREEBSD
#include <malloc_np.h>
#else
#include <malloc.h>
#endif
#endif
#include "monitoring/perf_context_imp.h"
#include "port/port.h"
#include "rocksdb/filter_policy.h"
@@ -80,14 +72,8 @@ inline void FullFilterBlockBuilder::AddPrefix(const Slice& key) {
}
}
void FullFilterBlockBuilder::Reset() {
last_whole_key_recorded_ = false;
last_prefix_recorded_ = false;
}
Slice FullFilterBlockBuilder::Finish(const BlockHandle& /*tmp*/,
Status* status) {
Reset();
// In this impl we ignore BlockHandle
*status = Status::OK();
if (num_added_ != 0) {
@@ -159,14 +145,6 @@ bool FullFilterBlockReader::MayMatch(const Slice& entry) {
}
size_t FullFilterBlockReader::ApproximateMemoryUsage() const {
size_t usage = block_contents_.usable_size();
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
usage += malloc_usable_size((void*)this);
usage += malloc_usable_size(filter_bits_reader_.get());
#else
usage += sizeof(*this);
usage += sizeof(*filter_bits_reader_.get());
#endif // ROCKSDB_MALLOC_USABLE_SIZE
return usage;
return contents_.size();
}
} // namespace rocksdb
+1 -1
View File
@@ -52,7 +52,6 @@ class FullFilterBlockBuilder : public FilterBlockBuilder {
protected:
virtual void AddKey(const Slice& key);
std::unique_ptr<FilterBitsBuilder> filter_bits_builder_;
virtual void Reset();
private:
// important: all of these might point to invalid addresses
@@ -114,6 +113,7 @@ class FullFilterBlockReader : public FilterBlockReader {
Slice contents_;
std::unique_ptr<FilterBitsReader> filter_bits_reader_;
BlockContents block_contents_;
std::unique_ptr<const char[]> filter_data_;
// No copying allowed
FullFilterBlockReader(const FullFilterBlockReader&);
+8 -36
View File
@@ -31,15 +31,13 @@ IndexBuilder* IndexBuilder::CreateIndexBuilder(
IndexBuilder* result = nullptr;
switch (index_type) {
case BlockBasedTableOptions::kBinarySearch: {
result = new ShortenedIndexBuilder(comparator,
table_opt.index_block_restart_interval,
table_opt.format_version);
result = new ShortenedIndexBuilder(comparator,
table_opt.index_block_restart_interval);
}
break;
case BlockBasedTableOptions::kHashSearch: {
result = new HashIndexBuilder(comparator, int_key_slice_transform,
table_opt.index_block_restart_interval,
table_opt.format_version);
table_opt.index_block_restart_interval);
}
break;
case BlockBasedTableOptions::kTwoLevelIndexSearch: {
@@ -64,13 +62,9 @@ PartitionedIndexBuilder::PartitionedIndexBuilder(
const InternalKeyComparator* comparator,
const BlockBasedTableOptions& table_opt)
: IndexBuilder(comparator),
index_block_builder_(table_opt.index_block_restart_interval,
table_opt.format_version),
index_block_builder_without_seq_(table_opt.index_block_restart_interval,
table_opt.format_version),
index_block_builder_(table_opt.index_block_restart_interval),
sub_index_builder_(nullptr),
table_opt_(table_opt),
seperator_is_key_plus_seq_(false) {}
table_opt_(table_opt) {}
PartitionedIndexBuilder::~PartitionedIndexBuilder() {
delete sub_index_builder_;
@@ -79,8 +73,7 @@ PartitionedIndexBuilder::~PartitionedIndexBuilder() {
void PartitionedIndexBuilder::MakeNewSubIndexBuilder() {
assert(sub_index_builder_ == nullptr);
sub_index_builder_ = new ShortenedIndexBuilder(
comparator_, table_opt_.index_block_restart_interval,
table_opt_.format_version);
comparator_, table_opt_.index_block_restart_interval);
flush_policy_.reset(FlushBlockBySizePolicyFactory::NewFlushBlockPolicy(
table_opt_.metadata_block_size, table_opt_.block_size_deviation,
sub_index_builder_->index_block_builder_));
@@ -102,10 +95,6 @@ void PartitionedIndexBuilder::AddIndexEntry(
}
sub_index_builder_->AddIndexEntry(last_key_in_current_block,
first_key_in_next_block, block_handle);
if (sub_index_builder_->seperator_is_key_plus_seq_) {
// then we need to apply it to all sub-index builders
seperator_is_key_plus_seq_ = true;
}
sub_index_last_key_ = std::string(*last_key_in_current_block);
entries_.push_back(
{sub_index_last_key_,
@@ -134,10 +123,6 @@ void PartitionedIndexBuilder::AddIndexEntry(
sub_index_builder_->AddIndexEntry(last_key_in_current_block,
first_key_in_next_block, block_handle);
sub_index_last_key_ = std::string(*last_key_in_current_block);
if (sub_index_builder_->seperator_is_key_plus_seq_) {
// then we need to apply it to all sub-index builders
seperator_is_key_plus_seq_ = true;
}
}
}
@@ -151,27 +136,16 @@ Status PartitionedIndexBuilder::Finish(
std::string handle_encoding;
last_partition_block_handle.EncodeTo(&handle_encoding);
index_block_builder_.Add(last_entry.key, handle_encoding);
if (!seperator_is_key_plus_seq_) {
index_block_builder_without_seq_.Add(ExtractUserKey(last_entry.key),
handle_encoding);
}
entries_.pop_front();
}
// If there is no sub_index left, then return the 2nd level index.
if (UNLIKELY(entries_.empty())) {
if (seperator_is_key_plus_seq_) {
index_blocks->index_block_contents = index_block_builder_.Finish();
} else {
index_blocks->index_block_contents =
index_block_builder_without_seq_.Finish();
}
index_blocks->index_block_contents = index_block_builder_.Finish();
return Status::OK();
} else {
// Finish the next partition index in line and Incomplete() to indicate we
// expect more calls to Finish
Entry& entry = entries_.front();
// Apply the policy to all sub-indexes
entry.value->seperator_is_key_plus_seq_ = seperator_is_key_plus_seq_;
auto s = entry.value->Finish(index_blocks);
finishing_indexes = true;
return s.ok() ? Status::Incomplete() : s;
@@ -203,9 +177,7 @@ size_t PartitionedIndexBuilder::EstimateTopLevelIndexSize(
uint64_t size = it->value->EstimatedSize();
BlockHandle tmp_block_handle(offset, size);
tmp_block_handle.EncodeTo(&tmp_handle_encoding);
tmp_builder.Add(
seperator_is_key_plus_seq_ ? it->key : ExtractUserKey(it->key),
tmp_handle_encoding);
tmp_builder.Add(it->key, tmp_handle_encoding);
offset += size;
}
return tmp_builder.CurrentSizeEstimate();
+7 -52
View File
@@ -99,8 +99,6 @@ class IndexBuilder {
// Get the estimated size for index block.
virtual size_t EstimatedSize() const = 0;
virtual bool seperator_is_key_plus_seq() { return true; }
protected:
const InternalKeyComparator* comparator_;
};
@@ -117,14 +115,9 @@ class IndexBuilder {
class ShortenedIndexBuilder : public IndexBuilder {
public:
explicit ShortenedIndexBuilder(const InternalKeyComparator* comparator,
int index_block_restart_interval,
uint32_t format_version)
int index_block_restart_interval)
: IndexBuilder(comparator),
index_block_builder_(index_block_restart_interval),
index_block_builder_without_seq_(index_block_restart_interval) {
// Making the default true will disable the feature for old versions
seperator_is_key_plus_seq_ = (format_version <= 2);
}
index_block_builder_(index_block_restart_interval) {}
virtual void AddIndexEntry(std::string* last_key_in_current_block,
const Slice* first_key_in_next_block,
@@ -132,57 +125,31 @@ class ShortenedIndexBuilder : public IndexBuilder {
if (first_key_in_next_block != nullptr) {
comparator_->FindShortestSeparator(last_key_in_current_block,
*first_key_in_next_block);
if (!seperator_is_key_plus_seq_ &&
comparator_->user_comparator()->Compare(
ExtractUserKey(*last_key_in_current_block),
ExtractUserKey(*first_key_in_next_block)) == 0) {
seperator_is_key_plus_seq_ = true;
}
} else {
comparator_->FindShortSuccessor(last_key_in_current_block);
}
auto sep = Slice(*last_key_in_current_block);
std::string handle_encoding;
block_handle.EncodeTo(&handle_encoding);
index_block_builder_.Add(sep, handle_encoding);
if (!seperator_is_key_plus_seq_) {
index_block_builder_without_seq_.Add(ExtractUserKey(sep),
handle_encoding);
}
index_block_builder_.Add(*last_key_in_current_block, handle_encoding);
}
using IndexBuilder::Finish;
virtual Status Finish(
IndexBlocks* index_blocks,
const BlockHandle& /*last_partition_block_handle*/) override {
if (seperator_is_key_plus_seq_) {
index_blocks->index_block_contents = index_block_builder_.Finish();
} else {
index_blocks->index_block_contents =
index_block_builder_without_seq_.Finish();
}
index_blocks->index_block_contents = index_block_builder_.Finish();
return Status::OK();
}
virtual size_t EstimatedSize() const override {
if (seperator_is_key_plus_seq_) {
return index_block_builder_.CurrentSizeEstimate();
} else {
return index_block_builder_without_seq_.CurrentSizeEstimate();
}
}
virtual bool seperator_is_key_plus_seq() override {
return seperator_is_key_plus_seq_;
return index_block_builder_.CurrentSizeEstimate();
}
friend class PartitionedIndexBuilder;
private:
BlockBuilder index_block_builder_;
BlockBuilder index_block_builder_without_seq_;
bool seperator_is_key_plus_seq_;
};
// HashIndexBuilder contains a binary-searchable primary index and the
@@ -216,11 +183,9 @@ class HashIndexBuilder : public IndexBuilder {
public:
explicit HashIndexBuilder(const InternalKeyComparator* comparator,
const SliceTransform* hash_key_extractor,
int index_block_restart_interval,
int format_version)
int index_block_restart_interval)
: IndexBuilder(comparator),
primary_index_builder_(comparator, index_block_restart_interval,
format_version),
primary_index_builder_(comparator, index_block_restart_interval),
hash_key_extractor_(hash_key_extractor) {}
virtual void AddIndexEntry(std::string* last_key_in_current_block,
@@ -275,10 +240,6 @@ class HashIndexBuilder : public IndexBuilder {
prefix_meta_block_.size();
}
virtual bool seperator_is_key_plus_seq() override {
return primary_index_builder_.seperator_is_key_plus_seq();
}
private:
void FlushPendingPrefix() {
prefix_block_.append(pending_entry_prefix_.data(),
@@ -355,10 +316,6 @@ class PartitionedIndexBuilder : public IndexBuilder {
// cutting the next partition
void RequestPartitionCut();
virtual bool seperator_is_key_plus_seq() override {
return seperator_is_key_plus_seq_;
}
private:
void MakeNewSubIndexBuilder();
@@ -368,7 +325,6 @@ class PartitionedIndexBuilder : public IndexBuilder {
};
std::list<Entry> entries_; // list of partitioned indexes and their keys
BlockBuilder index_block_builder_; // top-level index builder
BlockBuilder index_block_builder_without_seq_; // same for user keys
// the active partition index builder
ShortenedIndexBuilder* sub_index_builder_;
// the last key in the active partition index builder
@@ -377,7 +333,6 @@ class PartitionedIndexBuilder : public IndexBuilder {
// true if Finish is called once but not complete yet.
bool finishing_indexes = false;
const BlockBasedTableOptions& table_opt_;
bool seperator_is_key_plus_seq_;
// true if an external entity (such as filter partition builder) request
// cutting the next partition
bool partition_cut_requested_ = true;
+21 -5
View File
@@ -228,12 +228,28 @@ class MergingIterator : public InternalIterator {
Slice target = key();
for (auto& child : children_) {
if (&child != current_) {
child.SeekForPrev(target);
TEST_SYNC_POINT_CALLBACK("MergeIterator::Prev:BeforePrev", &child);
considerStatus(child.status());
if (child.Valid() && comparator_->Equal(target, child.key())) {
child.Prev();
if (!prefix_seek_mode_) {
child.Seek(target);
if (child.Valid()) {
// Child is at first entry >= key(). Step back one to be < key()
TEST_SYNC_POINT_CALLBACK("MergeIterator::Prev:BeforePrev",
&child);
assert(child.status().ok());
child.Prev();
} else {
// Child has no entries >= key(). Position at last entry.
TEST_SYNC_POINT("MergeIterator::Prev:BeforeSeekToLast");
considerStatus(child.status());
child.SeekToLast();
}
considerStatus(child.status());
} else {
child.SeekForPrev(target);
considerStatus(child.status());
if (child.Valid() && comparator_->Equal(target, child.key())) {
child.Prev();
considerStatus(child.status());
}
}
}
if (child.Valid()) {
+4 -10
View File
@@ -71,7 +71,6 @@ void PropertyBlockBuilder::AddTableProperty(const TableProperties& props) {
Add(TablePropertiesNames::kIndexPartitions, props.index_partitions);
Add(TablePropertiesNames::kTopLevelIndexSize, props.top_level_index_size);
}
Add(TablePropertiesNames::kIndexKeyIsUserKey, props.index_key_is_user_key);
Add(TablePropertiesNames::kNumEntries, props.num_entries);
Add(TablePropertiesNames::kNumDataBlocks, props.num_data_blocks);
Add(TablePropertiesNames::kFilterSize, props.filter_size);
@@ -193,8 +192,7 @@ Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
Block properties_block(std::move(block_contents),
kDisableGlobalSequenceNumber);
BlockIter iter;
properties_block.NewIterator(BytewiseComparator(), BytewiseComparator(),
&iter);
properties_block.NewIterator(BytewiseComparator(), &iter);
auto new_table_properties = new TableProperties();
// All pre-defined properties of type uint64_t
@@ -205,8 +203,6 @@ Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
&new_table_properties->index_partitions},
{TablePropertiesNames::kTopLevelIndexSize,
&new_table_properties->top_level_index_size},
{TablePropertiesNames::kIndexKeyIsUserKey,
&new_table_properties->index_key_is_user_key},
{TablePropertiesNames::kFilterSize, &new_table_properties->filter_size},
{TablePropertiesNames::kRawKeySize, &new_table_properties->raw_key_size},
{TablePropertiesNames::kRawValueSize,
@@ -316,7 +312,7 @@ Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
Block metaindex_block(std::move(metaindex_contents),
kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter(
metaindex_block.NewIterator(BytewiseComparator(), BytewiseComparator()));
metaindex_block.NewIterator(BytewiseComparator()));
// -- Read property block
bool found_properties_block = true;
@@ -379,8 +375,7 @@ Status FindMetaBlock(RandomAccessFileReader* file, uint64_t file_size,
kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter;
meta_iter.reset(
metaindex_block.NewIterator(BytewiseComparator(), BytewiseComparator()));
meta_iter.reset(metaindex_block.NewIterator(BytewiseComparator()));
return FindMetaBlock(meta_iter.get(), meta_block_name, block_handle);
}
@@ -421,8 +416,7 @@ Status ReadMetaBlock(RandomAccessFileReader* file,
kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter;
meta_iter.reset(
metaindex_block.NewIterator(BytewiseComparator(), BytewiseComparator()));
meta_iter.reset(metaindex_block.NewIterator(BytewiseComparator()));
BlockHandle block_handle;
status = FindMetaBlock(meta_iter.get(), meta_block_name, &block_handle);
+8 -36
View File
@@ -5,13 +5,6 @@
#include "table/partitioned_filter_block.h"
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
#ifdef OS_FREEBSD
#include <malloc_np.h>
#else
#include <malloc.h>
#endif
#endif
#include <utility>
#include "monitoring/perf_context_imp.h"
@@ -31,7 +24,6 @@ PartitionedFilterBlockBuilder::PartitionedFilterBlockBuilder(
: FullFilterBlockBuilder(prefix_extractor, whole_key_filtering,
filter_bits_builder),
index_on_filter_block_builder_(index_block_restart_interval),
index_on_filter_block_builder_without_seq_(index_block_restart_interval),
p_index_builder_(p_index_builder),
filters_in_partition_(0),
num_added_(0) {
@@ -56,7 +48,6 @@ void PartitionedFilterBlockBuilder::MaybeCutAFilterBlock() {
std::string& index_key = p_index_builder_->GetPartitionKey();
filters.push_back({index_key, filter});
filters_in_partition_ = 0;
Reset();
}
void PartitionedFilterBlockBuilder::AddKey(const Slice& key) {
@@ -74,10 +65,6 @@ Slice PartitionedFilterBlockBuilder::Finish(
std::string handle_encoding;
last_partition_block_handle.EncodeTo(&handle_encoding);
index_on_filter_block_builder_.Add(last_entry.key, handle_encoding);
if (!p_index_builder_->seperator_is_key_plus_seq()) {
index_on_filter_block_builder_without_seq_.Add(
ExtractUserKey(last_entry.key), handle_encoding);
}
filters.pop_front();
} else {
MaybeCutAFilterBlock();
@@ -87,11 +74,7 @@ Slice PartitionedFilterBlockBuilder::Finish(
if (UNLIKELY(filters.empty())) {
*status = Status::OK();
if (finishing_filters) {
if (p_index_builder_->seperator_is_key_plus_seq()) {
return index_on_filter_block_builder_.Finish();
} else {
return index_on_filter_block_builder_without_seq_.Finish();
}
return index_on_filter_block_builder_.Finish();
} else {
// This is the rare case where no key was added to the filter
return Slice();
@@ -108,13 +91,12 @@ Slice PartitionedFilterBlockBuilder::Finish(
PartitionedFilterBlockReader::PartitionedFilterBlockReader(
const SliceTransform* prefix_extractor, bool _whole_key_filtering,
BlockContents&& contents, FilterBitsReader* /*filter_bits_reader*/,
Statistics* stats, const InternalKeyComparator comparator,
const BlockBasedTable* table, const bool index_key_includes_seq)
Statistics* stats, const Comparator& comparator,
const BlockBasedTable* table)
: FilterBlockReader(contents.data.size(), stats, _whole_key_filtering),
prefix_extractor_(prefix_extractor),
comparator_(comparator),
table_(table),
index_key_includes_seq_(index_key_includes_seq) {
table_(table) {
idx_on_fltr_blk_.reset(new Block(std::move(contents),
kDisableGlobalSequenceNumber,
0 /* read_amp_bytes_per_bit */, stats));
@@ -131,8 +113,7 @@ PartitionedFilterBlockReader::~PartitionedFilterBlockReader() {
char cache_key[BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length];
BlockIter biter;
BlockHandle handle;
idx_on_fltr_blk_->NewIterator(&comparator_, comparator_.user_comparator(),
&biter, true, nullptr, index_key_includes_seq_);
idx_on_fltr_blk_->NewIterator(&comparator_, &biter, true);
biter.SeekToFirst();
for (; biter.Valid(); biter.Next()) {
auto input = biter.value();
@@ -226,8 +207,7 @@ bool PartitionedFilterBlockReader::PrefixMayMatch(
Slice PartitionedFilterBlockReader::GetFilterPartitionHandle(
const Slice& entry) {
BlockIter iter;
idx_on_fltr_blk_->NewIterator(&comparator_, comparator_.user_comparator(),
&iter, true, nullptr, index_key_includes_seq_);
idx_on_fltr_blk_->NewIterator(&comparator_, &iter, true);
iter.Seek(entry);
if (UNLIKELY(!iter.Valid())) {
return Slice();
@@ -272,14 +252,7 @@ PartitionedFilterBlockReader::GetFilterPartition(
}
size_t PartitionedFilterBlockReader::ApproximateMemoryUsage() const {
size_t usage = idx_on_fltr_blk_->usable_size();
#ifdef ROCKSDB_MALLOC_USABLE_SIZE
usage += malloc_usable_size((void*)this);
#else
usage += sizeof(*this);
#endif // ROCKSDB_MALLOC_USABLE_SIZE
return usage;
// TODO(myabandeh): better estimation for filter_map_ size
return idx_on_fltr_blk_->size();
}
// Release the cached entry and decrement its ref count.
@@ -296,8 +269,7 @@ void PartitionedFilterBlockReader::CacheDependencies(
auto rep = table_->rep_;
BlockIter biter;
BlockHandle handle;
idx_on_fltr_blk_->NewIterator(&comparator_, comparator_.user_comparator(),
&biter, true, nullptr, index_key_includes_seq_);
idx_on_fltr_blk_->NewIterator(&comparator_, &biter, true);
// Index partitions are assumed to be consecuitive. Prefetch them all.
// Read the first block offset
biter.SeekToFirst();
+8 -9
View File
@@ -41,8 +41,6 @@ class PartitionedFilterBlockBuilder : public FullFilterBlockBuilder {
private:
// Filter data
BlockBuilder index_on_filter_block_builder_; // top-level index builder
BlockBuilder
index_on_filter_block_builder_without_seq_; // same for user keys
struct FilterEntry {
std::string key;
Slice filter;
@@ -70,11 +68,13 @@ class PartitionedFilterBlockBuilder : public FullFilterBlockBuilder {
class PartitionedFilterBlockReader : public FilterBlockReader,
public Cleanable {
public:
explicit PartitionedFilterBlockReader(
const SliceTransform* prefix_extractor, bool whole_key_filtering,
BlockContents&& contents, FilterBitsReader* filter_bits_reader,
Statistics* stats, const InternalKeyComparator comparator,
const BlockBasedTable* table, const bool index_key_includes_seq);
explicit PartitionedFilterBlockReader(const SliceTransform* prefix_extractor,
bool whole_key_filtering,
BlockContents&& contents,
FilterBitsReader* filter_bits_reader,
Statistics* stats,
const Comparator& comparator,
const BlockBasedTable* table);
virtual ~PartitionedFilterBlockReader();
virtual bool IsBlockBased() override { return false; }
@@ -98,9 +98,8 @@ class PartitionedFilterBlockReader : public FilterBlockReader,
const SliceTransform* prefix_extractor_;
std::unique_ptr<Block> idx_on_fltr_blk_;
const InternalKeyComparator comparator_;
const Comparator& comparator_;
const BlockBasedTable* table_;
const bool index_key_includes_seq_;
std::unordered_map<uint64_t,
BlockBasedTable::CachableEntry<FilterBlockReader>>
filter_map_;
+8 -9
View File
@@ -111,7 +111,7 @@ class PartitionedFilterBlockTest : public testing::Test {
std::unique_ptr<MockedBlockBasedTable> table;
PartitionedFilterBlockReader* NewReader(
PartitionedFilterBlockBuilder* builder, PartitionedIndexBuilder* pib) {
PartitionedFilterBlockBuilder* builder) {
BlockHandle bh;
Status status;
Slice slice;
@@ -127,14 +127,13 @@ class PartitionedFilterBlockTest : public testing::Test {
ioptions, env_options, table_options_, icomp, false)));
auto reader = new PartitionedFilterBlockReader(
nullptr, true, BlockContents(slice, false, kNoCompression), nullptr,
nullptr, icomp, table.get(), pib->seperator_is_key_plus_seq());
nullptr, *icomp.user_comparator(), table.get());
return reader;
}
void VerifyReader(PartitionedFilterBlockBuilder* builder,
PartitionedIndexBuilder* pib, bool empty = false) {
std::unique_ptr<PartitionedFilterBlockReader> reader(
NewReader(builder, pib));
bool empty = false) {
std::unique_ptr<PartitionedFilterBlockReader> reader(NewReader(builder));
// Querying added keys
const bool no_io = true;
for (auto key : keys) {
@@ -183,7 +182,7 @@ class PartitionedFilterBlockTest : public testing::Test {
builder->Add(keys[i]);
CutABlock(pib.get(), keys[i]);
VerifyReader(builder.get(), pib.get());
VerifyReader(builder.get());
return CountNumOfIndexPartitions(pib.get());
}
@@ -203,7 +202,7 @@ class PartitionedFilterBlockTest : public testing::Test {
builder->Add(keys[i]);
CutABlock(pib.get(), keys[i]);
VerifyReader(builder.get(), pib.get());
VerifyReader(builder.get());
}
void TestBlockPerAllKeys() {
@@ -221,7 +220,7 @@ class PartitionedFilterBlockTest : public testing::Test {
builder->Add(keys[i]);
CutABlock(pib.get(), keys[i]);
VerifyReader(builder.get(), pib.get());
VerifyReader(builder.get());
}
void CutABlock(PartitionedIndexBuilder* builder,
@@ -262,7 +261,7 @@ TEST_F(PartitionedFilterBlockTest, EmptyBuilder) {
std::unique_ptr<PartitionedIndexBuilder> pib(NewIndexBuilder());
std::unique_ptr<PartitionedFilterBlockBuilder> builder(NewBuilder(pib.get()));
const bool empty = true;
VerifyReader(builder.get(), pib.get(), empty);
VerifyReader(builder.get(), empty);
}
TEST_F(PartitionedFilterBlockTest, OneBlock) {
+1 -9
View File
@@ -90,12 +90,7 @@ std::string TableProperties::ToString(
prop_delim, kv_delim);
AppendProperty(result, "data block size", data_size, prop_delim, kv_delim);
char index_block_size_str[80];
snprintf(index_block_size_str, sizeof(index_block_size_str),
"index block size (user-key? %d)",
static_cast<int>(index_key_is_user_key));
AppendProperty(result, index_block_size_str, index_size, prop_delim,
kv_delim);
AppendProperty(result, "index block size", index_size, prop_delim, kv_delim);
if (index_partitions != 0) {
AppendProperty(result, "# index partitions", index_partitions, prop_delim,
kv_delim);
@@ -160,7 +155,6 @@ void TableProperties::Add(const TableProperties& tp) {
index_size += tp.index_size;
index_partitions += tp.index_partitions;
top_level_index_size += tp.top_level_index_size;
index_key_is_user_key += tp.index_key_is_user_key;
filter_size += tp.filter_size;
raw_key_size += tp.raw_key_size;
raw_value_size += tp.raw_value_size;
@@ -176,8 +170,6 @@ const std::string TablePropertiesNames::kIndexPartitions =
"rocksdb.index.partitions";
const std::string TablePropertiesNames::kTopLevelIndexSize =
"rocksdb.top-level.index.size";
const std::string TablePropertiesNames::kIndexKeyIsUserKey =
"rocksdb.index.key.is.user.key";
const std::string TablePropertiesNames::kFilterSize =
"rocksdb.filter.size";
const std::string TablePropertiesNames::kRawKeySize =
+114 -139
View File
@@ -237,7 +237,7 @@ class BlockConstructor: public Constructor {
}
virtual InternalIterator* NewIterator(
const SliceTransform* /*prefix_extractor*/) const override {
return block_->NewIterator(comparator_, comparator_);
return block_->NewIterator(comparator_);
}
private:
@@ -1049,32 +1049,13 @@ class TableTest : public testing::Test {
};
class GeneralTableTest : public TableTest {};
class BlockBasedTableTest
: public TableTest,
virtual public ::testing::WithParamInterface<uint32_t> {
public:
BlockBasedTableTest() : format_(GetParam()) {}
BlockBasedTableOptions GetBlockBasedTableOptions() {
BlockBasedTableOptions options;
options.format_version = format_;
return options;
}
class BlockBasedTableTest : public TableTest {
protected:
uint64_t IndexUncompressedHelper(bool indexCompress);
private:
uint32_t format_;
};
class PlainTableTest : public TableTest {};
class TablePropertyTest : public testing::Test {};
INSTANTIATE_TEST_CASE_P(FormatDef, BlockBasedTableTest,
testing::Values(test::kDefaultFormatVersion));
INSTANTIATE_TEST_CASE_P(FormatLatest, BlockBasedTableTest,
testing::Values(test::kLatestFormatVersion));
// This test serves as the living tutorial for the prefix scan of user collected
// properties.
TEST_F(TablePropertyTest, PrefixScanTest) {
@@ -1114,7 +1095,7 @@ TEST_F(TablePropertyTest, PrefixScanTest) {
// This test include all the basic checks except those for index size and block
// size, which will be conducted in separated unit tests.
TEST_P(BlockBasedTableTest, BasicBlockBasedTableProperties) {
TEST_F(BlockBasedTableTest, BasicBlockBasedTableProperties) {
TableConstructor c(BytewiseComparator(), true /* convert_to_internal_key_ */);
c.Add("a1", "val1");
@@ -1134,7 +1115,7 @@ TEST_P(BlockBasedTableTest, BasicBlockBasedTableProperties) {
options.compression = kNoCompression;
options.statistics = CreateDBStatistics();
options.statistics->stats_level_ = StatsLevel::kAll;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_restart_interval = 1;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1182,7 +1163,7 @@ uint64_t BlockBasedTableTest::IndexUncompressedHelper(bool compressed) {
options.compression = kSnappyCompression;
options.statistics = CreateDBStatistics();
options.statistics->stats_level_ = StatsLevel::kAll;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_restart_interval = 1;
table_options.enable_index_compression = compressed;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1195,7 +1176,7 @@ uint64_t BlockBasedTableTest::IndexUncompressedHelper(bool compressed) {
c.ResetTableReader();
return options.statistics->getTickerCount(NUMBER_BLOCK_COMPRESSED);
}
TEST_P(BlockBasedTableTest, IndexUncompressed) {
TEST_F(BlockBasedTableTest, IndexUncompressed) {
uint64_t tbl1_compressed_cnt = IndexUncompressedHelper(true);
uint64_t tbl2_compressed_cnt = IndexUncompressedHelper(false);
// tbl1_compressed_cnt should include 1 index block
@@ -1203,7 +1184,7 @@ TEST_P(BlockBasedTableTest, IndexUncompressed) {
}
#endif // SNAPPY
TEST_P(BlockBasedTableTest, BlockBasedTableProperties2) {
TEST_F(BlockBasedTableTest, BlockBasedTableProperties2) {
TableConstructor c(&reverse_key_comparator);
std::vector<std::string> keys;
stl_wrappers::KVMap kvmap;
@@ -1211,7 +1192,7 @@ TEST_P(BlockBasedTableTest, BlockBasedTableProperties2) {
{
Options options;
options.compression = CompressionType::kNoCompression;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
const ImmutableCFOptions ioptions(options);
@@ -1238,7 +1219,7 @@ TEST_P(BlockBasedTableTest, BlockBasedTableProperties2) {
{
Options options;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
options.comparator = &reverse_key_comparator;
options.merge_operator = MergeOperators::CreateUInt64AddOperator();
@@ -1265,7 +1246,7 @@ TEST_P(BlockBasedTableTest, BlockBasedTableProperties2) {
}
}
TEST_P(BlockBasedTableTest, RangeDelBlock) {
TEST_F(BlockBasedTableTest, RangeDelBlock) {
TableConstructor c(BytewiseComparator());
std::vector<std::string> keys = {"1pika", "2chu"};
std::vector<std::string> vals = {"p", "c"};
@@ -1280,7 +1261,7 @@ TEST_P(BlockBasedTableTest, RangeDelBlock) {
stl_wrappers::KVMap kvmap;
Options options;
options.compression = kNoCompression;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_restart_interval = 1;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1316,12 +1297,12 @@ TEST_P(BlockBasedTableTest, RangeDelBlock) {
}
}
TEST_P(BlockBasedTableTest, FilterPolicyNameProperties) {
TEST_F(BlockBasedTableTest, FilterPolicyNameProperties) {
TableConstructor c(BytewiseComparator(), true /* convert_to_internal_key_ */);
c.Add("a1", "val1");
std::vector<std::string> keys;
stl_wrappers::KVMap kvmap;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(10));
Options options;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1405,14 +1386,14 @@ void PrefetchRange(TableConstructor* c, Options* opt,
c->ResetTableReader();
}
TEST_P(BlockBasedTableTest, PrefetchTest) {
TEST_F(BlockBasedTableTest, PrefetchTest) {
// The purpose of this test is to test the prefetching operation built into
// BlockBasedTable.
Options opt;
unique_ptr<InternalKeyComparator> ikc;
ikc.reset(new test::PlainInternalKeyComparator(opt.comparator));
opt.compression = kNoCompression;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_size = 1024;
// big enough so we don't ever lose cached values.
table_options.block_cache = NewLRUCache(16 * 1024 * 1024, 4);
@@ -1473,8 +1454,8 @@ TEST_P(BlockBasedTableTest, PrefetchTest) {
c.ResetTableReader();
}
TEST_P(BlockBasedTableTest, TotalOrderSeekOnHashIndex) {
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
TEST_F(BlockBasedTableTest, TotalOrderSeekOnHashIndex) {
BlockBasedTableOptions table_options;
for (int i = 0; i < 4; ++i) {
Options options;
// Make each key/value an individual block
@@ -1565,8 +1546,8 @@ TEST_P(BlockBasedTableTest, TotalOrderSeekOnHashIndex) {
}
}
TEST_P(BlockBasedTableTest, NoopTransformSeek) {
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
TEST_F(BlockBasedTableTest, NoopTransformSeek) {
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(10));
Options options;
@@ -1602,10 +1583,10 @@ TEST_P(BlockBasedTableTest, NoopTransformSeek) {
}
}
TEST_P(BlockBasedTableTest, SkipPrefixBloomFilter) {
TEST_F(BlockBasedTableTest, SkipPrefixBloomFilter) {
// if DB is opened with a prefix extractor of a different name,
// prefix bloom is skipped when read the file
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(2));
table_options.whole_key_filtering = false;
@@ -1769,24 +1750,24 @@ void TableTest::IndexTest(BlockBasedTableOptions table_options) {
c.ResetTableReader();
}
TEST_P(BlockBasedTableTest, BinaryIndexTest) {
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
TEST_F(TableTest, BinaryIndexTest) {
BlockBasedTableOptions table_options;
table_options.index_type = BlockBasedTableOptions::kBinarySearch;
IndexTest(table_options);
}
TEST_P(BlockBasedTableTest, HashIndexTest) {
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
TEST_F(TableTest, HashIndexTest) {
BlockBasedTableOptions table_options;
table_options.index_type = BlockBasedTableOptions::kHashSearch;
IndexTest(table_options);
}
TEST_P(BlockBasedTableTest, PartitionIndexTest) {
TEST_F(TableTest, PartitionIndexTest) {
const int max_index_keys = 5;
const int est_max_index_key_value_size = 32;
const int est_max_index_size = max_index_keys * est_max_index_key_value_size;
for (int i = 1; i <= est_max_index_size + 1; i++) {
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.index_type = BlockBasedTableOptions::kTwoLevelIndexSearch;
table_options.metadata_block_size = i;
IndexTest(table_options);
@@ -1796,7 +1777,7 @@ TEST_P(BlockBasedTableTest, PartitionIndexTest) {
// It's very hard to figure out the index block size of a block accurately.
// To make sure we get the index size, we just make sure as key number
// grows, the filter block size also grows.
TEST_P(BlockBasedTableTest, IndexSizeStat) {
TEST_F(BlockBasedTableTest, IndexSizeStat) {
uint64_t last_index_size = 0;
// we need to use random keys since the pure human readable texts
@@ -1822,7 +1803,7 @@ TEST_P(BlockBasedTableTest, IndexSizeStat) {
stl_wrappers::KVMap kvmap;
Options options;
options.compression = kNoCompression;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_restart_interval = 1;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1837,12 +1818,12 @@ TEST_P(BlockBasedTableTest, IndexSizeStat) {
}
}
TEST_P(BlockBasedTableTest, NumBlockStat) {
TEST_F(BlockBasedTableTest, NumBlockStat) {
Random rnd(test::RandomSeed());
TableConstructor c(BytewiseComparator(), true /* convert_to_internal_key_ */);
Options options;
options.compression = kNoCompression;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_restart_interval = 1;
table_options.block_size = 1000;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1929,11 +1910,11 @@ class BlockCachePropertiesSnapshot {
// Make sure, by default, index/filter blocks were pre-loaded (meaning we won't
// use block cache to store them).
TEST_P(BlockBasedTableTest, BlockCacheDisabledTest) {
TEST_F(BlockBasedTableTest, BlockCacheDisabledTest) {
Options options;
options.create_if_missing = true;
options.statistics = CreateDBStatistics();
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_cache = NewLRUCache(1024, 4);
table_options.filter_policy.reset(NewBloomFilterPolicy(10));
options.table_factory.reset(new BlockBasedTableFactory(table_options));
@@ -1974,15 +1955,15 @@ TEST_P(BlockBasedTableTest, BlockCacheDisabledTest) {
// Due to the difficulities of the intersaction between statistics, this test
// only tests the case when "index block is put to block cache"
TEST_P(BlockBasedTableTest, FilterBlockInBlockCache) {
TEST_F(BlockBasedTableTest, FilterBlockInBlockCache) {
// -- Table construction
Options options;
options.create_if_missing = true;
options.statistics = CreateDBStatistics();
// Enable the cache for index/filter blocks
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
table_options.block_cache = NewLRUCache(1024, 2);
BlockBasedTableOptions table_options;
table_options.block_cache = NewLRUCache(1024, 4);
table_options.cache_index_and_filter_blocks = true;
options.table_factory.reset(new BlockBasedTableFactory(table_options));
std::vector<std::string> keys;
@@ -2134,7 +2115,7 @@ TEST_P(BlockBasedTableTest, FilterBlockInBlockCache) {
GetContext get_context(options.comparator, nullptr, nullptr, nullptr,
GetContext::kNotFound, user_key, &value, nullptr,
nullptr, nullptr, nullptr);
ASSERT_OK(reader->Get(ReadOptions(), internal_key.Encode(), &get_context,
ASSERT_OK(reader->Get(ReadOptions(), user_key, &get_context,
moptions4.prefix_extractor.get()));
ASSERT_STREQ(value.data(), "hello");
BlockCachePropertiesSnapshot props(options.statistics.get());
@@ -2166,7 +2147,7 @@ void ValidateBlockRestartInterval(int value, int expected) {
delete factory;
}
TEST_P(BlockBasedTableTest, InvalidOptions) {
TEST_F(BlockBasedTableTest, InvalidOptions) {
// invalid values for block_size_deviation (<0 or >100) are silently set to 0
ValidateBlockSizeDeviation(-10, 0);
ValidateBlockSizeDeviation(-1, 0);
@@ -2186,7 +2167,7 @@ TEST_P(BlockBasedTableTest, InvalidOptions) {
ValidateBlockRestartInterval(1000, 1000);
}
TEST_P(BlockBasedTableTest, BlockReadCountTest) {
TEST_F(BlockBasedTableTest, BlockReadCountTest) {
// bloom_filter_type = 0 -- block-based filter
// bloom_filter_type = 0 -- full filter
for (int bloom_filter_type = 0; bloom_filter_type < 2; ++bloom_filter_type) {
@@ -2195,7 +2176,7 @@ TEST_P(BlockBasedTableTest, BlockReadCountTest) {
Options options;
options.create_if_missing = true;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_cache = NewLRUCache(1, 0);
table_options.cache_index_and_filter_blocks = index_and_filter_in_cache;
table_options.filter_policy.reset(
@@ -2314,7 +2295,7 @@ std::map<std::string, size_t> MockCache::marked_data_in_cache_;
// object depends on the table to be live, it then must be destructed before the
// table is closed. This test makes sure that the only items remains in the
// cache after the table is closed are raw data blocks.
TEST_P(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
TEST_F(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
for (int level: {-1, 0, 1, 10}) {
for (auto index_type :
{BlockBasedTableOptions::IndexType::kBinarySearch,
@@ -2329,74 +2310,70 @@ TEST_P(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
}
for (bool index_and_filter_in_cache : {true, false}) {
for (bool pin_l0 : {true, false}) {
for (bool pin_top_level : {true, false}) {
if (pin_l0 && !index_and_filter_in_cache) {
continue;
}
// Create a table
Options opt;
unique_ptr<InternalKeyComparator> ikc;
ikc.reset(new test::PlainInternalKeyComparator(opt.comparator));
opt.compression = kNoCompression;
BlockBasedTableOptions table_options =
GetBlockBasedTableOptions();
table_options.block_size = 1024;
table_options.index_type =
BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch;
table_options.pin_l0_filter_and_index_blocks_in_cache = pin_l0;
table_options.pin_top_level_index_and_filter = pin_top_level;
table_options.partition_filters = partition_filter;
table_options.cache_index_and_filter_blocks =
index_and_filter_in_cache;
// big enough so we don't ever lose cached values.
table_options.block_cache = std::shared_ptr<rocksdb::Cache>(
new MockCache(16 * 1024 * 1024, 4, false, 0.0));
table_options.filter_policy.reset(
rocksdb::NewBloomFilterPolicy(10, block_based_filter));
opt.table_factory.reset(NewBlockBasedTableFactory(table_options));
if (pin_l0 && !index_and_filter_in_cache) {
continue;
}
// Create a table
Options opt;
unique_ptr<InternalKeyComparator> ikc;
ikc.reset(new test::PlainInternalKeyComparator(opt.comparator));
opt.compression = kNoCompression;
BlockBasedTableOptions table_options;
table_options.block_size = 1024;
table_options.index_type =
BlockBasedTableOptions::IndexType::kTwoLevelIndexSearch;
table_options.pin_l0_filter_and_index_blocks_in_cache = pin_l0;
table_options.partition_filters = partition_filter;
table_options.cache_index_and_filter_blocks =
index_and_filter_in_cache;
// big enough so we don't ever lose cached values.
table_options.block_cache = std::shared_ptr<rocksdb::Cache>(
new MockCache(16 * 1024 * 1024, 4, false, 0.0));
table_options.filter_policy.reset(
rocksdb::NewBloomFilterPolicy(10, block_based_filter));
opt.table_factory.reset(NewBlockBasedTableFactory(table_options));
bool convert_to_internal_key = false;
TableConstructor c(BytewiseComparator(), convert_to_internal_key,
level);
std::string user_key = "k01";
std::string key =
InternalKey(user_key, 0, kTypeValue).Encode().ToString();
c.Add(key, "hello");
std::vector<std::string> keys;
stl_wrappers::KVMap kvmap;
const ImmutableCFOptions ioptions(opt);
const MutableCFOptions moptions(opt);
c.Finish(opt, ioptions, moptions, table_options, *ikc, &keys,
&kvmap);
bool convert_to_internal_key = false;
TableConstructor c(BytewiseComparator(), convert_to_internal_key,
level);
std::string user_key = "k01";
std::string key =
InternalKey(user_key, 0, kTypeValue).Encode().ToString();
c.Add(key, "hello");
std::vector<std::string> keys;
stl_wrappers::KVMap kvmap;
const ImmutableCFOptions ioptions(opt);
const MutableCFOptions moptions(opt);
c.Finish(opt, ioptions, moptions, table_options, *ikc, &keys,
&kvmap);
// Doing a read to make index/filter loaded into the cache
auto table_reader =
dynamic_cast<BlockBasedTable*>(c.GetTableReader());
PinnableSlice value;
GetContext get_context(opt.comparator, nullptr, nullptr, nullptr,
GetContext::kNotFound, user_key, &value,
nullptr, nullptr, nullptr, nullptr);
InternalKey ikey(user_key, 0, kTypeValue);
auto s = table_reader->Get(ReadOptions(), key, &get_context,
moptions.prefix_extractor.get());
ASSERT_EQ(get_context.State(), GetContext::kFound);
ASSERT_STREQ(value.data(), "hello");
// Doing a read to make index/filter loaded into the cache
auto table_reader =
dynamic_cast<BlockBasedTable*>(c.GetTableReader());
PinnableSlice value;
GetContext get_context(opt.comparator, nullptr, nullptr, nullptr,
GetContext::kNotFound, user_key, &value,
nullptr, nullptr, nullptr, nullptr);
InternalKey ikey(user_key, 0, kTypeValue);
auto s = table_reader->Get(ReadOptions(), key, &get_context,
moptions.prefix_extractor.get());
ASSERT_EQ(get_context.State(), GetContext::kFound);
ASSERT_STREQ(value.data(), "hello");
// Close the table
c.ResetTableReader();
// Close the table
c.ResetTableReader();
auto usage = table_options.block_cache->GetUsage();
auto pinned_usage = table_options.block_cache->GetPinnedUsage();
// The only usage must be for marked data blocks
ASSERT_EQ(usage, MockCache::marked_size_);
// There must be some pinned data since PinnableSlice has not
// released them yet
ASSERT_GT(pinned_usage, 0);
// Release pinnable slice reousrces
value.Reset();
pinned_usage = table_options.block_cache->GetPinnedUsage();
ASSERT_EQ(pinned_usage, 0);
}
auto usage = table_options.block_cache->GetUsage();
auto pinned_usage = table_options.block_cache->GetPinnedUsage();
// The only usage must be for marked data blocks
ASSERT_EQ(usage, MockCache::marked_size_);
// There must be some pinned data since PinnableSlice has not
// released them yet
ASSERT_GT(pinned_usage, 0);
// Release pinnable slice reousrces
value.Reset();
pinned_usage = table_options.block_cache->GetPinnedUsage();
ASSERT_EQ(pinned_usage, 0);
}
}
}
@@ -2405,7 +2382,7 @@ TEST_P(BlockBasedTableTest, NoObjectInCacheAfterTableClose) {
} // level
}
TEST_P(BlockBasedTableTest, BlockCacheLeak) {
TEST_F(BlockBasedTableTest, BlockCacheLeak) {
// Check that when we reopen a table we don't lose access to blocks already
// in the cache. This test checks whether the Table actually makes use of the
// unique ID from the file.
@@ -2414,7 +2391,7 @@ TEST_P(BlockBasedTableTest, BlockCacheLeak) {
unique_ptr<InternalKeyComparator> ikc;
ikc.reset(new test::PlainInternalKeyComparator(opt.comparator));
opt.compression = kNoCompression;
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.block_size = 1024;
// big enough so we don't ever lose cached values.
table_options.block_cache = NewLRUCache(16 * 1024 * 1024, 4);
@@ -2450,8 +2427,7 @@ TEST_P(BlockBasedTableTest, BlockCacheLeak) {
ASSERT_OK(c.Reopen(ioptions1, moptions1));
auto table_reader = dynamic_cast<BlockBasedTable*>(c.GetTableReader());
for (const std::string& key : keys) {
InternalKey ikey(key, kMaxSequenceNumber, kTypeValue);
ASSERT_TRUE(table_reader->TEST_KeyInCache(ReadOptions(), ikey.Encode()));
ASSERT_TRUE(table_reader->TEST_KeyInCache(ReadOptions(), key));
}
c.ResetTableReader();
@@ -2463,13 +2439,12 @@ TEST_P(BlockBasedTableTest, BlockCacheLeak) {
ASSERT_OK(c.Reopen(ioptions2, moptions2));
table_reader = dynamic_cast<BlockBasedTable*>(c.GetTableReader());
for (const std::string& key : keys) {
InternalKey ikey(key, kMaxSequenceNumber, kTypeValue);
ASSERT_TRUE(!table_reader->TEST_KeyInCache(ReadOptions(), ikey.Encode()));
ASSERT_TRUE(!table_reader->TEST_KeyInCache(ReadOptions(), key));
}
c.ResetTableReader();
}
TEST_P(BlockBasedTableTest, NewIndexIteratorLeak) {
TEST_F(BlockBasedTableTest, NewIndexIteratorLeak) {
// A regression test to avoid data race described in
// https://github.com/facebook/rocksdb/issues/1267
TableConstructor c(BytewiseComparator(), true /* convert_to_internal_key_ */);
@@ -2478,7 +2453,7 @@ TEST_P(BlockBasedTableTest, NewIndexIteratorLeak) {
c.Add("a1", "val1");
Options options;
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
BlockBasedTableOptions table_options;
table_options.index_type = BlockBasedTableOptions::kHashSearch;
table_options.cache_index_and_filter_blocks = true;
table_options.block_cache = NewLRUCache(0);
@@ -2980,7 +2955,7 @@ TEST_F(HarnessTest, FooterTests) {
}
class IndexBlockRestartIntervalTest
: public TableTest,
: public BlockBasedTableTest,
public ::testing::WithParamInterface<int> {
public:
static std::vector<int> GetRestartValues() { return {-1, 0, 1, 8, 16, 32}; }
@@ -3125,8 +3100,8 @@ TEST_F(PrefixTest, PrefixAndWholeKeyTest) {
// rocksdb still works.
}
TEST_P(BlockBasedTableTest, TableWithGlobalSeqno) {
BlockBasedTableOptions bbto = GetBlockBasedTableOptions();
TEST_F(BlockBasedTableTest, TableWithGlobalSeqno) {
BlockBasedTableOptions bbto;
test::StringSink* sink = new test::StringSink();
unique_ptr<WritableFileWriter> file_writer(test::GetWritableFileWriter(sink));
Options options;
@@ -3305,8 +3280,8 @@ TEST_P(BlockBasedTableTest, TableWithGlobalSeqno) {
delete iter;
}
TEST_P(BlockBasedTableTest, BlockAlignTest) {
BlockBasedTableOptions bbto = GetBlockBasedTableOptions();
TEST_F(BlockBasedTableTest, BlockAlignTest) {
BlockBasedTableOptions bbto;
bbto.block_align = true;
test::StringSink* sink = new test::StringSink();
unique_ptr<WritableFileWriter> file_writer(test::GetWritableFileWriter(sink));
@@ -3394,10 +3369,10 @@ TEST_P(BlockBasedTableTest, BlockAlignTest) {
table_reader.reset();
}
TEST_P(BlockBasedTableTest, BadOptions) {
TEST_F(BlockBasedTableTest, BadOptions) {
rocksdb::Options options;
options.compression = kNoCompression;
BlockBasedTableOptions bbto = GetBlockBasedTableOptions();
rocksdb::BlockBasedTableOptions bbto;
bbto.block_size = 4000;
bbto.block_align = true;
+1 -13
View File
@@ -430,19 +430,10 @@ DEFINE_int32(ops_between_duration_checks, 1000,
DEFINE_bool(pin_l0_filter_and_index_blocks_in_cache, false,
"Pin index/filter blocks of L0 files in block cache.");
DEFINE_bool(
pin_top_level_index_and_filter, false,
"Pin top-level index of partitioned index/filter blocks in block cache.");
DEFINE_int32(block_size,
static_cast<int32_t>(rocksdb::BlockBasedTableOptions().block_size),
"Number of bytes in a block.");
DEFINE_int32(
format_version,
static_cast<int32_t>(rocksdb::BlockBasedTableOptions().format_version),
"Format version of SST files.");
DEFINE_int32(block_restart_interval,
rocksdb::BlockBasedTableOptions().block_restart_interval,
"Number of keys between restart points "
@@ -3141,8 +3132,6 @@ void VerifyDBFromDB(std::string& truth_db_name) {
FLAGS_cache_index_and_filter_blocks;
block_based_options.pin_l0_filter_and_index_blocks_in_cache =
FLAGS_pin_l0_filter_and_index_blocks_in_cache;
block_based_options.pin_top_level_index_and_filter =
FLAGS_pin_top_level_index_and_filter;
if (FLAGS_cache_high_pri_pool_ratio > 1e-6) { // > 0.0 + eps
block_based_options.cache_index_and_filter_blocks_with_high_priority =
true;
@@ -3154,8 +3143,7 @@ void VerifyDBFromDB(std::string& truth_db_name) {
block_based_options.index_block_restart_interval =
FLAGS_index_block_restart_interval;
block_based_options.filter_policy = filter_policy_;
block_based_options.format_version =
static_cast<uint32_t>(FLAGS_format_version);
block_based_options.format_version = 2;
block_based_options.read_amp_bytes_per_bit = FLAGS_read_amp_bytes_per_bit;
block_based_options.enable_index_compression =
FLAGS_enable_index_compression;
-1
View File
@@ -48,7 +48,6 @@ default_params = {
"verify_checksum": 1,
"write_buffer_size": 4 * 1024 * 1024,
"writepercent": 35,
"format_version": lambda: random.randint(2, 3),
}
+17 -12
View File
@@ -219,14 +219,10 @@ DEFINE_int32(level0_stop_writes_trigger,
rocksdb::Options().level0_stop_writes_trigger,
"Number of files in level-0 that will trigger put stop.");
DEFINE_int32(block_size, rocksdb::BlockBasedTableOptions().block_size,
DEFINE_int32(block_size,
static_cast<int32_t>(rocksdb::BlockBasedTableOptions().block_size),
"Number of bytes in a block.");
DEFINE_int32(
format_version,
static_cast<int32_t>(rocksdb::BlockBasedTableOptions().format_version),
"Format version of SST files.");
DEFINE_int32(max_background_compactions,
rocksdb::Options().max_background_compactions,
"The maximum number of concurrent background compactions "
@@ -526,6 +522,8 @@ DEFINE_uint64(log2_keys_per_lock, 2, "Log2 of number of keys per lock");
static const bool FLAGS_log2_keys_per_lock_dummy __attribute__((__unused__)) =
RegisterFlagValidator(&FLAGS_log2_keys_per_lock, &ValidateUint32Range);
DEFINE_uint64(max_manifest_file_size, 16384, "Maximum size of a MANIFEST file");
DEFINE_bool(in_place_update, false, "On true, does inplace update in memtable");
enum RepFactory {
@@ -2128,9 +2126,12 @@ class StressTest {
Slice v(value, sz);
if (!FLAGS_test_batches_snapshots) {
// If the chosen key does not allow overwrite and it already
// exists, choose another key.
// exists, choose another key. Also avoid using merge operands in
// no-overwrite positions (where single delete will be called later),
// as those features have undefined behavior when used together.
while (!shared->AllowsOverwrite(rand_column_family, rand_key) &&
shared->Exists(rand_column_family, rand_key)) {
(FLAGS_use_merge ||
shared->Exists(rand_column_family, rand_key))) {
l.reset();
rand_key = thread->rand.Next() % max_key;
rand_column_family = thread->rand.Next() % FLAGS_column_families;
@@ -2481,7 +2482,6 @@ class StressTest {
void PrintEnv() const {
fprintf(stdout, "RocksDB version : %d.%d\n", kMajorVersion,
kMinorVersion);
fprintf(stdout, "Format version : %d\n", FLAGS_format_version);
fprintf(stdout, "TransactionDB : %s\n",
FLAGS_use_txn ? "true" : "false");
fprintf(stdout, "Column families : %d\n", FLAGS_column_families);
@@ -2565,8 +2565,7 @@ class StressTest {
block_based_options.block_cache_compressed = compressed_cache_;
block_based_options.checksum = FLAGS_checksum_type_e;
block_based_options.block_size = FLAGS_block_size;
block_based_options.format_version =
static_cast<uint32_t>(FLAGS_format_version);
block_based_options.format_version = 2;
block_based_options.filter_policy = filter_policy_;
options_.table_factory.reset(
NewBlockBasedTableFactory(block_based_options));
@@ -2607,7 +2606,7 @@ class StressTest {
FLAGS_level0_file_num_compaction_trigger;
options_.compression = FLAGS_compression_type_e;
options_.create_if_missing = true;
options_.max_manifest_file_size = 10 * 1024;
options_.max_manifest_file_size = FLAGS_max_manifest_file_size;
options_.inplace_update_support = FLAGS_in_place_update;
options_.max_subcompactions = static_cast<uint32_t>(FLAGS_subcompactions);
options_.allow_concurrent_memtable_write =
@@ -2923,6 +2922,12 @@ int main(int argc, char** argv) {
kValueMaxLen / kRandomValueMaxFactor);
exit(1);
}
if (FLAGS_use_merge && FLAGS_nooverwritepercent == 100) {
fprintf(
stderr,
"Error: nooverwritepercent must not be 100 when using merge operands");
exit(1);
}
// Choose a location for the test database if none given with --db=<path>
if (FLAGS_db.empty()) {
+25 -5
View File
@@ -254,9 +254,15 @@ inline bool Zlib_Compress(const CompressionOptions& opts,
// memLevel=9 uses maximum memory for optimal speed.
// The default value is 8. See zconf.h for more details.
static const int memLevel = 8;
int level;
if (opts.level == CompressionOptions::kDefaultCompressionLevel) {
level = Z_DEFAULT_COMPRESSION;
} else {
level = opts.level;
}
z_stream _stream;
memset(&_stream, 0, sizeof(z_stream));
int st = deflateInit2(&_stream, opts.level, Z_DEFLATED, opts.window_bits,
int st = deflateInit2(&_stream, level, Z_DEFLATED, opts.window_bits,
memLevel, opts.strategy);
if (st != Z_OK) {
return false;
@@ -719,9 +725,15 @@ inline bool LZ4HC_Compress(const CompressionOptions& opts,
output->resize(static_cast<size_t>(output_header_len + compress_bound));
int outlen;
int level;
if (opts.level == CompressionOptions::kDefaultCompressionLevel) {
level = 0; // lz4hc.h says any value < 1 will be sanitized to default
} else {
level = opts.level;
}
#if LZ4_VERSION_NUMBER >= 10400 // r124+
LZ4_streamHC_t* stream = LZ4_createStreamHC();
LZ4_resetStreamHC(stream, opts.level);
LZ4_resetStreamHC(stream, level);
const char* compression_dict_data =
compression_dict.size() > 0 ? compression_dict.data() : nullptr;
size_t compression_dict_size = compression_dict.size();
@@ -742,7 +754,7 @@ inline bool LZ4HC_Compress(const CompressionOptions& opts,
#elif LZ4_VERSION_MAJOR // r113-r123
outlen = LZ4_compressHC2_limitedOutput(input, &(*output)[output_header_len],
static_cast<int>(length),
compress_bound, opts.level);
compress_bound, level);
#else // up to r112
outlen =
LZ4_compressHC_limitedOutput(input, &(*output)[output_header_len],
@@ -807,15 +819,23 @@ inline bool ZSTD_Compress(const CompressionOptions& opts, const char* input,
size_t compressBound = ZSTD_compressBound(length);
output->resize(static_cast<size_t>(output_header_len + compressBound));
size_t outlen;
int level;
if (opts.level == CompressionOptions::kDefaultCompressionLevel) {
// 3 is the value of ZSTD_CLEVEL_DEFAULT (not exposed publicly), see
// https://github.com/facebook/zstd/issues/1148
level = 3;
} else {
level = opts.level;
}
#if ZSTD_VERSION_NUMBER >= 500 // v0.5.0+
ZSTD_CCtx* context = ZSTD_createCCtx();
outlen = ZSTD_compress_usingDict(
context, &(*output)[output_header_len], compressBound, input, length,
compression_dict.data(), compression_dict.size(), opts.level);
compression_dict.data(), compression_dict.size(), level);
ZSTD_freeCCtx(context);
#else // up to v0.4.x
outlen = ZSTD_compress(&(*output)[output_header_len], compressBound, input,
length, opts.level);
length, level);
#endif // ZSTD_VERSION_NUMBER >= 500
if (outlen == 0) {
return false;
+7 -6
View File
@@ -19,9 +19,6 @@
namespace rocksdb {
namespace test {
const uint32_t kDefaultFormatVersion = BlockBasedTableOptions().format_version;
const uint32_t kLatestFormatVersion = 3u;
Slice RandomString(Random* rnd, int len, std::string* dst) {
dst->resize(len);
for (int i = 0; i < len; i++) {
@@ -119,9 +116,14 @@ class Uint64ComparatorImpl : public Comparator {
};
} // namespace
static port::OnceType once;
static const Comparator* uint64comp;
static void InitModule() { uint64comp = new Uint64ComparatorImpl; }
const Comparator* Uint64Comparator() {
static Uint64ComparatorImpl uint64comp;
return &uint64comp;
port::InitOnce(&once, InitModule);
return uint64comp;
}
WritableFileWriter* GetWritableFileWriter(WritableFile* wf) {
@@ -194,7 +196,6 @@ BlockBasedTableOptions RandomBlockBasedTableOptions(Random* rnd) {
BlockBasedTableOptions opt;
opt.cache_index_and_filter_blocks = rnd->Uniform(2);
opt.pin_l0_filter_and_index_blocks_in_cache = rnd->Uniform(2);
opt.pin_top_level_index_and_filter = rnd->Uniform(2);
opt.index_type = rnd->Uniform(2) ? BlockBasedTableOptions::kBinarySearch
: BlockBasedTableOptions::kHashSearch;
opt.hash_index_allow_collision = rnd->Uniform(2);
+10 -3
View File
@@ -32,9 +32,6 @@ class SequentialFileReader;
namespace test {
extern const uint32_t kDefaultFormatVersion;
extern const uint32_t kLatestFormatVersion;
// Store in *dst a random string of length "len" and return a Slice that
// references the generated data.
extern Slice RandomString(Random* rnd, int len, std::string* dst);
@@ -90,6 +87,13 @@ class PlainInternalKeyComparator : public InternalKeyComparator {
virtual int Compare(const Slice& a, const Slice& b) const override {
return user_comparator()->Compare(a, b);
}
virtual void FindShortestSeparator(std::string* start,
const Slice& limit) const override {
user_comparator()->FindShortestSeparator(start, limit);
}
virtual void FindShortSuccessor(std::string* key) const override {
user_comparator()->FindShortSuccessor(key);
}
};
#endif
@@ -175,6 +179,9 @@ class VectorIterator : public InternalIterator {
virtual Status status() const override { return Status::OK(); }
virtual bool IsKeyPinned() const override { return true; }
virtual bool IsValuePinned() const override { return true; }
private:
std::vector<std::string> keys_;
std::vector<std::string> values_;
@@ -46,8 +46,7 @@ PessimisticTransaction::PessimisticTransaction(
waiting_key_(nullptr),
lock_timeout_(0),
deadlock_detect_(false),
deadlock_detect_depth_(0),
skip_concurrency_control_(false) {
deadlock_detect_depth_(0) {
txn_db_impl_ =
static_cast_with_check<PessimisticTransactionDB, TransactionDB>(txn_db);
db_impl_ = static_cast_with_check<DBImpl, DB>(db_);
@@ -62,7 +61,6 @@ void PessimisticTransaction::Initialize(const TransactionOptions& txn_options) {
deadlock_detect_ = txn_options.deadlock_detect;
deadlock_detect_depth_ = txn_options.deadlock_detect_depth;
write_batch_.SetMaxBytes(txn_options.max_write_batch_size);
skip_concurrency_control_ = txn_options.skip_concurrency_control;
lock_timeout_ = txn_options.lock_timeout * 1000;
if (lock_timeout_ < 0) {
@@ -469,14 +467,11 @@ Status PessimisticTransaction::LockBatch(WriteBatch* batch,
Status PessimisticTransaction::TryLock(ColumnFamilyHandle* column_family,
const Slice& key, bool read_only,
bool exclusive, bool skip_validate) {
Status s;
if (UNLIKELY(skip_concurrency_control_)) {
return s;
}
uint32_t cfh_id = GetColumnFamilyID(column_family);
std::string key_str = key.ToString();
bool previously_locked;
bool lock_upgrade = false;
Status s;
// lock this key if this transactions hasn't already locked it
SequenceNumber tracked_at_seq = kMaxSequenceNumber;
@@ -183,9 +183,6 @@ class PessimisticTransaction : public TransactionBaseImpl {
// Whether to perform deadlock detection or not.
int64_t deadlock_detect_depth_;
// Refer to TransactionOptions::skip_concurrency_control
bool skip_concurrency_control_;
virtual Status ValidateSnapshot(ColumnFamilyHandle* column_family,
const Slice& key,
SequenceNumber* tracked_at_seq);
@@ -129,14 +129,6 @@ Status PessimisticTransactionDB::Initialize(
WriteOptions w_options;
w_options.sync = true;
TransactionOptions t_options;
// This would help avoiding deadlock for keys that although exist in the WAL
// did not go through concurrency control. This includes the merge that
// MyRocks uses for auto-inc columns. It is safe to do so, since (i) if
// there is a conflict between the keys of two transactions that must be
// avoided, it is already avoided by the application, MyRocks, before the
// restart (ii) application, MyRocks, guarntees to rollback/commit the
// recovered transactions before new transactions start.
t_options.skip_concurrency_control = true;
Transaction* real_trx = BeginTransaction(w_options, t_options, nullptr);
assert(real_trx);
@@ -372,7 +372,7 @@ Status TransactionLockMgr::AcquireWithTimeout(
if (wait_ids.size() != 0) {
if (txn->IsDeadlockDetect()) {
if (IncrementWaiters(txn, wait_ids, key, column_family_id,
lock_info.exclusive, env)) {
lock_info.exclusive)) {
result = Status::Busy(Status::SubCode::kDeadlock);
stripe->stripe_mutex->UnLock();
return result;
@@ -444,7 +444,7 @@ void TransactionLockMgr::DecrementWaitersImpl(
bool TransactionLockMgr::IncrementWaiters(
const PessimisticTransaction* txn,
const autovector<TransactionID>& wait_ids, const std::string& key,
const uint32_t& cf_id, const bool& exclusive, Env* const env) {
const uint32_t& cf_id, const bool& exclusive) {
auto id = txn->GetID();
std::vector<int> queue_parents(txn->GetDeadlockDetectDepth());
std::vector<TransactionID> queue_values(txn->GetDeadlockDetectDepth());
@@ -468,7 +468,6 @@ bool TransactionLockMgr::IncrementWaiters(
const auto* next_ids = &wait_ids;
int parent = -1;
int64_t deadlock_time = 0;
for (int tail = 0, head = 0; head < txn->GetDeadlockDetectDepth(); head++) {
int i = 0;
if (next_ids) {
@@ -498,10 +497,8 @@ bool TransactionLockMgr::IncrementWaiters(
extracted_info.m_exclusive});
head = queue_parents[head];
}
env->GetCurrentTime(&deadlock_time);
std::reverse(path.begin(), path.end());
dlock_buffer_.AddNewPath(DeadlockPath(path, deadlock_time));
deadlock_time = 0;
dlock_buffer_.AddNewPath(DeadlockPath(path));
DecrementWaitersImpl(txn, wait_ids);
return true;
} else if (!wait_txn_map_.Contains(next)) {
@@ -514,8 +511,7 @@ bool TransactionLockMgr::IncrementWaiters(
}
// Wait cycle too big, just assume deadlock.
env->GetCurrentTime(&deadlock_time);
dlock_buffer_.AddNewPath(DeadlockPath(deadlock_time, true));
dlock_buffer_.AddNewPath(DeadlockPath(true));
DecrementWaitersImpl(txn, wait_ids);
return true;
}
@@ -143,7 +143,7 @@ class TransactionLockMgr {
bool IncrementWaiters(const PessimisticTransaction* txn,
const autovector<TransactionID>& wait_ids,
const std::string& key, const uint32_t& cf_id,
const bool& exclusive, Env* const env);
const bool& exclusive);
void DecrementWaiters(const PessimisticTransaction* txn,
const autovector<TransactionID>& wait_ids);
void DecrementWaitersImpl(const PessimisticTransaction* txn,
@@ -452,14 +452,6 @@ TEST_P(TransactionTest, DeadlockCycleShared) {
ASSERT_EQ(dlock_buffer.size(), curr_dlock_buffer_len_);
auto dlock_entry = dlock_buffer[0].path;
ASSERT_EQ(dlock_entry.size(), kInitialMaxDeadlocks);
int64_t pre_deadlock_time = dlock_buffer[0].deadlock_time;
int64_t cur_deadlock_time = 0;
for (auto const& dl_path_rec : dlock_buffer) {
cur_deadlock_time = dl_path_rec.deadlock_time;
ASSERT_NE(cur_deadlock_time, 0);
ASSERT_TRUE(cur_deadlock_time <= pre_deadlock_time);
pre_deadlock_time = cur_deadlock_time;
}
int64_t curr_waiting_key = 0;
@@ -665,15 +657,6 @@ TEST_P(TransactionTest, DeadlockCycle) {
ASSERT_EQ(dlock_entry.size(), check_len);
ASSERT_EQ(dlock_buffer[0].limit_exceeded, check_limit_flag);
int64_t pre_deadlock_time = dlock_buffer[0].deadlock_time;
int64_t cur_deadlock_time = 0;
for (auto const& dl_path_rec : dlock_buffer) {
cur_deadlock_time = dl_path_rec.deadlock_time;
ASSERT_NE(cur_deadlock_time, 0);
ASSERT_TRUE(cur_deadlock_time <= pre_deadlock_time);
pre_deadlock_time = cur_deadlock_time;
}
// Iterates backwards over path verifying decreasing txn_ids.
for (auto it = dlock_entry.rbegin(); it != dlock_entry.rend(); it++) {
auto dl_node = *it;
@@ -810,7 +810,6 @@ TEST_P(WritePreparedTransactionTest, CheckAgainstSnapshotsTest) {
std::vector<SequenceNumber> snapshots = {100l, 200l, 300l, 400l, 500l,
600l, 700l, 800l, 900l};
const size_t snapshot_cache_bits = 2;
const uint64_t cache_size = 1ul << snapshot_cache_bits;
// Safety check to express the intended size in the test. Can be adjusted if
// the snapshots lists changed.
assert((1ul << snapshot_cache_bits) * 2 + 1 == snapshots.size());
@@ -838,57 +837,6 @@ TEST_P(WritePreparedTransactionTest, CheckAgainstSnapshotsTest) {
commit_entry.prep_seq <= snapshots.back();
ASSERT_EQ(expect_update, !wp_db->old_commit_map_empty_);
}
// Test that search will include multiple snapshot from snapshot cache
{
// exclude first and last item in the cache
CommitEntry commit_entry = {snapshots.front() + 1,
snapshots[cache_size - 1] - 1};
wp_db->old_commit_map_empty_ = true; // reset
wp_db->old_commit_map_.clear();
wp_db->CheckAgainstSnapshots(commit_entry);
ASSERT_EQ(wp_db->old_commit_map_.size(), cache_size - 2);
}
// Test that search will include multiple snapshot from old snapshots
{
// include two in the middle
CommitEntry commit_entry = {snapshots[cache_size] + 1,
snapshots[cache_size + 2] + 1};
wp_db->old_commit_map_empty_ = true; // reset
wp_db->old_commit_map_.clear();
wp_db->CheckAgainstSnapshots(commit_entry);
ASSERT_EQ(wp_db->old_commit_map_.size(), 2);
}
// Test that search will include both snapshot cache and old snapshots
// Case 1: includes all in snapshot cache
{
CommitEntry commit_entry = {snapshots.front() - 1, snapshots.back() + 1};
wp_db->old_commit_map_empty_ = true; // reset
wp_db->old_commit_map_.clear();
wp_db->CheckAgainstSnapshots(commit_entry);
ASSERT_EQ(wp_db->old_commit_map_.size(), snapshots.size());
}
// Case 2: includes all snapshot caches except the smallest
{
CommitEntry commit_entry = {snapshots.front() + 1, snapshots.back() + 1};
wp_db->old_commit_map_empty_ = true; // reset
wp_db->old_commit_map_.clear();
wp_db->CheckAgainstSnapshots(commit_entry);
ASSERT_EQ(wp_db->old_commit_map_.size(), snapshots.size() - 1);
}
// Case 3: includes only the largest of snapshot cache
{
CommitEntry commit_entry = {snapshots[cache_size - 1] - 1,
snapshots.back() + 1};
wp_db->old_commit_map_empty_ = true; // reset
wp_db->old_commit_map_.clear();
wp_db->CheckAgainstSnapshots(commit_entry);
ASSERT_EQ(wp_db->old_commit_map_.size(), snapshots.size() - cache_size + 1);
}
}
// This test is too slow for travis
@@ -1345,6 +1293,55 @@ TEST_P(WritePreparedTransactionTest, BasicRecoveryTest) {
pinnable_val.Reset();
}
// After recovery the new transactions should still conflict with recovered
// transactions.
TEST_P(WritePreparedTransactionTest, ConflictDetectionAfterRecoveryTest) {
options.disable_auto_compactions = true;
ReOpen();
TransactionOptions txn_options;
WriteOptions write_options;
size_t index = 0;
Transaction* txn0 = db->BeginTransaction(write_options, txn_options);
auto istr0 = std::to_string(index);
auto s = txn0->SetName("xid" + istr0);
ASSERT_OK(s);
s = txn0->Put(Slice("key" + istr0), Slice("bar0" + istr0));
ASSERT_OK(s);
s = txn0->Prepare();
// With the same index 0 and key prefix, txn_t0 should conflict with txn0
txn_t0_with_status(0, Status::TimedOut());
delete txn0;
auto db_impl = reinterpret_cast<DBImpl*>(db->GetRootDB());
db_impl->FlushWAL(true);
dynamic_cast<WritePreparedTxnDB*>(db)->TEST_Crash();
ReOpenNoDelete();
// It should still conflict after the recovery
txn_t0_with_status(0, Status::TimedOut());
db_impl = reinterpret_cast<DBImpl*>(db->GetRootDB());
db_impl->FlushWAL(true);
ReOpenNoDelete();
// Check that a recovered txn will still cause conflicts after 2nd recovery
txn_t0_with_status(0, Status::TimedOut());
txn0 = db->GetTransactionByName("xid" + istr0);
ASSERT_NE(txn0, nullptr);
txn0->Commit();
delete txn0;
db_impl = reinterpret_cast<DBImpl*>(db->GetRootDB());
db_impl->FlushWAL(true);
ReOpenNoDelete();
// tnx0 is now committed and should no longer cause a conflict
txn_t0_with_status(0, Status::OK());
}
// After recovery the commit map is empty while the max is set. The code would
// go through a different path which requires a separate test.
TEST_P(WritePreparedTransactionTest, IsInSnapshotEmptyMapTest) {
@@ -567,16 +567,14 @@ void WritePreparedTxnDB::ReleaseSnapshotInternal(
bool need_gc = false;
{
WPRecordTick(TXN_OLD_COMMIT_MAP_MUTEX_OVERHEAD);
ROCKS_LOG_WARN(info_log_, "old_commit_map_mutex_ overhead for %" PRIu64,
snap_seq);
ROCKS_LOG_WARN(info_log_, "old_commit_map_mutex_ overhead");
ReadLock rl(&old_commit_map_mutex_);
auto prep_set_entry = old_commit_map_.find(snap_seq);
need_gc = prep_set_entry != old_commit_map_.end();
}
if (need_gc) {
WPRecordTick(TXN_OLD_COMMIT_MAP_MUTEX_OVERHEAD);
ROCKS_LOG_WARN(info_log_, "old_commit_map_mutex_ overhead for %" PRIu64,
snap_seq);
ROCKS_LOG_WARN(info_log_, "old_commit_map_mutex_ overhead");
WriteLock wl(&old_commit_map_mutex_);
old_commit_map_.erase(snap_seq);
old_commit_map_empty_.store(old_commit_map_.empty(),
@@ -651,20 +649,13 @@ void WritePreparedTxnDB::CheckAgainstSnapshots(const CommitEntry& evicted) {
// place before gets overwritten the reader that reads bottom-up will
// eventully see it.
const bool next_is_larger = true;
// We will set to true if the border line snapshot suggests that.
bool search_larger_list = false;
SequenceNumber snapshot_seq = kMaxSequenceNumber;
size_t ip1 = std::min(cnt, SNAPSHOT_CACHE_SIZE);
for (; 0 < ip1; ip1--) {
SequenceNumber snapshot_seq =
snapshot_cache_[ip1 - 1].load(std::memory_order_acquire);
snapshot_seq = snapshot_cache_[ip1 - 1].load(std::memory_order_acquire);
TEST_IDX_SYNC_POINT("WritePreparedTxnDB::CheckAgainstSnapshots:p:",
++sync_i);
TEST_IDX_SYNC_POINT("WritePreparedTxnDB::CheckAgainstSnapshots:s:", sync_i);
if (ip1 == SNAPSHOT_CACHE_SIZE) { // border line snapshot
// snapshot_seq < commit_seq => larger_snapshot_seq <= commit_seq
// then later also continue the search to larger snapshots
search_larger_list = snapshot_seq < evicted.commit_seq;
}
if (!MaybeUpdateOldCommitMap(evicted.prep_seq, evicted.commit_seq,
snapshot_seq, !next_is_larger)) {
break;
@@ -679,20 +670,17 @@ void WritePreparedTxnDB::CheckAgainstSnapshots(const CommitEntry& evicted) {
#endif
TEST_SYNC_POINT("WritePreparedTxnDB::CheckAgainstSnapshots:p:end");
TEST_SYNC_POINT("WritePreparedTxnDB::CheckAgainstSnapshots:s:end");
if (UNLIKELY(SNAPSHOT_CACHE_SIZE < cnt && search_larger_list)) {
if (UNLIKELY(SNAPSHOT_CACHE_SIZE < cnt && ip1 == SNAPSHOT_CACHE_SIZE &&
snapshot_seq < evicted.prep_seq)) {
// Then access the less efficient list of snapshots_
WPRecordTick(TXN_SNAPSHOT_MUTEX_OVERHEAD);
ROCKS_LOG_WARN(info_log_,
"snapshots_mutex_ overhead for <%" PRIu64 ",%" PRIu64
"> with %" ROCKSDB_PRIszt " snapshots",
evicted.prep_seq, evicted.commit_seq, cnt);
ROCKS_LOG_WARN(info_log_, "snapshots_mutex_ overhead");
ReadLock rl(&snapshots_mutex_);
// Items could have moved from the snapshots_ to snapshot_cache_ before
// accquiring the lock. To make sure that we do not miss a valid snapshot,
// read snapshot_cache_ again while holding the lock.
for (size_t i = 0; i < SNAPSHOT_CACHE_SIZE; i++) {
SequenceNumber snapshot_seq =
snapshot_cache_[i].load(std::memory_order_acquire);
snapshot_seq = snapshot_cache_[i].load(std::memory_order_acquire);
if (!MaybeUpdateOldCommitMap(evicted.prep_seq, evicted.commit_seq,
snapshot_seq, next_is_larger)) {
break;
@@ -720,10 +708,7 @@ bool WritePreparedTxnDB::MaybeUpdateOldCommitMap(
// then snapshot_seq < commit_seq
if (prep_seq <= snapshot_seq) { // overlapping range
WPRecordTick(TXN_OLD_COMMIT_MAP_MUTEX_OVERHEAD);
ROCKS_LOG_WARN(info_log_,
"old_commit_map_mutex_ overhead for %" PRIu64
" commit entry: <%" PRIu64 ",%" PRIu64 ">",
snapshot_seq, prep_seq, commit_seq);
ROCKS_LOG_WARN(info_log_, "old_commit_map_mutex_ overhead");
WriteLock wl(&old_commit_map_mutex_);
old_commit_map_empty_.store(false, std::memory_order_release);
auto& vec = old_commit_map_[snapshot_seq];
@@ -222,6 +222,7 @@ class WritePreparedTxnDB : public PessimisticTransactionDB {
// rare case and it is ok to pay the cost of mutex ReadLock for such old,
// reading transactions.
WPRecordTick(TXN_OLD_COMMIT_MAP_MUTEX_OVERHEAD);
ROCKS_LOG_WARN(info_log_, "old_commit_map_mutex_ overhead");
ReadLock rl(&old_commit_map_mutex_);
auto prep_set_entry = old_commit_map_.find(snapshot_seq);
bool found = prep_set_entry != old_commit_map_.end();