Compare commits

...

35 Commits

Author SHA1 Message Date
Maysam Yabandeh 8756a118be WritePrepared: Fix bug in searching in non-cached snapshots (#4639)
Summary:
When evicting an entry form the commit_cache, it is verified against the list of old snapshots to see if it overlaps with any. The list of old snapshots is split into two lists: an efficient concurrent cache and an slow vector protected by a lock. The patch fixes a bug that would stop the search in the cache if it finds any and yet would not include the larger snapshots in the slower list.
An extra info log entry is also removed. The condition to trigger that although very rare is still feasible and should not spam the LOG when that happens.
Fixes #4621
Pull Request resolved: https://github.com/facebook/rocksdb/pull/4639

Differential Revision: D12934989

Pulled By: maysamyabandeh

fbshipit-source-id: 4e0fe8147ba292b554ae78e94c21c2ef31e03e2d
2018-11-06 14:00:18 -08:00
Maysam Yabandeh c190eb57ba Skip concurrency control during recovery of pessimistic txn (#4346)
Summary:
TransactionOptions::skip_concurrency_control allows pessimistic transactions to skip the overhead of concurrency control. This could be as an optimization if the application knows that the transaction would not have any conflict with concurrent transactions. It is currently used during recovery assuming (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.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/4346

Differential Revision: D9759149

Pulled By: maysamyabandeh

fbshipit-source-id: f896e84fa58b0b584be904c7fd3883a41ea3215b
2018-09-24 11:34:21 -07:00
Andrew Kryczka ca4cfb8877 bump version and update history 2018-08-31 15:28:10 -07:00
Taewook Oh 4ddb620ddb Suppress leak warning for clang(LLVM) asan (#4066)
Summary:
Instead of __SANITIZE_ADDRESS__ macro, LLVM uses __has_feature(address_sanitzer) to check if ASAN is enabled for the build. I tested it with MySQL sanitizer build that uses RocksDB as a submodule.
Closes https://github.com/facebook/rocksdb/pull/4066

Reviewed By: riversand963

Differential Revision: D8668941

Pulled By: taewookoh

fbshipit-source-id: af4d1da180c1470d257a228f431eebc61490bc36
2018-08-31 15:25:18 -07:00
Andrew Kryczka 2ae772050b bump version 2018-07-30 11:47:23 -07:00
Andrew Kryczka e8330a2e74 Smaller tail readahead when not reading index/filters (#4159)
Summary:
In all cases during `BlockBasedTable::Open`, we issue at least three read requests to the file's tail: (1) footer, (2) metaindex block, and (3) properties block. Depending on the config, we may also read other metablocks like filter and index.

This PR issues smaller readahead when we expect to do only the three necessary reads mentioned above. Then, 4KB should be enough (ignoring the case where there are lots of user-defined properties). We can keep doing 512KB readahead when additional reads are expected.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/4159

Differential Revision: D8924002

Pulled By: ajkr

fbshipit-source-id: cfc713275de4d05ce11f18571f1d72e27ccd3356
2018-07-20 13:32:29 -07:00
chouxi f912a80c15 Store timestamp in deadlock detection (#4060)
Summary:
- Summary
    Add timestamp into the DeadlockInfo to store the timestamp when deadlock detected on the rocksdb side.

- Testplan:
    `make check -j64`
Closes https://github.com/facebook/rocksdb/pull/4060

Differential Revision: D8655380

Pulled By: chouxi

fbshipit-source-id: f58e1aa5e09eb1d1eed0a181d4e2304aaf01efe8
2018-07-12 13:26:30 -07:00
Maysam Yabandeh cba8a8d9ae Fix mis-spoken assert on prefetch_filter and prefetch_index (#4077)
Summary:
We can have prefetch_index without prefetch_filter but not the other way around. The assert statement is fixed.
Closes https://github.com/facebook/rocksdb/pull/4077

Differential Revision: D8694472

Pulled By: maysamyabandeh

fbshipit-source-id: ccd2804d9d9cdafb1c3e65062c7bc38603e69004
2018-07-10 15:33:14 -07:00
Maysam Yabandeh a19312e8ce Charging block cache more accurately (#4073)
Summary:
Currently the block cache is charged only by the size of the raw data block and excludes the overhead of the c++ objects that contain the raw data block. The patch improves the accuracy of the charge by including the c++ object overhead into it.
Closes https://github.com/facebook/rocksdb/pull/4073

Differential Revision: D8686552

Pulled By: maysamyabandeh

fbshipit-source-id: 8472f7fc163c0644533bc6942e20cdd5725f520f
2018-07-10 15:32:52 -07:00
Maysam Yabandeh a99c562305 Pin top-level index on partitioned index/filter blocks (#4037)
Summary:
Top-level index in partitioned index/filter blocks are small and could be pinned in memory. So far we use that by cache_index_and_filter_blocks to false. This however make it difficult to keep account of the total memory usage. This patch introduces pin_top_level_index_and_filter which in combination with cache_index_and_filter_blocks=true keeps the top-level index in cache and yet pinned them to avoid cache misses and also cache lookup overhead.
Closes https://github.com/facebook/rocksdb/pull/4037

Differential Revision: D8596218

Pulled By: maysamyabandeh

fbshipit-source-id: 3a5f7f9ca6b4b525b03ff6bd82354881ae974ad2
2018-07-10 15:28:50 -07:00
Siying Dong a39fb8267f 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-07-10 15:18:22 -07:00
Maysam Yabandeh d1873ed841 Extend format 3 to partitioned index/filters (#3958)
Summary:
format_version 3 changes the format of index blocks by storing user keys instead of the internal keys, which saves 8-bytes per key. This patch extends the format to top-level indexes in partitioned index/filters.
Closes https://github.com/facebook/rocksdb/pull/3958

Differential Revision: D8294615

Pulled By: maysamyabandeh

fbshipit-source-id: 17666cc16b8076c363972e2308e31547e835f0fe
2018-07-10 15:08:22 -07:00
Maysam Yabandeh 0e4f96e1d1 Extend some tests to format_version=3 (#3942)
Summary:
format_version=3 changes the format of SST index. This is however not being tested currently since tests only work with the default format_version which is currently 2. The patch extends the most related tests to also test for format_version=3.
Closes https://github.com/facebook/rocksdb/pull/3942

Differential Revision: D8238413

Pulled By: maysamyabandeh

fbshipit-source-id: 915725f55753dd8e9188e802bf471c23645ad035
2018-07-10 15:08:02 -07:00
Zhongyi Xie 131b62be31 fix PrefixExtractorChanged: pass raw pointer instead shared_ptr
Summary:
This should resolve the performance regression caused by the unnecessary copying of the shared_ptr.
Closes https://github.com/facebook/rocksdb/pull/3937

Differential Revision: D8232330

Pulled By: miasantreble

fbshipit-source-id: 7885bf7cd190b6f87164c52d6edd328298c13f97
2018-07-10 15:06:55 -07:00
Maysam Yabandeh 6c45345353 Fix the bug of some test scenarios being put after kEnd
Summary:
DBTestBase::OptionConfig includes the scenarios that unit tests could iterate over them by calling ChangeOptions(). Some of the options have  been mistakenly put after kEnd which makes them essentially invisible to ChangeOptions() caller. This patch fixes it except for kUniversalSubcompactions which is left as TODO since it would break some unit tests.
Closes https://github.com/facebook/rocksdb/pull/3935

Differential Revision: D8230748

Pulled By: maysamyabandeh

fbshipit-source-id: edddb8fffcd161af1809fef24798ce118f8593db
2018-07-10 15:06:44 -07:00
Maysam Yabandeh 482f659733 Check for rep_->table_properties being nullptr
Summary:
The very old sst formats do not have table_properties and rep_->table_properties is thus nullptr. The recent patch in https://github.com/facebook/rocksdb/pull/3894 does not check for nullptr and hence makes it backward incompatible. This patch adds the check.
Closes https://github.com/facebook/rocksdb/pull/3918

Differential Revision: D8188638

Pulled By: maysamyabandeh

fbshipit-source-id: b1d986665ecf0b4d1c442adfa8a193b97707d47b
2018-07-10 15:06:33 -07:00
Maysam Yabandeh b082a2d63f Exclude seq from index keys
Summary:
Index blocks have the same format as data blocks. The keys therefore similarly to the keys in the data blocks are internal keys, which means that in addition to the user key it also has 8 bytes that encodes sequence number and value type. This extra 8 bytes however is not necessary in index blocks since the index keys act as an separator between two data blocks. The only exception is when the last key of a block and the first key of the next block share the same user key, in which the sequence number is required to act as a separator.
The patch excludes the sequence from index keys only if the above special case does not happen for any of the index keys. It then records that in the property block. The reader looks at the property block to see if it should expect sequence numbers in the keys of the index block.s
Closes https://github.com/facebook/rocksdb/pull/3894

Differential Revision: D8118775

Pulled By: maysamyabandeh

fbshipit-source-id: 915479f028b5799ca91671d67455ecdefbd873bd
2018-07-10 14:51:40 -07:00
Siying Dong afb79a8165 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-07-10 14:51:23 -07:00
Zhongyi Xie fee4fe2abe 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-07-10 14:32:37 -07:00
Zhongyi Xie 6c9b549544 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-07-10 14:13:20 -07:00
Sagar Vemuri 5089e12116 Bump version to 5.14.2 and update HISTORY 2018-07-03 20:56:14 -07:00
sdong 7d7b4e04db Update HISTORY.md 2018-07-03 19:57:11 -07:00
Siying Dong 9b450cbae6 Change default value of bytes_max_delete_chunk to 0 in NewSstFileManager() (#4092)
Summary:
Now by default, with NewSstFileManager, checkpoints may be corrupted. Disable this feature to avoid this issue.
Closes https://github.com/facebook/rocksdb/pull/4092

Differential Revision: D8729856

Pulled By: siying

fbshipit-source-id: 914c321d6eaf52d8c5981171322d85dd29088307
2018-07-03 19:56:11 -07:00
Adam Retter 32ccae27f4 Remove unused arg which causes compilation failure (#4080)
Summary:
It seems that compilation has been made stricter about unused args.
Closes https://github.com/facebook/rocksdb/pull/4080

Differential Revision: D8712049

Pulled By: sagar0

fbshipit-source-id: 984af1982638af3568aac1a167f565f4741badee
2018-07-02 10:34:10 -07:00
Andrey Zagrebin 0ac22f2921 check if data size exceeds java array vm limit when it is copied in jni (#3850)
Summary:
to address issue #3849
Closes https://github.com/facebook/rocksdb/pull/3850

Differential Revision: D8695487

Pulled By: sagar0

fbshipit-source-id: 04baeb2127663934ed1321fe6d9a9ec23c86e16b
2018-06-29 16:44:47 -07:00
Adam Retter 6633bd0caa Set DEBUG_LEVEL=0 for RocksJava Mac Release (#4040)
Summary:
Closes https://github.com/facebook/rocksdb/issues/2717
Closes https://github.com/facebook/rocksdb/pull/4040

Differential Revision: D8592058

Pulled By: sagar0

fbshipit-source-id: d01099a1067aa32659abb0b4bed641d919a3927e
2018-06-29 12:41:43 -07:00
Tomas Kolda 1e3fe96ffc Crash on Windows, because of shared_ptr reinterpret cast (#3999)
Summary:
For more details see #3998
Closes https://github.com/facebook/rocksdb/pull/3999

Differential Revision: D8458905

Pulled By: sagar0

fbshipit-source-id: d6e09182933253a08eaf81ac7cfe50ed3b6576c5
2018-06-29 12:32:44 -07:00
Yi Wu 4e69cf0d20 Update TARGETS file (#4028)
Summary:
-Wshorten-64-to-32 is invalid flag in fbcode. Changing it to -Warrowing.
Closes https://github.com/facebook/rocksdb/pull/4028

Differential Revision: D8553694

Pulled By: yiwu-arbug

fbshipit-source-id: 1523cbcb4c76cf1d2b10a4d28b5f58c78e6cb876
2018-06-24 12:00:43 -07:00
Yi Wu 66d2c15e00 Update HISTORY.md for 5.14.1 2018-06-20 12:22:32 -07:00
Yi Wu e49a7097b4 Bump version to 5.14.1 2018-06-20 11:53:14 -07:00
Mike Kolupaev 60842997c5 Fix performance regression in Get() for block-based tables (#3953)
Summary:
This fixes a regression in one of myrocks regression tests (readwhilewriting), introduced in https://github.com/facebook/rocksdb/commit/8bf555f487d1de84a4fb19cb97b9ae1a8dbebc60

This PR changes two lines of code: one of them actually fixes the observed regression, the other is a mostly unrelated small fix that I'm piggy-backing here. EDIT: Nevermind, it fixes one line. More details in inline comments.
Closes https://github.com/facebook/rocksdb/pull/3953

Differential Revision: D8270664

Pulled By: al13n321

fbshipit-source-id: a7d91e196807d1e816551591257c700f70e4ccac
2018-06-20 11:13:44 -07:00
Maysam Yabandeh d2239f0fce Fix the bug with duplicate prefix in partition filters (#4024)
Summary:
https://github.com/facebook/rocksdb/pull/3764 introduced an optimization feature to skip duplicate prefix entires in full bloom filters. Unfortunately it also introduces a bug in partitioned full filters, where the duplicate prefix should still be inserted if it is in a new partition. The patch fixes the bug by resetting the duplicate detection logic each time a partition is cut.
This bug could result into false negatives, which means that DB could skip an existing key.
Closes https://github.com/facebook/rocksdb/pull/4024

Differential Revision: D8518866

Pulled By: maysamyabandeh

fbshipit-source-id: 044f4d988e606a330ecafd8c79daceb68b8796bf
2018-06-19 15:25:24 -07:00
Siying Dong 6278420cd0 Fix regression bug of Prev() with upper bound (#3989)
Summary:
A recent change pushed down the upper bound checking to child iterators. However, this causes the logic of following sequence wrong:
  Seek(key);
  if (!Valid()) SeekToLast();
Because !Valid() may be caused by upper bounds, rather than the end of the iterator. In this case SeekToLast() points to totally wrong places. This can cause wrong results, infinite loops, or segfault in some cases.
This sequence is called when changing direction from forward to backward. And this by itself also implicitly happen during reseeking optimization in Prev().

Fix this bug by using SeekForPrev() rather than this sequuence, as what is already done in prefix extrator case.
Closes https://github.com/facebook/rocksdb/pull/3989

Differential Revision: D8385422

Pulled By: siying

fbshipit-source-id: 429e869990cfd2dc389421e0836fc496bed67bb4
2018-06-12 17:03:28 -07:00
Adam Retter abf9ad9193 Fix an issue with unnecessary capture in lambda expressions
Summary:
Closes https://github.com/facebook/rocksdb/issues/3900
Replaces https://github.com/facebook/rocksdb/pull/3901

I needed this to build v5.12.4 on Mac OS X (10.13.3).
Closes https://github.com/facebook/rocksdb/pull/3904

Differential Revision: D8169357

Pulled By: sagar0

fbshipit-source-id: 85faac42168796e7def9250d0c221a9a03b84476
2018-05-25 16:12:21 -07:00
Yanqin Jin 457f746a78 Fix segfault caused by object premature destruction
Summary:
Please refer to earlier discussion in [issue 3609](https://github.com/facebook/rocksdb/issues/3609).
There was also an alternative fix in [PR 3888](https://github.com/facebook/rocksdb/pull/3888), but the proposed solution requires complex change.

To summarize the cause of the problem. Upon creation of a column family, a `BlockBasedTableFactory` object is `new`ed and encapsulated by a `std::shared_ptr`. Since there is no other `std::shared_ptr` pointing to this `BlockBasedTableFactory`, when the column family is dropped, the `ColumnFamilyData` is `delete`d, causing the destructor of `std::shared_ptr`. Since there is no other `std::shared_ptr`, the underlying memory is also freed.
Later when the db exits, it releases all the table readers, including the table readers that have been operating on the dropped column family. This needs to access the `table_options` owned by `BlockBasedTableFactory` that has already been deleted. Therefore, a segfault is raised.
Previous workaround is to purge all obsolete files upon `ColumnFamilyData` destruction, which leads to a force release of table readers of the dropped column family. However this does not work when the user disables file deletion.

Our solution in this PR is making a copy of `table_options` in `BlockBasedTable::Rep`. This solution increases memory copy and usage, but is much simpler.

Test plan
```
$ make -j16
$ ./column_family_test --gtest_filter=ColumnFamilyTest.CreateDropAndDestroy:ColumnFamilyTest.CreateDropAndDestroyWithoutFileDeletion
```

Expected behavior:
All tests should pass.
Closes https://github.com/facebook/rocksdb/pull/3898

Differential Revision: D8149421

Pulled By: riversand963

fbshipit-source-id: eaecc2e064057ef607fbdd4cc275874f866c3438
2018-05-25 15:12:29 -07:00
119 changed files with 2888 additions and 1371 deletions
+37 -1
View File
@@ -1,5 +1,37 @@
# Rocksdb Change Log # Rocksdb Change Log
## Unreleased ## 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.
## 5.14.0 (5/16/2018) ## 5.14.0 (5/16/2018)
### Public API Change ### Public API Change
@@ -19,6 +51,7 @@
* Add `Env::LowerThreadPoolCPUPriority(Priority)` method, which lowers the CPU priority of background (esp. compaction) threads to minimize interference with foreground tasks. * Add `Env::LowerThreadPoolCPUPriority(Priority)` method, which lowers the CPU priority of background (esp. compaction) threads to minimize interference with foreground tasks.
* Fsync parent directory after deleting a file in delete scheduler. * Fsync parent directory after deleting a file in delete scheduler.
* In level-based compaction, if bottom-pri thread pool was setup via `Env::SetBackgroundThreads()`, compactions to the bottom level will be delegated to that thread pool. * In level-based compaction, if bottom-pri thread pool was setup via `Env::SetBackgroundThreads()`, compactions to the bottom level will be delegated to that thread pool.
* `prefix_extractor` has been moved from ImmutableCFOptions to MutableCFOptions, meaning it can be dynamically changed without a DB restart.
### Bug Fixes ### Bug Fixes
* Fsync after writing global seq number to the ingestion file in ExternalSstFileIngestionJob. * Fsync after writing global seq number to the ingestion file in ExternalSstFileIngestionJob.
@@ -26,6 +59,8 @@
* Fix `BackupableDBOptions::max_valid_backups_to_open` to not delete backup files when refcount cannot be accurately determined. * 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 * 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. * 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 ### Java API Changes
* Add `BlockBasedTableConfig.setBlockCache` to allow sharing a block cache across DB instances. * Add `BlockBasedTableConfig.setBlockCache` to allow sharing a block cache across DB instances.
@@ -106,7 +141,8 @@
* `BackupableDBOptions::max_valid_backups_to_open == 0` now means no backups will be opened during BackupEngine initialization. Previously this condition disabled limiting backups opened. * `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. * `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. * 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 * 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. * 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. * 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,6 +85,10 @@ ifeq ($(MAKECMDGOALS),rocksdbjavastaticrelease)
DEBUG_LEVEL=0 DEBUG_LEVEL=0
endif endif
ifeq ($(MAKECMDGOALS),rocksdbjavastaticreleasedocker)
DEBUG_LEVEL=0
endif
ifeq ($(MAKECMDGOALS),rocksdbjavastaticpublish) ifeq ($(MAKECMDGOALS),rocksdbjavastaticpublish)
DEBUG_LEVEL=0 DEBUG_LEVEL=0
endif endif
+5 -5
View File
@@ -28,7 +28,7 @@ rocksdb_compiler_flags = [
# Added missing flags from output of build_detect_platform # Added missing flags from output of build_detect_platform
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX", "-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
"-DROCKSDB_BACKTRACE", "-DROCKSDB_BACKTRACE",
"-Wshorten-64-to-32", "-Wnarrowing",
] ]
rocksdb_external_deps = [ rocksdb_external_deps = [
@@ -556,13 +556,13 @@ ROCKS_TESTS = [
"serial", "serial",
], ],
[ [
"db_iter_test", "db_iter_stress_test",
"db/db_iter_test.cc", "db/db_iter_stress_test.cc",
"serial", "serial",
], ],
[ [
"db_iter_stress_test", "db_iter_test",
"db/db_iter_stress_test.cc", "db/db_iter_test.cc",
"serial", "serial",
], ],
[ [
+1 -1
View File
@@ -32,7 +32,7 @@ rocksdb_compiler_flags = [
# Added missing flags from output of build_detect_platform # Added missing flags from output of build_detect_platform
"-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX", "-DROCKSDB_PTHREAD_ADAPTIVE_MUTEX",
"-DROCKSDB_BACKTRACE", "-DROCKSDB_BACKTRACE",
"-Wshorten-64-to-32", "-Wnarrowing",
] ]
rocksdb_external_deps = [ rocksdb_external_deps = [
+7
View File
@@ -505,9 +505,16 @@ uint32_t LRUCache::GetHash(Handle* handle) const {
void LRUCache::DisownData() { void LRUCache::DisownData() {
// Do not drop data if compile with ASAN to suppress leak warning. // 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__ #ifndef __SANITIZE_ADDRESS__
shards_ = nullptr; shards_ = nullptr;
#endif // !__SANITIZE_ADDRESS__ #endif // !__SANITIZE_ADDRESS__
#endif // __clang__
} }
size_t LRUCache::TEST_GetLRUSize() { size_t LRUCache::TEST_GetLRUSize() {
+17 -14
View File
@@ -39,7 +39,7 @@ namespace rocksdb {
class TableFactory; class TableFactory;
TableBuilder* NewTableBuilder( TableBuilder* NewTableBuilder(
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions, const MutableCFOptions& moptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories, int_tbl_prop_collector_factories,
@@ -52,19 +52,20 @@ TableBuilder* NewTableBuilder(
TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) == TablePropertiesCollectorFactory::Context::kUnknownColumnFamily) ==
column_family_name.empty()); column_family_name.empty());
return ioptions.table_factory->NewTableBuilder( return ioptions.table_factory->NewTableBuilder(
TableBuilderOptions( TableBuilderOptions(ioptions, moptions, internal_comparator,
ioptions, internal_comparator, int_tbl_prop_collector_factories, int_tbl_prop_collector_factories, compression_type,
compression_type, compression_opts, compression_dict, skip_filters, compression_opts, compression_dict, skip_filters,
column_family_name, level, creation_time, oldest_key_time), column_family_name, level, creation_time,
oldest_key_time),
column_family_id, file); column_family_id, file);
} }
Status BuildTable( Status BuildTable(
const std::string& dbname, Env* env, const ImmutableCFOptions& ioptions, const std::string& dbname, Env* env, const ImmutableCFOptions& ioptions,
const MutableCFOptions& /*mutable_cf_options*/, const MutableCFOptions& mutable_cf_options, const EnvOptions& env_options,
const EnvOptions& env_options, TableCache* table_cache, TableCache* table_cache, InternalIterator* iter,
InternalIterator* iter, std::unique_ptr<InternalIterator> range_del_iter, std::unique_ptr<InternalIterator> range_del_iter, FileMetaData* meta,
FileMetaData* meta, const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories, int_tbl_prop_collector_factories,
uint32_t column_family_id, const std::string& column_family_name, uint32_t column_family_id, const std::string& column_family_name,
@@ -122,10 +123,11 @@ Status BuildTable(
file_writer.reset(new WritableFileWriter(std::move(file), env_options, file_writer.reset(new WritableFileWriter(std::move(file), env_options,
ioptions.statistics)); ioptions.statistics));
builder = NewTableBuilder( builder = NewTableBuilder(
ioptions, internal_comparator, int_tbl_prop_collector_factories, ioptions, mutable_cf_options, internal_comparator,
column_family_id, column_family_name, file_writer.get(), compression, int_tbl_prop_collector_factories, column_family_id,
compression_opts, level, nullptr /* compression_dict */, column_family_name, file_writer.get(), compression, compression_opts,
false /* skip_filters */, creation_time, oldest_key_time); level, nullptr /* compression_dict */, false /* skip_filters */,
creation_time, oldest_key_time);
} }
MergeHelper merge(env, internal_comparator.user_comparator(), MergeHelper merge(env, internal_comparator.user_comparator(),
@@ -195,7 +197,8 @@ Status BuildTable(
// to cache it here for further user reads // to cache it here for further user reads
std::unique_ptr<InternalIterator> it(table_cache->NewIterator( std::unique_ptr<InternalIterator> it(table_cache->NewIterator(
ReadOptions(), env_options, internal_comparator, meta->fd, ReadOptions(), env_options, internal_comparator, meta->fd,
nullptr /* range_del_agg */, nullptr, nullptr /* range_del_agg */,
mutable_cf_options.prefix_extractor.get(), nullptr,
(internal_stats == nullptr) ? nullptr (internal_stats == nullptr) ? nullptr
: internal_stats->GetFileReadHist(0), : internal_stats->GetFileReadHist(0),
false /* for_compaction */, nullptr /* arena */, false /* for_compaction */, nullptr /* arena */,
+1 -1
View File
@@ -43,7 +43,7 @@ class InternalIterator;
// @param compression_dict Data for presetting the compression library's // @param compression_dict Data for presetting the compression library's
// dictionary, or nullptr. // dictionary, or nullptr.
TableBuilder* NewTableBuilder( TableBuilder* NewTableBuilder(
const ImmutableCFOptions& options, const ImmutableCFOptions& options, const MutableCFOptions& moptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories, int_tbl_prop_collector_factories,
+5
View File
@@ -1969,6 +1969,11 @@ 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; 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( void rocksdb_options_set_block_based_table_factory(
rocksdb_options_t *opt, rocksdb_options_t *opt,
rocksdb_block_based_table_options_t* table_options) { rocksdb_block_based_table_options_t* table_options) {
+144 -72
View File
@@ -57,9 +57,9 @@ class EnvCounter : public EnvWrapper {
std::atomic<int> num_new_writable_file_; std::atomic<int> num_new_writable_file_;
}; };
class ColumnFamilyTest : public testing::Test { class ColumnFamilyTestBase : public testing::Test {
public: public:
ColumnFamilyTest() : rnd_(139) { ColumnFamilyTestBase(uint32_t format) : rnd_(139), format_(format) {
env_ = new EnvCounter(Env::Default()); env_ = new EnvCounter(Env::Default());
dbname_ = test::TmpDir() + "/column_family_test"; dbname_ = test::TmpDir() + "/column_family_test";
db_options_.create_if_missing = true; db_options_.create_if_missing = true;
@@ -68,7 +68,7 @@ class ColumnFamilyTest : public testing::Test {
DestroyDB(dbname_, Options(db_options_, column_family_options_)); DestroyDB(dbname_, Options(db_options_, column_family_options_));
} }
~ColumnFamilyTest() { virtual ~ColumnFamilyTestBase() {
std::vector<ColumnFamilyDescriptor> column_families; std::vector<ColumnFamilyDescriptor> column_families;
for (auto h : handles_) { for (auto h : handles_) {
ColumnFamilyDescriptor cfdescriptor; ColumnFamilyDescriptor cfdescriptor;
@@ -81,6 +81,12 @@ class ColumnFamilyTest : public testing::Test {
delete env_; delete env_;
} }
BlockBasedTableOptions GetBlockBasedTableOptions() {
BlockBasedTableOptions options;
options.format_version = format_;
return options;
}
// Return the value to associate with the specified key // Return the value to associate with the specified key
Slice Value(int k, std::string* storage) { Slice Value(int k, std::string* storage) {
if (k == 0) { if (k == 0) {
@@ -513,9 +519,22 @@ class ColumnFamilyTest : public testing::Test {
DB* db_ = nullptr; DB* db_ = nullptr;
EnvCounter* env_; EnvCounter* env_;
Random rnd_; Random rnd_;
uint32_t format_;
}; };
TEST_F(ColumnFamilyTest, DontReuseColumnFamilyID) { 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) {
for (int iter = 0; iter < 3; ++iter) { for (int iter = 0; iter < 3; ++iter) {
Open(); Open();
CreateColumnFamilies({"one", "two", "three"}); CreateColumnFamilies({"one", "two", "three"});
@@ -534,7 +553,8 @@ TEST_F(ColumnFamilyTest, DontReuseColumnFamilyID) {
Reopen(); Reopen();
} }
CreateColumnFamilies({"three2"}); 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]); auto cfh3 = reinterpret_cast<ColumnFamilyHandleImpl*>(handles_[3]);
ASSERT_EQ(4U, cfh3->GetID()); ASSERT_EQ(4U, cfh3->GetID());
Close(); Close();
@@ -543,7 +563,7 @@ TEST_F(ColumnFamilyTest, DontReuseColumnFamilyID) {
} }
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
TEST_F(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) { TEST_P(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
Open(); Open();
rocksdb::SyncPoint::GetInstance()->LoadDependency( rocksdb::SyncPoint::GetInstance()->LoadDependency(
@@ -566,10 +586,13 @@ TEST_F(ColumnFamilyTest, CreateCFRaceWithGetAggProperty) {
} }
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
class FlushEmptyCFTestWithParam : public ColumnFamilyTest, class FlushEmptyCFTestWithParam
public testing::WithParamInterface<bool> { : public ColumnFamilyTestBase,
virtual public testing::WithParamInterface<std::tuple<uint32_t, bool>> {
public: public:
FlushEmptyCFTestWithParam() { allow_2pc_ = GetParam(); } FlushEmptyCFTestWithParam()
: ColumnFamilyTestBase(std::get<0>(GetParam())),
allow_2pc_(std::get<1>(GetParam())) {}
// Required if inheriting from testing::WithParamInterface<> // Required if inheriting from testing::WithParamInterface<>
static void SetUpTestCase() {} static void SetUpTestCase() {}
@@ -694,10 +717,16 @@ TEST_P(FlushEmptyCFTestWithParam, FlushEmptyCFTest2) {
db_options_.env = env_; db_options_.env = env_;
} }
INSTANTIATE_TEST_CASE_P(FlushEmptyCFTestWithParam, FlushEmptyCFTestWithParam, INSTANTIATE_TEST_CASE_P(
::testing::Bool()); 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)));
TEST_F(ColumnFamilyTest, AddDrop) { TEST_P(ColumnFamilyTest, AddDrop) {
Open(); Open();
CreateColumnFamilies({"one", "two", "three"}); CreateColumnFamilies({"one", "two", "three"});
ASSERT_EQ("NOT_FOUND", Get(1, "fodor")); ASSERT_EQ("NOT_FOUND", Get(1, "fodor"));
@@ -723,7 +752,7 @@ TEST_F(ColumnFamilyTest, AddDrop) {
std::vector<std::string>({"default", "four", "three"})); std::vector<std::string>({"default", "four", "three"}));
} }
TEST_F(ColumnFamilyTest, BulkAddDrop) { TEST_P(ColumnFamilyTest, BulkAddDrop) {
constexpr int kNumCF = 1000; constexpr int kNumCF = 1000;
ColumnFamilyOptions cf_options; ColumnFamilyOptions cf_options;
WriteOptions write_options; WriteOptions write_options;
@@ -761,7 +790,7 @@ TEST_F(ColumnFamilyTest, BulkAddDrop) {
ASSERT_TRUE(families == std::vector<std::string>({"default"})); ASSERT_TRUE(families == std::vector<std::string>({"default"}));
} }
TEST_F(ColumnFamilyTest, DropTest) { TEST_P(ColumnFamilyTest, DropTest) {
// first iteration - dont reopen DB before dropping // first iteration - dont reopen DB before dropping
// second iteration - reopen DB before dropping // second iteration - reopen DB before dropping
for (int iter = 0; iter < 2; ++iter) { for (int iter = 0; iter < 2; ++iter) {
@@ -785,7 +814,7 @@ TEST_F(ColumnFamilyTest, DropTest) {
} }
} }
TEST_F(ColumnFamilyTest, WriteBatchFailure) { TEST_P(ColumnFamilyTest, WriteBatchFailure) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two"}); CreateColumnFamiliesAndReopen({"one", "two"});
WriteBatch batch; WriteBatch batch;
@@ -803,7 +832,7 @@ TEST_F(ColumnFamilyTest, WriteBatchFailure) {
Close(); Close();
} }
TEST_F(ColumnFamilyTest, ReadWrite) { TEST_P(ColumnFamilyTest, ReadWrite) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two"}); CreateColumnFamiliesAndReopen({"one", "two"});
ASSERT_OK(Put(0, "foo", "v1")); ASSERT_OK(Put(0, "foo", "v1"));
@@ -827,7 +856,7 @@ TEST_F(ColumnFamilyTest, ReadWrite) {
Close(); Close();
} }
TEST_F(ColumnFamilyTest, IgnoreRecoveredLog) { TEST_P(ColumnFamilyTest, IgnoreRecoveredLog) {
std::string backup_logs = dbname_ + "/backup_logs"; std::string backup_logs = dbname_ + "/backup_logs";
// delete old files in backup_logs directory // delete old files in backup_logs directory
@@ -903,7 +932,7 @@ TEST_F(ColumnFamilyTest, IgnoreRecoveredLog) {
} }
#ifndef ROCKSDB_LITE // TEST functions used are not supported #ifndef ROCKSDB_LITE // TEST functions used are not supported
TEST_F(ColumnFamilyTest, FlushTest) { TEST_P(ColumnFamilyTest, FlushTest) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two"}); CreateColumnFamiliesAndReopen({"one", "two"});
ASSERT_OK(Put(0, "foo", "v1")); ASSERT_OK(Put(0, "foo", "v1"));
@@ -951,7 +980,7 @@ TEST_F(ColumnFamilyTest, FlushTest) {
} }
// Makes sure that obsolete log files get deleted // Makes sure that obsolete log files get deleted
TEST_F(ColumnFamilyTest, LogDeletionTest) { TEST_P(ColumnFamilyTest, LogDeletionTest) {
db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max(); db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max();
column_family_options_.arena_block_size = 4 * 1024; column_family_options_.arena_block_size = 4 * 1024;
column_family_options_.write_buffer_size = 128000; // 128KB column_family_options_.write_buffer_size = 128000; // 128KB
@@ -1019,7 +1048,7 @@ TEST_F(ColumnFamilyTest, LogDeletionTest) {
} }
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
TEST_F(ColumnFamilyTest, CrashAfterFlush) { TEST_P(ColumnFamilyTest, CrashAfterFlush) {
std::unique_ptr<FaultInjectionTestEnv> fault_env( std::unique_ptr<FaultInjectionTestEnv> fault_env(
new FaultInjectionTestEnv(env_)); new FaultInjectionTestEnv(env_));
db_options_.env = fault_env.get(); db_options_.env = fault_env.get();
@@ -1051,7 +1080,7 @@ TEST_F(ColumnFamilyTest, CrashAfterFlush) {
db_options_.env = env_; db_options_.env = env_;
} }
TEST_F(ColumnFamilyTest, OpenNonexistentColumnFamily) { TEST_P(ColumnFamilyTest, OpenNonexistentColumnFamily) {
ASSERT_OK(TryOpen({"default"})); ASSERT_OK(TryOpen({"default"}));
Close(); Close();
ASSERT_TRUE(TryOpen({"default", "dne"}).IsInvalidArgument()); ASSERT_TRUE(TryOpen({"default", "dne"}).IsInvalidArgument());
@@ -1059,7 +1088,7 @@ TEST_F(ColumnFamilyTest, OpenNonexistentColumnFamily) {
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported #ifndef ROCKSDB_LITE // WaitForFlush() is not supported
// Makes sure that obsolete log files get deleted // Makes sure that obsolete log files get deleted
TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) { TEST_P(ColumnFamilyTest, DifferentWriteBufferSizes) {
// disable flushing stale column families // disable flushing stale column families
db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max(); db_options_.max_total_wal_size = std::numeric_limits<uint64_t>::max();
Open(); Open();
@@ -1165,7 +1194,7 @@ TEST_F(ColumnFamilyTest, DifferentWriteBufferSizes) {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // Cuckoo is not supported in lite #ifndef ROCKSDB_LITE // Cuckoo is not supported in lite
TEST_F(ColumnFamilyTest, MemtableNotSupportSnapshot) { TEST_P(ColumnFamilyTest, MemtableNotSupportSnapshot) {
db_options_.allow_concurrent_memtable_write = false; db_options_.allow_concurrent_memtable_write = false;
Open(); Open();
auto* s1 = dbfull()->GetSnapshot(); auto* s1 = dbfull()->GetSnapshot();
@@ -1203,7 +1232,7 @@ static TestComparator third_comparator;
static TestComparator fourth_comparator; static TestComparator fourth_comparator;
// Test that we can retrieve the comparator from a created CF // Test that we can retrieve the comparator from a created CF
TEST_F(ColumnFamilyTest, GetComparator) { TEST_P(ColumnFamilyTest, GetComparator) {
Open(); Open();
// Add a column family with no comparator specified // Add a column family with no comparator specified
CreateColumnFamilies({"first"}); CreateColumnFamilies({"first"});
@@ -1222,7 +1251,7 @@ TEST_F(ColumnFamilyTest, GetComparator) {
Close(); Close();
} }
TEST_F(ColumnFamilyTest, DifferentMergeOperators) { TEST_P(ColumnFamilyTest, DifferentMergeOperators) {
Open(); Open();
CreateColumnFamilies({"first", "second"}); CreateColumnFamilies({"first", "second"});
ColumnFamilyOptions default_cf, first, second; ColumnFamilyOptions default_cf, first, second;
@@ -1253,7 +1282,7 @@ TEST_F(ColumnFamilyTest, DifferentMergeOperators) {
} }
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported #ifndef ROCKSDB_LITE // WaitForFlush() is not supported
TEST_F(ColumnFamilyTest, DifferentCompactionStyles) { TEST_P(ColumnFamilyTest, DifferentCompactionStyles) {
Open(); Open();
CreateColumnFamilies({"one", "two"}); CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two; ColumnFamilyOptions default_cf, one, two;
@@ -1265,7 +1294,7 @@ TEST_F(ColumnFamilyTest, DifferentCompactionStyles) {
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = static_cast<uint64_t>(1) << 60; default_cf.max_compaction_bytes = static_cast<uint64_t>(1) << 60;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1325,7 +1354,7 @@ TEST_F(ColumnFamilyTest, DifferentCompactionStyles) {
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
// Sync points not supported in RocksDB Lite // Sync points not supported in RocksDB Lite
TEST_F(ColumnFamilyTest, MultipleManualCompactions) { TEST_P(ColumnFamilyTest, MultipleManualCompactions) {
Open(); Open();
CreateColumnFamilies({"one", "two"}); CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two; ColumnFamilyOptions default_cf, one, two;
@@ -1337,7 +1366,7 @@ TEST_F(ColumnFamilyTest, MultipleManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1419,10 +1448,12 @@ TEST_F(ColumnFamilyTest, MultipleManualCompactions) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
Close(); Close();
} }
TEST_F(ColumnFamilyTest, AutomaticAndManualCompactions) { TEST_P(ColumnFamilyTest, AutomaticAndManualCompactions) {
Open(); Open();
CreateColumnFamilies({"one", "two"}); CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two; ColumnFamilyOptions default_cf, one, two;
@@ -1434,7 +1465,8 @@ TEST_F(ColumnFamilyTest, AutomaticAndManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1513,9 +1545,11 @@ TEST_F(ColumnFamilyTest, AutomaticAndManualCompactions) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
TEST_F(ColumnFamilyTest, ManualAndAutomaticCompactions) { TEST_P(ColumnFamilyTest, ManualAndAutomaticCompactions) {
Open(); Open();
CreateColumnFamilies({"one", "two"}); CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two; ColumnFamilyOptions default_cf, one, two;
@@ -1527,7 +1561,8 @@ TEST_F(ColumnFamilyTest, ManualAndAutomaticCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1609,9 +1644,11 @@ TEST_F(ColumnFamilyTest, ManualAndAutomaticCompactions) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
TEST_F(ColumnFamilyTest, SameCFManualManualCompactions) { TEST_P(ColumnFamilyTest, SameCFManualManualCompactions) {
Open(); Open();
CreateColumnFamilies({"one"}); CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one; ColumnFamilyOptions default_cf, one;
@@ -1623,7 +1660,8 @@ TEST_F(ColumnFamilyTest, SameCFManualManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1708,9 +1746,11 @@ TEST_F(ColumnFamilyTest, SameCFManualManualCompactions) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactions) { TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
Open(); Open();
CreateColumnFamilies({"one"}); CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one; ColumnFamilyOptions default_cf, one;
@@ -1722,7 +1762,8 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1798,9 +1839,11 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactions) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) { TEST_P(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
Open(); Open();
CreateColumnFamilies({"one"}); CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one; ColumnFamilyOptions default_cf, one;
@@ -1812,7 +1855,8 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1888,6 +1932,8 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
// In this test, we generate enough files to trigger automatic compactions. // In this test, we generate enough files to trigger automatic compactions.
@@ -1896,7 +1942,7 @@ TEST_F(ColumnFamilyTest, SameCFManualAutomaticCompactionsLevel) {
// This will wait because the automatic compaction has files it needs. // This will wait because the automatic compaction has files it needs.
// Once the conflict is hit, the automatic compaction starts and ends // Once the conflict is hit, the automatic compaction starts and ends
// Then the manual will run and end. // Then the manual will run and end.
TEST_F(ColumnFamilyTest, SameCFAutomaticManualCompactions) { TEST_P(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
Open(); Open();
CreateColumnFamilies({"one"}); CreateColumnFamilies({"one"});
ColumnFamilyOptions default_cf, one; ColumnFamilyOptions default_cf, one;
@@ -1908,7 +1954,8 @@ TEST_F(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
default_cf.write_buffer_size = 64 << 10; // 64KB default_cf.write_buffer_size = 64 << 10; // 64KB
default_cf.target_file_size_base = 30 << 10; default_cf.target_file_size_base = 30 << 10;
default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100; default_cf.max_compaction_bytes = default_cf.target_file_size_base * 1100;
BlockBasedTableOptions table_options; BlockBasedTableOptions table_options = GetBlockBasedTableOptions();
;
table_options.no_block_cache = true; table_options.no_block_cache = true;
default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options)); default_cf.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1977,6 +2024,8 @@ TEST_F(ColumnFamilyTest, SameCFAutomaticManualCompactions) {
ASSERT_NE("NOT_FOUND", Get(1, *key_iter)); ASSERT_NE("NOT_FOUND", Get(1, *key_iter));
key_iter++; key_iter++;
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
@@ -1993,7 +2042,7 @@ std::string IterStatus(Iterator* iter) {
} }
} // anonymous namespace } // anonymous namespace
TEST_F(ColumnFamilyTest, NewIteratorsTest) { TEST_P(ColumnFamilyTest, NewIteratorsTest) {
// iter == 0 -- no tailing // iter == 0 -- no tailing
// iter == 2 -- tailing // iter == 2 -- tailing
for (int iter = 0; iter < 2; ++iter) { for (int iter = 0; iter < 2; ++iter) {
@@ -2040,7 +2089,7 @@ TEST_F(ColumnFamilyTest, NewIteratorsTest) {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // ReadOnlyDB is not supported #ifndef ROCKSDB_LITE // ReadOnlyDB is not supported
TEST_F(ColumnFamilyTest, ReadOnlyDBTest) { TEST_P(ColumnFamilyTest, ReadOnlyDBTest) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two", "three", "four"}); CreateColumnFamiliesAndReopen({"one", "two", "three", "four"});
ASSERT_OK(Put(0, "a", "b")); ASSERT_OK(Put(0, "a", "b"));
@@ -2092,7 +2141,7 @@ TEST_F(ColumnFamilyTest, ReadOnlyDBTest) {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported in lite #ifndef ROCKSDB_LITE // WaitForFlush() is not supported in lite
TEST_F(ColumnFamilyTest, DontRollEmptyLogs) { TEST_P(ColumnFamilyTest, DontRollEmptyLogs) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two", "three", "four"}); CreateColumnFamiliesAndReopen({"one", "two", "three", "four"});
@@ -2116,7 +2165,7 @@ TEST_F(ColumnFamilyTest, DontRollEmptyLogs) {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // WaitForCompaction() is not supported in lite #ifndef ROCKSDB_LITE // WaitForCompaction() is not supported in lite
TEST_F(ColumnFamilyTest, FlushStaleColumnFamilies) { TEST_P(ColumnFamilyTest, FlushStaleColumnFamilies) {
Open(); Open();
CreateColumnFamilies({"one", "two"}); CreateColumnFamilies({"one", "two"});
ColumnFamilyOptions default_cf, one, two; ColumnFamilyOptions default_cf, one, two;
@@ -2151,7 +2200,7 @@ TEST_F(ColumnFamilyTest, FlushStaleColumnFamilies) {
} }
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
TEST_F(ColumnFamilyTest, CreateMissingColumnFamilies) { TEST_P(ColumnFamilyTest, CreateMissingColumnFamilies) {
Status s = TryOpen({"one", "two"}); Status s = TryOpen({"one", "two"});
ASSERT_TRUE(!s.ok()); ASSERT_TRUE(!s.ok());
db_options_.create_missing_column_families = true; db_options_.create_missing_column_families = true;
@@ -2160,7 +2209,7 @@ TEST_F(ColumnFamilyTest, CreateMissingColumnFamilies) {
Close(); Close();
} }
TEST_F(ColumnFamilyTest, SanitizeOptions) { TEST_P(ColumnFamilyTest, SanitizeOptions) {
DBOptions db_options; DBOptions db_options;
for (int s = kCompactionStyleLevel; s <= kCompactionStyleUniversal; ++s) { for (int s = kCompactionStyleLevel; s <= kCompactionStyleUniversal; ++s) {
for (int l = 0; l <= 2; l++) { for (int l = 0; l <= 2; l++) {
@@ -2209,7 +2258,7 @@ TEST_F(ColumnFamilyTest, SanitizeOptions) {
} }
} }
TEST_F(ColumnFamilyTest, ReadDroppedColumnFamily) { TEST_P(ColumnFamilyTest, ReadDroppedColumnFamily) {
// iter 0 -- drop CF, don't reopen // iter 0 -- drop CF, don't reopen
// iter 1 -- delete CF, reopen // iter 1 -- delete CF, reopen
for (int iter = 0; iter < 2; ++iter) { for (int iter = 0; iter < 2; ++iter) {
@@ -2281,7 +2330,7 @@ TEST_F(ColumnFamilyTest, ReadDroppedColumnFamily) {
} }
} }
TEST_F(ColumnFamilyTest, FlushAndDropRaceCondition) { TEST_P(ColumnFamilyTest, FlushAndDropRaceCondition) {
db_options_.create_missing_column_families = true; db_options_.create_missing_column_families = true;
Open({"default", "one"}); Open({"default", "one"});
ColumnFamilyOptions options; ColumnFamilyOptions options;
@@ -2347,12 +2396,13 @@ TEST_F(ColumnFamilyTest, FlushAndDropRaceCondition) {
// skipped as persisting options is not supported in ROCKSDB_LITE // skipped as persisting options is not supported in ROCKSDB_LITE
namespace { namespace {
std::atomic<int> test_stage(0); std::atomic<int> test_stage(0);
std::atomic<bool> ordered_by_writethread(false);
const int kMainThreadStartPersistingOptionsFile = 1; const int kMainThreadStartPersistingOptionsFile = 1;
const int kChildThreadFinishDroppingColumnFamily = 2; const int kChildThreadFinishDroppingColumnFamily = 2;
const int kChildThreadWaitingMainThreadPersistOptions = 3;
void DropSingleColumnFamily(ColumnFamilyTest* cf_test, int cf_id, void DropSingleColumnFamily(ColumnFamilyTest* cf_test, int cf_id,
std::vector<Comparator*>* comparators) { std::vector<Comparator*>* comparators) {
while (test_stage < kMainThreadStartPersistingOptionsFile) { while (test_stage < kMainThreadStartPersistingOptionsFile &&
!ordered_by_writethread) {
Env::Default()->SleepForMicroseconds(100); Env::Default()->SleepForMicroseconds(100);
} }
cf_test->DropColumnFamilies({cf_id}); cf_test->DropColumnFamilies({cf_id});
@@ -2364,7 +2414,7 @@ void DropSingleColumnFamily(ColumnFamilyTest* cf_test, int cf_id,
} }
} // namespace } // namespace
TEST_F(ColumnFamilyTest, CreateAndDropRace) { TEST_P(ColumnFamilyTest, CreateAndDropRace) {
const int kCfCount = 5; const int kCfCount = 5;
std::vector<ColumnFamilyOptions> cf_opts; std::vector<ColumnFamilyOptions> cf_opts;
std::vector<Comparator*> comparators; std::vector<Comparator*> comparators;
@@ -2385,7 +2435,8 @@ TEST_F(ColumnFamilyTest, CreateAndDropRace) {
// will be blocked until some other thread update the test_stage. // will be blocked until some other thread update the test_stage.
if (main_thread_id == current_thread_id) { if (main_thread_id == current_thread_id) {
test_stage = kMainThreadStartPersistingOptionsFile; test_stage = kMainThreadStartPersistingOptionsFile;
while (test_stage < kChildThreadFinishDroppingColumnFamily) { while (test_stage < kChildThreadFinishDroppingColumnFamily &&
!ordered_by_writethread) {
Env::Default()->SleepForMicroseconds(100); Env::Default()->SleepForMicroseconds(100);
} }
} }
@@ -2396,11 +2447,7 @@ TEST_F(ColumnFamilyTest, CreateAndDropRace) {
// This means a thread doing DropColumnFamily() is waiting for // This means a thread doing DropColumnFamily() is waiting for
// other thread to finish persisting options. // other thread to finish persisting options.
// In such case, we update the test_stage to unblock the main thread. // In such case, we update the test_stage to unblock the main thread.
test_stage = kChildThreadWaitingMainThreadPersistOptions; ordered_by_writethread = true;
// 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 // Create a database with four column families
@@ -2411,7 +2458,8 @@ TEST_F(ColumnFamilyTest, CreateAndDropRace) {
// Start a thread that will drop the first column family // Start a thread that will drop the first column family
// and its comparator // 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}); DropColumnFamilies({2});
@@ -2423,10 +2471,13 @@ TEST_F(ColumnFamilyTest, CreateAndDropRace) {
delete comparator; delete comparator;
} }
} }
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
TEST_F(ColumnFamilyTest, WriteStallSingleColumnFamily) { TEST_P(ColumnFamilyTest, WriteStallSingleColumnFamily) {
const uint64_t kBaseRate = 800000u; const uint64_t kBaseRate = 800000u;
db_options_.delayed_write_rate = kBaseRate; db_options_.delayed_write_rate = kBaseRate;
db_options_.max_background_compactions = 6; db_options_.max_background_compactions = 6;
@@ -2608,7 +2659,7 @@ TEST_F(ColumnFamilyTest, WriteStallSingleColumnFamily) {
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate()); ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
} }
TEST_F(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) { TEST_P(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) {
db_options_.max_background_compactions = 6; db_options_.max_background_compactions = 6;
Open({"default"}); Open({"default"});
ColumnFamilyData* cfd = ColumnFamilyData* cfd =
@@ -2672,7 +2723,7 @@ TEST_F(ColumnFamilyTest, CompactionSpeedupSingleColumnFamily) {
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed()); ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
} }
TEST_F(ColumnFamilyTest, WriteStallTwoColumnFamilies) { TEST_P(ColumnFamilyTest, WriteStallTwoColumnFamilies) {
const uint64_t kBaseRate = 810000u; const uint64_t kBaseRate = 810000u;
db_options_.delayed_write_rate = kBaseRate; db_options_.delayed_write_rate = kBaseRate;
Open(); Open();
@@ -2747,7 +2798,7 @@ TEST_F(ColumnFamilyTest, WriteStallTwoColumnFamilies) {
ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate()); ASSERT_EQ(kBaseRate / 1.25, GetDbDelayedWriteRate());
} }
TEST_F(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) { TEST_P(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
db_options_.max_background_compactions = 6; db_options_.max_background_compactions = 6;
column_family_options_.soft_pending_compaction_bytes_limit = 200; column_family_options_.soft_pending_compaction_bytes_limit = 200;
column_family_options_.hard_pending_compaction_bytes_limit = 2000; column_family_options_.hard_pending_compaction_bytes_limit = 2000;
@@ -2812,7 +2863,7 @@ TEST_F(ColumnFamilyTest, CompactionSpeedupTwoColumnFamilies) {
ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed()); ASSERT_EQ(1, dbfull()->TEST_BGCompactionsAllowed());
} }
TEST_F(ColumnFamilyTest, CreateAndDestoryOptions) { TEST_P(ColumnFamilyTest, CreateAndDestoryOptions) {
std::unique_ptr<ColumnFamilyOptions> cfo(new ColumnFamilyOptions()); std::unique_ptr<ColumnFamilyOptions> cfo(new ColumnFamilyOptions());
ColumnFamilyHandle* cfh; ColumnFamilyHandle* cfh;
Open(); Open();
@@ -2824,8 +2875,29 @@ TEST_F(ColumnFamilyTest, CreateAndDestoryOptions) {
ASSERT_OK(db_->DestroyColumnFamilyHandle(cfh)); 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 #ifndef ROCKSDB_LITE
TEST_F(ColumnFamilyTest, FlushCloseWALFiles) { 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) {
SpecialEnv env(Env::Default()); SpecialEnv env(Env::Default());
db_options_.env = &env; db_options_.env = &env;
db_options_.max_background_flushes = 1; db_options_.max_background_flushes = 1;
@@ -2867,7 +2939,7 @@ TEST_F(ColumnFamilyTest, FlushCloseWALFiles) {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // WaitForFlush() is not supported #ifndef ROCKSDB_LITE // WaitForFlush() is not supported
TEST_F(ColumnFamilyTest, IteratorCloseWALFile1) { TEST_P(ColumnFamilyTest, IteratorCloseWALFile1) {
SpecialEnv env(Env::Default()); SpecialEnv env(Env::Default());
db_options_.env = &env; db_options_.env = &env;
db_options_.max_background_flushes = 1; db_options_.max_background_flushes = 1;
@@ -2912,7 +2984,7 @@ TEST_F(ColumnFamilyTest, IteratorCloseWALFile1) {
Close(); Close();
} }
TEST_F(ColumnFamilyTest, IteratorCloseWALFile2) { TEST_P(ColumnFamilyTest, IteratorCloseWALFile2) {
SpecialEnv env(Env::Default()); SpecialEnv env(Env::Default());
// Allow both of flush and purge job to schedule. // Allow both of flush and purge job to schedule.
env.SetBackgroundThreads(2, Env::HIGH); env.SetBackgroundThreads(2, Env::HIGH);
@@ -2969,7 +3041,7 @@ TEST_F(ColumnFamilyTest, IteratorCloseWALFile2) {
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
#ifndef ROCKSDB_LITE // TEST functions are not supported in lite #ifndef ROCKSDB_LITE // TEST functions are not supported in lite
TEST_F(ColumnFamilyTest, ForwardIteratorCloseWALFile) { TEST_P(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
SpecialEnv env(Env::Default()); SpecialEnv env(Env::Default());
// Allow both of flush and purge job to schedule. // Allow both of flush and purge job to schedule.
env.SetBackgroundThreads(2, Env::HIGH); env.SetBackgroundThreads(2, Env::HIGH);
@@ -3046,7 +3118,7 @@ TEST_F(ColumnFamilyTest, ForwardIteratorCloseWALFile) {
// Disable on windows because SyncWAL requires env->IsSyncThreadSafe() // Disable on windows because SyncWAL requires env->IsSyncThreadSafe()
// to return true which is not so in unbuffered mode. // to return true which is not so in unbuffered mode.
#ifndef OS_WIN #ifndef OS_WIN
TEST_F(ColumnFamilyTest, LogSyncConflictFlush) { TEST_P(ColumnFamilyTest, LogSyncConflictFlush) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two"}); CreateColumnFamiliesAndReopen({"one", "two"});
@@ -3081,7 +3153,7 @@ TEST_F(ColumnFamilyTest, LogSyncConflictFlush) {
// test is being used to ensure a roll of wal files. // test is being used to ensure a roll of wal files.
// Basic idea is to test that WAL truncation is being detected and not // Basic idea is to test that WAL truncation is being detected and not
// ignored // ignored
TEST_F(ColumnFamilyTest, DISABLED_LogTruncationTest) { TEST_P(ColumnFamilyTest, DISABLED_LogTruncationTest) {
Open(); Open();
CreateColumnFamiliesAndReopen({"one", "two"}); CreateColumnFamiliesAndReopen({"one", "two"});
@@ -3151,7 +3223,7 @@ TEST_F(ColumnFamilyTest, DISABLED_LogTruncationTest) {
env_->DeleteDir(backup_logs); env_->DeleteDir(backup_logs);
} }
TEST_F(ColumnFamilyTest, DefaultCfPathsTest) { TEST_P(ColumnFamilyTest, DefaultCfPathsTest) {
Open(); Open();
// Leave cf_paths for one column families to be empty. // Leave cf_paths for one column families to be empty.
// Files should be generated according to db_paths for that // Files should be generated according to db_paths for that
@@ -3178,7 +3250,7 @@ TEST_F(ColumnFamilyTest, DefaultCfPathsTest) {
ASSERT_EQ(1, GetSstFileCount(dbname_)); ASSERT_EQ(1, GetSstFileCount(dbname_));
} }
TEST_F(ColumnFamilyTest, MultipleCFPathsTest) { TEST_P(ColumnFamilyTest, MultipleCFPathsTest) {
Open(); Open();
// Configure Column family specific paths. // Configure Column family specific paths.
ColumnFamilyOptions cf_opt1, cf_opt2; ColumnFamilyOptions cf_opt1, cf_opt2;
+3 -3
View File
@@ -49,8 +49,8 @@ Status CompactedDBImpl::Get(const ReadOptions& options, ColumnFamilyHandle*,
GetContext::kNotFound, key, value, nullptr, nullptr, GetContext::kNotFound, key, value, nullptr, nullptr,
nullptr, nullptr); nullptr, nullptr);
LookupKey lkey(key, kMaxSequenceNumber); LookupKey lkey(key, kMaxSequenceNumber);
files_.files[FindFile(key)].fd.table_reader->Get( files_.files[FindFile(key)].fd.table_reader->Get(options, lkey.internal_key(),
options, lkey.internal_key(), &get_context); &get_context, nullptr);
if (get_context.State() == GetContext::kFound) { if (get_context.State() == GetContext::kFound) {
return Status::OK(); return Status::OK();
} }
@@ -82,7 +82,7 @@ std::vector<Status> CompactedDBImpl::MultiGet(const ReadOptions& options,
GetContext::kNotFound, keys[idx], &pinnable_val, GetContext::kNotFound, keys[idx], &pinnable_val,
nullptr, nullptr, nullptr, nullptr); nullptr, nullptr, nullptr, nullptr);
LookupKey lkey(keys[idx], kMaxSequenceNumber); LookupKey lkey(keys[idx], kMaxSequenceNumber);
r->Get(options, lkey.internal_key(), &get_context); r->Get(options, lkey.internal_key(), &get_context, nullptr);
value.assign(pinnable_val.data(), pinnable_val.size()); value.assign(pinnable_val.data(), pinnable_val.size());
if (get_context.State() == GetContext::kFound) { if (get_context.State() == GetContext::kFound) {
statuses[idx] = Status::OK(); statuses[idx] = Status::OK();
+7 -4
View File
@@ -1183,7 +1183,9 @@ Status CompactionJob::FinishCompactionOutputFile(
// to cache it here for further user reads // to cache it here for further user reads
InternalIterator* iter = cfd->table_cache()->NewIterator( InternalIterator* iter = cfd->table_cache()->NewIterator(
ReadOptions(), env_options_, cfd->internal_comparator(), meta->fd, ReadOptions(), env_options_, cfd->internal_comparator(), meta->fd,
nullptr /* range_del_agg */, nullptr, nullptr /* range_del_agg */,
sub_compact->compaction->mutable_cf_options()->prefix_extractor.get(),
nullptr,
cfd->internal_stats()->GetFileReadHist( cfd->internal_stats()->GetFileReadHist(
compact_->compaction->output_level()), compact_->compaction->output_level()),
false, nullptr /* arena */, false /* skip_filters */, false, nullptr /* arena */, false /* skip_filters */,
@@ -1386,9 +1388,10 @@ Status CompactionJob::OpenCompactionOutputFile(
} }
sub_compact->builder.reset(NewTableBuilder( sub_compact->builder.reset(NewTableBuilder(
*cfd->ioptions(), cfd->internal_comparator(), *cfd->ioptions(), *(sub_compact->compaction->mutable_cf_options()),
cfd->int_tbl_prop_collector_factories(), cfd->GetID(), cfd->GetName(), cfd->internal_comparator(), cfd->int_tbl_prop_collector_factories(),
sub_compact->outfile.get(), sub_compact->compaction->output_compression(), cfd->GetID(), cfd->GetName(), sub_compact->outfile.get(),
sub_compact->compaction->output_compression(),
cfd->ioptions()->compression_opts, cfd->ioptions()->compression_opts,
sub_compact->compaction->output_level(), &sub_compact->compression_dict, sub_compact->compaction->output_level(), &sub_compact->compression_dict,
skip_filters, output_file_creation_time)); skip_filters, output_file_creation_time));
+166 -10
View File
@@ -2,6 +2,7 @@
// This source code is licensed under both the GPLv2 (found in the // This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License // COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory). // (found in the LICENSE.Apache file in the root directory).
#include <array>
#include <map> #include <map>
#include <string> #include <string>
@@ -250,18 +251,25 @@ class TwoStrComparator : public Comparator {
}; };
} // namespace } // namespace
class ComparatorDBTest : public testing::Test { class ComparatorDBTest
: public testing::Test,
virtual public ::testing::WithParamInterface<uint32_t> {
private: private:
std::string dbname_; std::string dbname_;
Env* env_; Env* env_;
DB* db_; DB* db_;
Options last_options_; Options last_options_;
std::unique_ptr<const Comparator> comparator_guard; std::unique_ptr<const Comparator> comparator_guard;
uint32_t format_;
public: public:
ComparatorDBTest() : env_(Env::Default()), db_(nullptr) { ComparatorDBTest() : env_(Env::Default()), db_(nullptr) {
comparator = BytewiseComparator(); comparator = BytewiseComparator();
dbname_ = test::TmpDir() + "/comparator_db_test"; 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_)); EXPECT_OK(DestroyDB(dbname_, last_options_));
} }
@@ -273,8 +281,12 @@ class ComparatorDBTest : public testing::Test {
DB* GetDB() { return db_; } DB* GetDB() { return db_; }
void SetOwnedComparator(const Comparator* cmp) { void SetOwnedComparator(const Comparator* cmp, bool owner = true) {
comparator_guard.reset(cmp); if (owner) {
comparator_guard.reset(cmp);
} else {
comparator_guard.reset();
}
comparator = cmp; comparator = cmp;
last_options_.comparator = cmp; last_options_.comparator = cmp;
} }
@@ -303,7 +315,12 @@ class ComparatorDBTest : public testing::Test {
} }
}; };
TEST_F(ComparatorDBTest, Bytewise) { INSTANTIATE_TEST_CASE_P(FormatDef, ComparatorDBTest,
testing::Values(test::kDefaultFormatVersion));
INSTANTIATE_TEST_CASE_P(FormatLatest, ComparatorDBTest,
testing::Values(test::kLatestFormatVersion));
TEST_P(ComparatorDBTest, Bytewise) {
for (int rand_seed = 301; rand_seed < 306; rand_seed++) { for (int rand_seed = 301; rand_seed < 306; rand_seed++) {
DestroyAndReopen(); DestroyAndReopen();
Random rnd(rand_seed); Random rnd(rand_seed);
@@ -313,7 +330,7 @@ TEST_F(ComparatorDBTest, Bytewise) {
} }
} }
TEST_F(ComparatorDBTest, SimpleSuffixReverseComparator) { TEST_P(ComparatorDBTest, SimpleSuffixReverseComparator) {
SetOwnedComparator(new test::SimpleSuffixReverseComparator()); SetOwnedComparator(new test::SimpleSuffixReverseComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) { for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -339,8 +356,8 @@ TEST_F(ComparatorDBTest, SimpleSuffixReverseComparator) {
} }
} }
TEST_F(ComparatorDBTest, Uint64Comparator) { TEST_P(ComparatorDBTest, Uint64Comparator) {
SetOwnedComparator(test::Uint64Comparator()); SetOwnedComparator(test::Uint64Comparator(), false /* owner */);
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) { for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
Options* opt = GetOptions(); Options* opt = GetOptions();
@@ -363,7 +380,7 @@ TEST_F(ComparatorDBTest, Uint64Comparator) {
} }
} }
TEST_F(ComparatorDBTest, DoubleComparator) { TEST_P(ComparatorDBTest, DoubleComparator) {
SetOwnedComparator(new DoubleComparator()); SetOwnedComparator(new DoubleComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) { for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -388,7 +405,7 @@ TEST_F(ComparatorDBTest, DoubleComparator) {
} }
} }
TEST_F(ComparatorDBTest, HashComparator) { TEST_P(ComparatorDBTest, HashComparator) {
SetOwnedComparator(new HashComparator()); SetOwnedComparator(new HashComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) { for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -407,7 +424,7 @@ TEST_F(ComparatorDBTest, HashComparator) {
} }
} }
TEST_F(ComparatorDBTest, TwoStrComparator) { TEST_P(ComparatorDBTest, TwoStrComparator) {
SetOwnedComparator(new TwoStrComparator()); SetOwnedComparator(new TwoStrComparator());
for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) { for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
@@ -433,6 +450,145 @@ TEST_F(ComparatorDBTest, TwoStrComparator) {
} }
} }
TEST_P(ComparatorDBTest, FindShortestSeparator) {
std::string s1 = "abc1xyz";
std::string s2 = "abc3xy";
BytewiseComparator()->FindShortestSeparator(&s1, s2);
ASSERT_EQ("abc2", s1);
s1 = "abc5xyztt";
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
ASSERT_EQ("abc5", s1);
s1 = "abc3";
s2 = "abc2xy";
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
ASSERT_EQ("abc3", s1);
s1 = "abc3xyz";
s2 = "abc2xy";
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
ASSERT_EQ("abc3", s1);
s1 = "abc3xyz";
s2 = "abc2";
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
ASSERT_EQ("abc3", s1);
std::string old_s1 = s1 = "abc2xy";
s2 = "abc2";
ReverseBytewiseComparator()->FindShortestSeparator(&s1, s2);
ASSERT_TRUE(old_s1 >= s1);
ASSERT_TRUE(s1 > s2);
}
TEST_P(ComparatorDBTest, SeparatorSuccessorRandomizeTest) {
// Char list for boundary cases.
std::array<unsigned char, 6> char_list{{0, 1, 2, 253, 254, 255}};
Random rnd(301);
for (int attempts = 0; attempts < 1000; attempts++) {
uint32_t size1 = rnd.Skewed(4);
uint32_t size2;
if (rnd.OneIn(2)) {
// size2 to be random size
size2 = rnd.Skewed(4);
} else {
// size1 is within [-2, +2] of size1
int diff = static_cast<int>(rnd.Uniform(5)) - 2;
int tmp_size2 = static_cast<int>(size1) + diff;
if (tmp_size2 < 0) {
tmp_size2 = 0;
}
size2 = static_cast<uint32_t>(tmp_size2);
}
std::string s1;
std::string s2;
for (uint32_t i = 0; i < size1; i++) {
if (rnd.OneIn(2)) {
// Use random byte
s1 += static_cast<char>(rnd.Uniform(256));
} else {
// Use one byte in char_list
char c = static_cast<char>(char_list[rnd.Uniform(sizeof(char_list))]);
s1 += c;
}
}
// First set s2 to be the same as s1, and then modify s2.
s2 = s1;
s2.resize(size2);
// We start from the back of the string
if (size2 > 0) {
uint32_t pos = size2 - 1;
do {
if (pos >= size1 || rnd.OneIn(4)) {
// For 1/4 chance, use random byte
s2[pos] = static_cast<char>(rnd.Uniform(256));
} else if (rnd.OneIn(4)) {
// In 1/4 chance, stop here.
break;
} else {
// Create a char within [-2, +2] of the matching char of s1.
int diff = static_cast<int>(rnd.Uniform(5)) - 2;
// char may be signed or unsigned based on platform.
int s1_char = static_cast<int>(static_cast<unsigned char>(s1[pos]));
int s2_char = s1_char + diff;
if (s2_char < 0) {
s2_char = 0;
}
if (s2_char > 255) {
s2_char = 255;
}
s2[pos] = static_cast<char>(s2_char);
}
} while (pos-- != 0);
}
// Test separators
for (int rev = 0; rev < 2; rev++) {
if (rev == 1) {
// switch s1 and s2
std::string t = s1;
s1 = s2;
s2 = t;
}
std::string separator = s1;
BytewiseComparator()->FindShortestSeparator(&separator, s2);
std::string rev_separator = s1;
ReverseBytewiseComparator()->FindShortestSeparator(&rev_separator, s2);
if (s1 == s2) {
ASSERT_EQ(s1, separator);
ASSERT_EQ(s2, rev_separator);
} else if (s1 < s2) {
ASSERT_TRUE(s1 <= separator);
ASSERT_TRUE(s2 > separator);
ASSERT_LE(separator.size(), std::max(s1.size(), s2.size()));
ASSERT_EQ(s1, rev_separator);
} else {
ASSERT_TRUE(s1 >= rev_separator);
ASSERT_TRUE(s2 < rev_separator);
ASSERT_LE(rev_separator.size(), std::max(s1.size(), s2.size()));
ASSERT_EQ(s1, separator);
}
}
// Test successors
std::string succ = s1;
BytewiseComparator()->FindShortSuccessor(&succ);
ASSERT_TRUE(succ >= s1);
succ = s1;
ReverseBytewiseComparator()->FindShortSuccessor(&succ);
ASSERT_TRUE(succ <= s1);
}
}
} // namespace rocksdb } // namespace rocksdb
int main(int argc, char** argv) { int main(int argc, char** argv) {
+3 -2
View File
@@ -50,8 +50,9 @@ Status VerifySstFileChecksum(const Options& options,
std::unique_ptr<RandomAccessFileReader> file_reader( std::unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(file), file_path)); new RandomAccessFileReader(std::move(file), file_path));
s = ioptions.table_factory->NewTableReader( s = ioptions.table_factory->NewTableReader(
TableReaderOptions(ioptions, env_options, internal_comparator, TableReaderOptions(ioptions, options.prefix_extractor.get(), env_options,
false /* skip_filters */, -1 /* level */), internal_comparator, false /* skip_filters */,
-1 /* level */),
std::move(file_reader), file_size, &table_reader, std::move(file_reader), file_size, &table_reader,
false /* prefetch_index_and_filter_in_cache */); false /* prefetch_index_and_filter_in_cache */);
if (!s.ok()) { if (!s.ok()) {
+12 -10
View File
@@ -969,7 +969,7 @@ InternalIterator* DBImpl::NewInternalIterator(
MergeIteratorBuilder merge_iter_builder( MergeIteratorBuilder merge_iter_builder(
&cfd->internal_comparator(), arena, &cfd->internal_comparator(), arena,
!read_options.total_order_seek && !read_options.total_order_seek &&
cfd->ioptions()->prefix_extractor != nullptr); super_version->mutable_cf_options.prefix_extractor != nullptr);
// Collect iterator for mutable mem // Collect iterator for mutable mem
merge_iter_builder.AddIterator( merge_iter_builder.AddIterator(
super_version->mem->NewIterator(read_options, arena)); super_version->mem->NewIterator(read_options, arena));
@@ -1568,11 +1568,11 @@ Iterator* DBImpl::NewIterator(const ReadOptions& read_options,
#else #else
SuperVersion* sv = cfd->GetReferencedSuperVersion(&mutex_); SuperVersion* sv = cfd->GetReferencedSuperVersion(&mutex_);
auto iter = new ForwardIterator(this, read_options, cfd, sv); auto iter = new ForwardIterator(this, read_options, cfd, sv);
result = result = NewDBIterator(
NewDBIterator(env_, read_options, *cfd->ioptions(), env_, read_options, *cfd->ioptions(), sv->mutable_cf_options,
cfd->user_comparator(), iter, kMaxSequenceNumber, cfd->user_comparator(), iter, kMaxSequenceNumber,
sv->mutable_cf_options.max_sequential_skip_in_iterations, sv->mutable_cf_options.max_sequential_skip_in_iterations,
read_callback); read_callback);
#endif #endif
} else { } else {
// Note: no need to consider the special case of // Note: no need to consider the special case of
@@ -1637,7 +1637,7 @@ ArenaWrappedDBIter* DBImpl::NewIteratorImpl(const ReadOptions& read_options,
// likely that any iterator pointer is close to the iterator it points to so // likely that any iterator pointer is close to the iterator it points to so
// that they are likely to be in the same cache line and/or page. // that they are likely to be in the same cache line and/or page.
ArenaWrappedDBIter* db_iter = NewArenaWrappedDbIterator( ArenaWrappedDBIter* db_iter = NewArenaWrappedDbIterator(
env_, read_options, *cfd->ioptions(), snapshot, env_, read_options, *cfd->ioptions(), sv->mutable_cf_options, snapshot,
sv->mutable_cf_options.max_sequential_skip_in_iterations, sv->mutable_cf_options.max_sequential_skip_in_iterations,
sv->version_number, read_callback, sv->version_number, read_callback,
((read_options.snapshot != nullptr) ? nullptr : this), cfd, allow_blob, ((read_options.snapshot != nullptr) ? nullptr : this), cfd, allow_blob,
@@ -1688,8 +1688,8 @@ Status DBImpl::NewIterators(
SuperVersion* sv = cfd->GetReferencedSuperVersion(&mutex_); SuperVersion* sv = cfd->GetReferencedSuperVersion(&mutex_);
auto iter = new ForwardIterator(this, read_options, cfd, sv); auto iter = new ForwardIterator(this, read_options, cfd, sv);
iterators->push_back(NewDBIterator( iterators->push_back(NewDBIterator(
env_, read_options, *cfd->ioptions(), cfd->user_comparator(), iter, env_, read_options, *cfd->ioptions(), sv->mutable_cf_options,
kMaxSequenceNumber, cfd->user_comparator(), iter, kMaxSequenceNumber,
sv->mutable_cf_options.max_sequential_skip_in_iterations, sv->mutable_cf_options.max_sequential_skip_in_iterations,
read_callback)); read_callback));
} }
@@ -2863,7 +2863,9 @@ Status DBImpl::IngestExternalFile(
pending_output_elem = CaptureCurrentFileNumberInPendingOutputs(); pending_output_elem = CaptureCurrentFileNumberInPendingOutputs();
} }
status = ingestion_job.Prepare(external_files); SuperVersion* super_version = cfd->GetReferencedSuperVersion(&mutex_);
status = ingestion_job.Prepare(external_files, super_version);
CleanupSuperVersion(super_version);
if (!status.ok()) { if (!status.ok()) {
return status; return status;
} }
+2 -2
View File
@@ -58,7 +58,7 @@ Iterator* DBImplReadOnly::NewIterator(const ReadOptions& read_options,
SequenceNumber latest_snapshot = versions_->LastSequence(); SequenceNumber latest_snapshot = versions_->LastSequence();
ReadCallback* read_callback = nullptr; // No read callback provided. ReadCallback* read_callback = nullptr; // No read callback provided.
auto db_iter = NewArenaWrappedDbIterator( auto db_iter = NewArenaWrappedDbIterator(
env_, read_options, *cfd->ioptions(), env_, read_options, *cfd->ioptions(), super_version->mutable_cf_options,
(read_options.snapshot != nullptr (read_options.snapshot != nullptr
? reinterpret_cast<const SnapshotImpl*>(read_options.snapshot) ? reinterpret_cast<const SnapshotImpl*>(read_options.snapshot)
->number_ ->number_
@@ -88,7 +88,7 @@ Status DBImplReadOnly::NewIterators(
auto* cfd = reinterpret_cast<ColumnFamilyHandleImpl*>(cfh)->cfd(); auto* cfd = reinterpret_cast<ColumnFamilyHandleImpl*>(cfh)->cfd();
auto* sv = cfd->GetSuperVersion()->Ref(); auto* sv = cfd->GetSuperVersion()->Ref();
auto* db_iter = NewArenaWrappedDbIterator( auto* db_iter = NewArenaWrappedDbIterator(
env_, read_options, *cfd->ioptions(), env_, read_options, *cfd->ioptions(), sv->mutable_cf_options,
(read_options.snapshot != nullptr (read_options.snapshot != nullptr
? reinterpret_cast<const SnapshotImpl*>(read_options.snapshot) ? reinterpret_cast<const SnapshotImpl*>(read_options.snapshot)
->number_ ->number_
+15 -11
View File
@@ -110,7 +110,8 @@ class DBIter final: public Iterator {
}; };
DBIter(Env* _env, const ReadOptions& read_options, DBIter(Env* _env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const Comparator* cmp, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options, const Comparator* cmp,
InternalIterator* iter, SequenceNumber s, bool arena_mode, InternalIterator* iter, SequenceNumber s, bool arena_mode,
uint64_t max_sequential_skip_in_iterations, uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback, bool allow_blob) ReadCallback* read_callback, bool allow_blob)
@@ -138,7 +139,7 @@ class DBIter final: public Iterator {
is_blob_(false), is_blob_(false),
start_seqnum_(read_options.iter_start_seqnum) { start_seqnum_(read_options.iter_start_seqnum) {
RecordTick(statistics_, NO_ITERATORS); RecordTick(statistics_, NO_ITERATORS);
prefix_extractor_ = cf_options.prefix_extractor; prefix_extractor_ = mutable_cf_options.prefix_extractor.get();
max_skip_ = max_sequential_skip_in_iterations; max_skip_ = max_sequential_skip_in_iterations;
max_skippable_internal_keys_ = read_options.max_skippable_internal_keys; max_skippable_internal_keys_ = read_options.max_skippable_internal_keys;
if (pin_thru_lifetime_) { if (pin_thru_lifetime_) {
@@ -1426,14 +1427,15 @@ void DBIter::SeekToLast() {
Iterator* NewDBIterator(Env* env, const ReadOptions& read_options, Iterator* NewDBIterator(Env* env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator, const Comparator* user_key_comparator,
InternalIterator* internal_iter, InternalIterator* internal_iter,
const SequenceNumber& sequence, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, uint64_t max_sequential_skip_in_iterations,
ReadCallback* read_callback, bool allow_blob) { ReadCallback* read_callback, bool allow_blob) {
DBIter* db_iter = DBIter* db_iter =
new DBIter(env, read_options, cf_options, user_key_comparator, new DBIter(env, read_options, cf_options, mutable_cf_options,
internal_iter, sequence, false, user_key_comparator, internal_iter, sequence, false,
max_sequential_skip_in_iterations, read_callback, allow_blob); max_sequential_skip_in_iterations, read_callback, allow_blob);
return db_iter; return db_iter;
} }
@@ -1477,6 +1479,7 @@ inline Status ArenaWrappedDBIter::GetProperty(std::string prop_name,
void ArenaWrappedDBIter::Init(Env* env, const ReadOptions& read_options, void ArenaWrappedDBIter::Init(Env* env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options,
const SequenceNumber& sequence, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iteration, uint64_t max_sequential_skip_in_iteration,
uint64_t version_number, uint64_t version_number,
@@ -1484,9 +1487,9 @@ void ArenaWrappedDBIter::Init(Env* env, const ReadOptions& read_options,
bool allow_refresh) { bool allow_refresh) {
auto mem = arena_.AllocateAligned(sizeof(DBIter)); auto mem = arena_.AllocateAligned(sizeof(DBIter));
db_iter_ = new (mem) db_iter_ = new (mem)
DBIter(env, read_options, cf_options, cf_options.user_comparator, nullptr, DBIter(env, read_options, cf_options, mutable_cf_options,
sequence, true, max_sequential_skip_in_iteration, read_callback, cf_options.user_comparator, nullptr, sequence, true,
allow_blob); max_sequential_skip_in_iteration, read_callback, allow_blob);
sv_number_ = version_number; sv_number_ = version_number;
allow_refresh_ = allow_refresh; allow_refresh_ = allow_refresh;
} }
@@ -1508,8 +1511,8 @@ Status ArenaWrappedDBIter::Refresh() {
new (&arena_) Arena(); new (&arena_) Arena();
SuperVersion* sv = cfd_->GetReferencedSuperVersion(db_impl_->mutex()); SuperVersion* sv = cfd_->GetReferencedSuperVersion(db_impl_->mutex());
Init(env, read_options_, *(cfd_->ioptions()), latest_seq, Init(env, read_options_, *(cfd_->ioptions()), sv->mutable_cf_options,
sv->mutable_cf_options.max_sequential_skip_in_iterations, latest_seq, sv->mutable_cf_options.max_sequential_skip_in_iterations,
cur_sv_number, read_callback_, allow_blob_, allow_refresh_); cur_sv_number, read_callback_, allow_blob_, allow_refresh_);
InternalIterator* internal_iter = db_impl_->NewInternalIterator( InternalIterator* internal_iter = db_impl_->NewInternalIterator(
@@ -1524,12 +1527,13 @@ Status ArenaWrappedDBIter::Refresh() {
ArenaWrappedDBIter* NewArenaWrappedDbIterator( ArenaWrappedDBIter* NewArenaWrappedDbIterator(
Env* env, const ReadOptions& read_options, Env* env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const SequenceNumber& sequence, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, uint64_t version_number, uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
ReadCallback* read_callback, DBImpl* db_impl, ColumnFamilyData* cfd, ReadCallback* read_callback, DBImpl* db_impl, ColumnFamilyData* cfd,
bool allow_blob, bool allow_refresh) { bool allow_blob, bool allow_refresh) {
ArenaWrappedDBIter* iter = new ArenaWrappedDBIter(); ArenaWrappedDBIter* iter = new ArenaWrappedDBIter();
iter->Init(env, read_options, cf_options, sequence, iter->Init(env, read_options, cf_options, mutable_cf_options, sequence,
max_sequential_skip_in_iterations, version_number, read_callback, max_sequential_skip_in_iterations, version_number, read_callback,
allow_blob, allow_refresh); allow_blob, allow_refresh);
if (db_impl != nullptr && cfd != nullptr && allow_refresh) { if (db_impl != nullptr && cfd != nullptr && allow_refresh) {
+4 -1
View File
@@ -30,6 +30,7 @@ class InternalIterator;
// into appropriate user keys. // into appropriate user keys.
extern Iterator* NewDBIterator(Env* env, const ReadOptions& read_options, extern Iterator* NewDBIterator(Env* env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options,
const Comparator* user_key_comparator, const Comparator* user_key_comparator,
InternalIterator* internal_iter, InternalIterator* internal_iter,
const SequenceNumber& sequence, const SequenceNumber& sequence,
@@ -71,6 +72,7 @@ class ArenaWrappedDBIter : public Iterator {
void Init(Env* env, const ReadOptions& read_options, void Init(Env* env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options,
const SequenceNumber& sequence, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, uint64_t version_number, uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
ReadCallback* read_callback, bool allow_blob, bool allow_refresh); ReadCallback* read_callback, bool allow_blob, bool allow_refresh);
@@ -102,7 +104,8 @@ class ArenaWrappedDBIter : public Iterator {
// be supported. // be supported.
extern ArenaWrappedDBIter* NewArenaWrappedDbIterator( extern ArenaWrappedDBIter* NewArenaWrappedDbIterator(
Env* env, const ReadOptions& read_options, Env* env, const ReadOptions& read_options,
const ImmutableCFOptions& cf_options, const SequenceNumber& sequence, const ImmutableCFOptions& cf_options,
const MutableCFOptions& mutable_cf_options, const SequenceNumber& sequence,
uint64_t max_sequential_skip_in_iterations, uint64_t version_number, uint64_t max_sequential_skip_in_iterations, uint64_t version_number,
ReadCallback* read_callback, DBImpl* db_impl = nullptr, ReadCallback* read_callback, DBImpl* db_impl = nullptr,
ColumnFamilyData* cfd = nullptr, bool allow_blob = false, ColumnFamilyData* cfd = nullptr, bool allow_blob = false,
+2 -1
View File
@@ -508,7 +508,8 @@ TEST_F(DBIteratorStressTest, StressTest) {
internal_iter->trace = trace; internal_iter->trace = trace;
db_iter.reset(NewDBIterator( db_iter.reset(NewDBIterator(
env_, ropt, ImmutableCFOptions(options), env_, ropt, ImmutableCFOptions(options),
BytewiseComparator(), internal_iter, sequence, MutableCFOptions(options), BytewiseComparator(),
internal_iter, sequence,
options.max_sequential_skip_in_iterations, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
} }
+240 -182
View File
@@ -36,7 +36,9 @@ class TestIterator : public InternalIterator {
valid_(false), valid_(false),
sequence_number_(0), sequence_number_(0),
iter_(0), iter_(0),
cmp(comparator) {} cmp(comparator) {
data_.reserve(16);
}
void AddPut(std::string argkey, std::string argvalue) { void AddPut(std::string argkey, std::string argvalue) {
Add(argkey, kTypeValue, argvalue); Add(argkey, kTypeValue, argvalue);
@@ -234,7 +236,7 @@ class DBIteratorTest : public testing::Test {
TEST_F(DBIteratorTest, DBIteratorPrevNext) { TEST_F(DBIteratorTest, DBIteratorPrevNext) {
Options options; Options options;
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
{ {
TestIterator* internal_iter = new TestIterator(BytewiseComparator()); TestIterator* internal_iter = new TestIterator(BytewiseComparator());
internal_iter->AddDeletion("a"); internal_iter->AddDeletion("a");
@@ -248,8 +250,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro; ReadOptions ro;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -280,8 +283,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro; ReadOptions ro;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -306,8 +310,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -338,8 +343,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -373,8 +379,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
@@ -402,8 +409,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 7, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 7, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
SetPerfLevel(kEnableCount); SetPerfLevel(kEnableCount);
ASSERT_TRUE(GetPerfLevel() == kEnableCount); ASSERT_TRUE(GetPerfLevel() == kEnableCount);
@@ -439,8 +447,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 4, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 4, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -464,8 +473,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
@@ -486,8 +496,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -521,8 +532,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ro.iterate_upper_bound = &prefix; ro.iterate_upper_bound = &prefix;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 7, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 7, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
SetPerfLevel(kEnableCount); SetPerfLevel(kEnableCount);
ASSERT_TRUE(GetPerfLevel() == kEnableCount); ASSERT_TRUE(GetPerfLevel() == kEnableCount);
@@ -550,8 +562,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro; ReadOptions ro;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -592,8 +605,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro; ReadOptions ro;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b"); ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -623,8 +637,9 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
ReadOptions ro; ReadOptions ro;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c"); ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -645,6 +660,7 @@ TEST_F(DBIteratorTest, DBIteratorPrevNext) {
TEST_F(DBIteratorTest, DBIteratorEmpty) { TEST_F(DBIteratorTest, DBIteratorEmpty) {
Options options; Options options;
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
ReadOptions ro; ReadOptions ro;
{ {
@@ -652,8 +668,9 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 0, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 0, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
} }
@@ -663,8 +680,9 @@ TEST_F(DBIteratorTest, DBIteratorEmpty) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 0, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 0, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
} }
@@ -684,10 +702,10 @@ TEST_F(DBIteratorTest, DBIteratorUseSkipCountSkips) {
} }
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 2, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 2,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c"); ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -716,6 +734,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
Options options; Options options;
options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
{ {
for (size_t i = 0; i < 200; ++i) { for (size_t i = 0; i < 200; ++i) {
@@ -729,8 +748,8 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
options.statistics = rocksdb::CreateDBStatistics(); options.statistics = rocksdb::CreateDBStatistics();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, i + 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, i + 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -765,8 +784,8 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, i + 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, i + 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -794,8 +813,8 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 202, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, 202, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -827,8 +846,8 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddPut("c", "200"); internal_iter->AddPut("c", "200");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, i, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, i, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
@@ -844,8 +863,9 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->AddPut("c", "200"); internal_iter->AddPut("c", "200");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 200, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 200, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c"); ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -878,8 +898,8 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, i + 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, i + 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -913,8 +933,8 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, i + 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, i + 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -945,6 +965,7 @@ TEST_F(DBIteratorTest, DBIteratorUseSkip) {
TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) { TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
Options options; Options options;
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
ReadOptions ro; ReadOptions ro;
// Basic test case ... Make sure explicityly passing the default value works. // Basic test case ... Make sure explicityly passing the default value works.
@@ -962,8 +983,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 0; ro.max_skippable_internal_keys = 0;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1008,8 +1030,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 2; ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1052,8 +1075,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 2; ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1090,8 +1114,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 2; ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1125,8 +1150,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 2; ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1155,8 +1181,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 2; ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1192,8 +1219,9 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = 2; ro.max_skippable_internal_keys = 2;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1229,8 +1257,8 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
ro.max_skippable_internal_keys = i; ro.max_skippable_internal_keys = i;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 2 * i + 1, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, 2 * i + 1, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
@@ -1283,8 +1311,8 @@ TEST_F(DBIteratorTest, DBIteratorSkipInternalKeys) {
options.max_sequential_skip_in_iterations = 1000; options.max_sequential_skip_in_iterations = 1000;
ro.max_skippable_internal_keys = i; ro.max_skippable_internal_keys = i;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 2 * i + 1, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, internal_iter, 2 * i + 1, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/)); nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
@@ -1321,10 +1349,10 @@ TEST_F(DBIteratorTest, DBIterator1) {
internal_iter->AddMerge("b", "2"); internal_iter->AddMerge("b", "2");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 1, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 1,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1349,10 +1377,10 @@ TEST_F(DBIteratorTest, DBIterator2) {
internal_iter->AddMerge("b", "2"); internal_iter->AddMerge("b", "2");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 0, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 0,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1374,10 +1402,10 @@ TEST_F(DBIteratorTest, DBIterator3) {
internal_iter->AddMerge("b", "2"); internal_iter->AddMerge("b", "2");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 2, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 2,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1399,10 +1427,10 @@ TEST_F(DBIteratorTest, DBIterator4) {
internal_iter->AddMerge("b", "2"); internal_iter->AddMerge("b", "2");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 4, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 4,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1420,6 +1448,7 @@ TEST_F(DBIteratorTest, DBIterator5) {
Options options; Options options;
options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
{ {
TestIterator* internal_iter = new TestIterator(BytewiseComparator()); TestIterator* internal_iter = new TestIterator(BytewiseComparator());
@@ -1433,8 +1462,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 0, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 0, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1455,8 +1485,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 1, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 1, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1477,8 +1508,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1499,8 +1531,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 3, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 3, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1521,8 +1554,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 4, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 4, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1543,8 +1577,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 5, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 5, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1565,8 +1600,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 6, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 6, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1585,8 +1621,9 @@ TEST_F(DBIteratorTest, DBIterator5) {
internal_iter->AddPut("b", "val_b"); internal_iter->AddPut("b", "val_b");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 10, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 10, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->Seek("b"); db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b"); ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -1601,6 +1638,7 @@ TEST_F(DBIteratorTest, DBIterator6) {
Options options; Options options;
options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
{ {
TestIterator* internal_iter = new TestIterator(BytewiseComparator()); TestIterator* internal_iter = new TestIterator(BytewiseComparator());
@@ -1614,8 +1652,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 0, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 0, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1636,8 +1675,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 1, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 1, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1658,8 +1698,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1680,8 +1721,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 3, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 3, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
} }
@@ -1698,8 +1740,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 4, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 4, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1720,8 +1763,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 5, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 5, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1742,8 +1786,9 @@ TEST_F(DBIteratorTest, DBIterator6) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 6, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 6, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1758,6 +1803,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
Options options; Options options;
options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
ImmutableCFOptions cf_options = ImmutableCFOptions(options); ImmutableCFOptions cf_options = ImmutableCFOptions(options);
MutableCFOptions mutable_cf_options = MutableCFOptions(options);
{ {
TestIterator* internal_iter = new TestIterator(BytewiseComparator()); TestIterator* internal_iter = new TestIterator(BytewiseComparator());
@@ -1783,8 +1829,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 0, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 0, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -1817,8 +1864,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 2, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 2, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1857,8 +1905,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 4, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 4, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1897,8 +1946,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 5, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 5, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1942,8 +1992,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 6, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 6, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -1988,8 +2039,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 7, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 7, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -2028,8 +2080,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 9, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 9, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -2074,8 +2127,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 13, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 13, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -2121,8 +2175,9 @@ TEST_F(DBIteratorTest, DBIterator7) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, cf_options, BytewiseComparator(), internal_iter, 14, env_, ro, cf_options, mutable_cf_options, BytewiseComparator(),
options.max_sequential_skip_in_iterations, nullptr /*read_callback*/)); internal_iter, 14, options.max_sequential_skip_in_iterations,
nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -2151,9 +2206,9 @@ TEST_F(DBIteratorTest, DBIterator8) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 10,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b"); ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -2182,9 +2237,9 @@ TEST_F(DBIteratorTest, DBIterator9) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 10,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -2249,9 +2304,9 @@ TEST_F(DBIteratorTest, DBIterator10) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 10,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->Seek("c"); db_iter->Seek("c");
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
@@ -2289,8 +2344,9 @@ TEST_F(DBIteratorTest, SeekToLastOccurrenceSeq0) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10, 0 /* force seek */, nullptr /*read_callback*/)); BytewiseComparator(), internal_iter, 10, 0 /* force seek */,
nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -2316,10 +2372,10 @@ TEST_F(DBIteratorTest, DBIterator11) {
internal_iter->AddMerge("b", "2"); internal_iter->AddMerge("b", "2");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 1, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 1,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a"); ASSERT_EQ(db_iter->key().ToString(), "a");
@@ -2343,9 +2399,9 @@ TEST_F(DBIteratorTest, DBIterator12) {
internal_iter->AddSingleDeletion("b"); internal_iter->AddSingleDeletion("b");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10, 0, nullptr /*read_callback*/)); BytewiseComparator(), internal_iter, 10, 0, nullptr /*read_callback*/));
db_iter->SeekToLast(); db_iter->SeekToLast();
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c"); ASSERT_EQ(db_iter->key().ToString(), "c");
@@ -2380,9 +2436,9 @@ TEST_F(DBIteratorTest, DBIterator13) {
internal_iter->AddPut(key, "8"); internal_iter->AddPut(key, "8");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 2, 3, nullptr /*read_callback*/)); BytewiseComparator(), internal_iter, 2, 3, nullptr /*read_callback*/));
db_iter->Seek("b"); db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), key); ASSERT_EQ(db_iter->key().ToString(), key);
@@ -2408,9 +2464,9 @@ TEST_F(DBIteratorTest, DBIterator14) {
internal_iter->AddPut("c", "9"); internal_iter->AddPut("c", "9");
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 4, 1, nullptr /*read_callback*/)); BytewiseComparator(), internal_iter, 4, 1, nullptr /*read_callback*/));
db_iter->Seek("b"); db_iter->Seek("b");
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b"); ASSERT_EQ(db_iter->key().ToString(), "b");
@@ -2435,10 +2491,10 @@ TEST_F(DBIteratorTest, DBIteratorTestDifferentialSnapshots) {
} }
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 13, BytewiseComparator(), internal_iter, 13,
options.max_sequential_skip_in_iterations, nullptr)); options.max_sequential_skip_in_iterations, nullptr));
// Expecting InternalKeys in [5,8] range with correct type // Expecting InternalKeys in [5,8] range with correct type
int seqnums[4] = {5,8,11,13}; int seqnums[4] = {5,8,11,13};
std::string user_keys[4] = {"1","2","3","4"}; std::string user_keys[4] = {"1","2","3","4"};
@@ -2470,10 +2526,10 @@ TEST_F(DBIteratorTest, DBIteratorTestDifferentialSnapshots) {
} }
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter( std::unique_ptr<Iterator> db_iter(NewDBIterator(
NewDBIterator(env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 13, BytewiseComparator(), internal_iter, 13,
options.max_sequential_skip_in_iterations, nullptr)); options.max_sequential_skip_in_iterations, nullptr));
// Expecting InternalKeys in [5,8] range with correct type // Expecting InternalKeys in [5,8] range with correct type
int seqnums[4] = {5,8,11,13}; int seqnums[4] = {5,8,11,13};
EntryType key_types[4] = {EntryType::kEntryDelete,EntryType::kEntryDelete, EntryType key_types[4] = {EntryType::kEntryDelete,EntryType::kEntryDelete,
@@ -2521,8 +2577,9 @@ class DBIterWithMergeIterTest : public testing::Test {
NewMergingIterator(&icomp_, &child_iters[0], 2u); NewMergingIterator(&icomp_, &child_iters[0], 2u);
db_iter_.reset(NewDBIterator( db_iter_.reset(NewDBIterator(
env_, ro_, ImmutableCFOptions(options_), BytewiseComparator(), env_, ro_, ImmutableCFOptions(options_), MutableCFOptions(options_),
merge_iter, 8 /* read data earlier than seqId 8 */, BytewiseComparator(), merge_iter,
8 /* read data earlier than seqId 8 */,
3 /* max iterators before reseek */, nullptr /*read_callback*/)); 3 /* max iterators before reseek */, nullptr /*read_callback*/));
} }
@@ -2605,7 +2662,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace1) {
// MergeIterator::Prev() realized the mem table iterator is at its end // MergeIterator::Prev() realized the mem table iterator is at its end
// and before an SeekToLast() is called. // and before an SeekToLast() is called.
rocksdb::SyncPoint::GetInstance()->SetCallBack( rocksdb::SyncPoint::GetInstance()->SetCallBack(
"MergeIterator::Prev:BeforeSeekToLast", "MergeIterator::Prev:BeforePrev",
[&](void* /*arg*/) { internal_iter2_->Add("z", kTypeValue, "7", 12u); }); [&](void* /*arg*/) { internal_iter2_->Add("z", kTypeValue, "7", 12u); });
rocksdb::SyncPoint::GetInstance()->EnableProcessing(); rocksdb::SyncPoint::GetInstance()->EnableProcessing();
@@ -2641,7 +2698,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace2) {
// mem table after MergeIterator::Prev() realized the mem tableiterator is at // mem table after MergeIterator::Prev() realized the mem tableiterator is at
// its end and before an SeekToLast() is called. // its end and before an SeekToLast() is called.
rocksdb::SyncPoint::GetInstance()->SetCallBack( rocksdb::SyncPoint::GetInstance()->SetCallBack(
"MergeIterator::Prev:BeforeSeekToLast", [&](void* /*arg*/) { "MergeIterator::Prev:BeforePrev", [&](void* /*arg*/) {
internal_iter2_->Add("z", kTypeValue, "7", 12u); internal_iter2_->Add("z", kTypeValue, "7", 12u);
internal_iter2_->Add("z", kTypeValue, "7", 11u); internal_iter2_->Add("z", kTypeValue, "7", 11u);
}); });
@@ -2679,7 +2736,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace3) {
// mem table after MergeIterator::Prev() realized the mem table iterator is at // mem table after MergeIterator::Prev() realized the mem table iterator is at
// its end and before an SeekToLast() is called. // its end and before an SeekToLast() is called.
rocksdb::SyncPoint::GetInstance()->SetCallBack( rocksdb::SyncPoint::GetInstance()->SetCallBack(
"MergeIterator::Prev:BeforeSeekToLast", [&](void* /*arg*/) { "MergeIterator::Prev:BeforePrev", [&](void* /*arg*/) {
internal_iter2_->Add("z", kTypeValue, "7", 16u, true); internal_iter2_->Add("z", kTypeValue, "7", 16u, true);
internal_iter2_->Add("z", kTypeValue, "7", 15u, true); internal_iter2_->Add("z", kTypeValue, "7", 15u, true);
internal_iter2_->Add("z", kTypeValue, "7", 14u, true); internal_iter2_->Add("z", kTypeValue, "7", 14u, true);
@@ -2960,9 +3017,9 @@ TEST_F(DBIteratorTest, SeekPrefixTombstones) {
ro.prefix_same_as_start = true; ro.prefix_same_as_start = true;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10, options.max_sequential_skip_in_iterations, BytewiseComparator(), internal_iter, 10,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
int skipped_keys = 0; int skipped_keys = 0;
@@ -2996,9 +3053,10 @@ TEST_F(DBIteratorTest, SeekToFirstLowerBound) {
ro.iterate_lower_bound = &lower_bound; ro.iterate_lower_bound = &lower_bound;
Options options; Options options;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10 /* sequence */, BytewiseComparator(), internal_iter, 10 /* sequence */,
options.max_sequential_skip_in_iterations, nullptr /* read_callback */)); options.max_sequential_skip_in_iterations,
nullptr /* read_callback */));
db_iter->SeekToFirst(); db_iter->SeekToFirst();
if (i == kNumKeys + 1) { if (i == kNumKeys + 1) {
@@ -3034,8 +3092,8 @@ TEST_F(DBIteratorTest, PrevLowerBound) {
ro.iterate_lower_bound = &lower_bound; ro.iterate_lower_bound = &lower_bound;
Options options; Options options;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10 /* sequence */, BytewiseComparator(), internal_iter, 10 /* sequence */,
options.max_sequential_skip_in_iterations, nullptr /* read_callback */)); options.max_sequential_skip_in_iterations, nullptr /* read_callback */));
db_iter->SeekToLast(); db_iter->SeekToLast();
@@ -3062,8 +3120,8 @@ TEST_F(DBIteratorTest, SeekLessLowerBound) {
ro.iterate_lower_bound = &lower_bound; ro.iterate_lower_bound = &lower_bound;
Options options; Options options;
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ro, ImmutableCFOptions(options), BytewiseComparator(), env_, ro, ImmutableCFOptions(options), MutableCFOptions(options),
internal_iter, 10 /* sequence */, BytewiseComparator(), internal_iter, 10 /* sequence */,
options.max_sequential_skip_in_iterations, nullptr /* read_callback */)); options.max_sequential_skip_in_iterations, nullptr /* read_callback */));
auto before_lower_bound_str = std::to_string(kLowerBound - 1); auto before_lower_bound_str = std::to_string(kLowerBound - 1);
@@ -3087,9 +3145,9 @@ TEST_F(DBIteratorTest, ReverseToForwardWithDisappearingKeys) {
internal_iter->Finish(); internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator( std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ReadOptions(), ImmutableCFOptions(options), BytewiseComparator(), env_, ReadOptions(), ImmutableCFOptions(options),
internal_iter, 10, options.max_sequential_skip_in_iterations, MutableCFOptions(options), BytewiseComparator(), internal_iter, 10,
nullptr /*read_callback*/)); options.max_sequential_skip_in_iterations, nullptr /*read_callback*/));
db_iter->SeekForPrev("a"); db_iter->SeekForPrev("a");
ASSERT_TRUE(db_iter->Valid()); ASSERT_TRUE(db_iter->Valid());
+82 -3
View File
@@ -862,6 +862,8 @@ TEST_P(DBIteratorTest, IteratorPinsRef) {
} while (ChangeCompactOptions()); } while (ChangeCompactOptions());
} }
// SetOptions not defined in ROCKSDB LITE
#ifndef ROCKSDB_LITE
TEST_P(DBIteratorTest, DBIteratorBoundTest) { TEST_P(DBIteratorTest, DBIteratorBoundTest) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.env = env_; options.env = env_;
@@ -946,9 +948,7 @@ TEST_P(DBIteratorTest, DBIteratorBoundTest) {
} }
// prefix is the first letter of the key // prefix is the first letter of the key
options.prefix_extractor.reset(NewFixedPrefixTransform(1)); ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "fixed:1"}}));
DestroyAndReopen(options);
ASSERT_OK(Put("a", "0")); ASSERT_OK(Put("a", "0"));
ASSERT_OK(Put("foo", "bar")); ASSERT_OK(Put("foo", "bar"));
ASSERT_OK(Put("foo1", "bar1")); ASSERT_OK(Put("foo1", "bar1"));
@@ -1035,6 +1035,7 @@ TEST_P(DBIteratorTest, DBIteratorBoundTest) {
ASSERT_EQ(static_cast<int>(get_perf_context()->internal_delete_skipped_count), 0); ASSERT_EQ(static_cast<int>(get_perf_context()->internal_delete_skipped_count), 0);
} }
} }
#endif
TEST_P(DBIteratorTest, DBIteratorBoundOptimizationTest) { TEST_P(DBIteratorTest, DBIteratorBoundOptimizationTest) {
int upper_bound_hits = 0; int upper_bound_hits = 0;
@@ -2043,6 +2044,43 @@ TEST_P(DBIteratorTest, CreationFailure) {
delete iter; 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) { TEST_P(DBIteratorTest, TableFilter) {
ASSERT_OK(Put("a", "1")); ASSERT_OK(Put("a", "1"));
dbfull()->Flush(FlushOptions()); dbfull()->Flush(FlushOptions());
@@ -2109,6 +2147,47 @@ 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) { TEST_P(DBIteratorTest, SkipStatistics) {
Options options = CurrentOptions(); Options options = CurrentOptions();
options.statistics = rocksdb::CreateDBStatistics(); options.statistics = rocksdb::CreateDBStatistics();
+15 -13
View File
@@ -177,17 +177,16 @@ void ParseTablePropertiesString(std::string tp_string, TableProperties* tp) {
std::replace(tp_string.begin(), tp_string.end(), ';', ' '); std::replace(tp_string.begin(), tp_string.end(), ';', ' ');
std::replace(tp_string.begin(), tp_string.end(), '=', ' '); std::replace(tp_string.begin(), tp_string.end(), '=', ' ');
ResetTableProperties(tp); ResetTableProperties(tp);
sscanf(tp_string.c_str(), sscanf(tp_string.c_str(),
"# data blocks %" SCNu64 " # entries %" SCNu64 " raw key size %" SCNu64 "# data blocks %" SCNu64 " # entries %" SCNu64 " raw key size %" SCNu64
" raw average key size %lf " " raw average key size %lf "
" raw value size %" SCNu64 " raw value size %" SCNu64
" raw average value size %lf " " raw average value size %lf "
" data block size %" SCNu64 " index block size %" SCNu64 " data block size %" SCNu64 " index block size (user-key? %" SCNu64
" filter block size %" SCNu64, ") %" SCNu64 " filter block size %" SCNu64,
&tp->num_data_blocks, &tp->num_entries, &tp->raw_key_size, &tp->num_data_blocks, &tp->num_entries, &tp->raw_key_size,
&dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size, &dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size,
&tp->index_size, &tp->filter_size); &tp->index_key_is_user_key, &tp->index_size, &tp->filter_size);
} }
void VerifySimilar(uint64_t a, uint64_t b, double bias) { void VerifySimilar(uint64_t a, uint64_t b, double bias) {
@@ -224,7 +223,8 @@ void GetExpectedTableProperties(TableProperties* expected_tp,
const int kKeySize, const int kValueSize, const int kKeySize, const int kValueSize,
const int kKeysPerTable, const int kTableCount, const int kKeysPerTable, const int kTableCount,
const int kBloomBitsPerKey, const int kBloomBitsPerKey,
const size_t kBlockSize) { const size_t kBlockSize,
const bool index_key_is_user_key) {
const int kKeyCount = kTableCount * kKeysPerTable; const int kKeyCount = kTableCount * kKeysPerTable;
const int kAvgSuccessorSize = kKeySize / 5; const int kAvgSuccessorSize = kKeySize / 5;
const int kEncodingSavePerKey = kKeySize / 4; const int kEncodingSavePerKey = kKeySize / 4;
@@ -238,7 +238,8 @@ void GetExpectedTableProperties(TableProperties* expected_tp,
expected_tp->data_size = expected_tp->data_size =
kTableCount * (kKeysPerTable * (kKeySize + 8 + kValueSize)); kTableCount * (kKeysPerTable * (kKeySize + 8 + kValueSize));
expected_tp->index_size = expected_tp->index_size =
expected_tp->num_data_blocks * (kAvgSuccessorSize + 8); expected_tp->num_data_blocks *
(kAvgSuccessorSize + (index_key_is_user_key ? 0 : 8));
expected_tp->filter_size = expected_tp->filter_size =
kTableCount * (kKeysPerTable * kBloomBitsPerKey / 8); kTableCount * (kKeysPerTable * kBloomBitsPerKey / 8);
} }
@@ -315,14 +316,14 @@ TEST_F(DBPropertiesTest, AggregatedTableProperties) {
} }
std::string property; std::string property;
db_->GetProperty(DB::Properties::kAggregatedTableProperties, &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; TableProperties expected_tp;
GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize, GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize,
kKeysPerTable, kTableCount, kBloomBitsPerKey, kKeysPerTable, kTableCount, kBloomBitsPerKey,
table_options.block_size); table_options.block_size, index_key_is_user_key);
TableProperties output_tp;
ParseTablePropertiesString(property, &output_tp);
VerifyTableProperties(expected_tp, output_tp); VerifyTableProperties(expected_tp, output_tp);
} }
@@ -489,6 +490,7 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
} }
db_->GetProperty(DB::Properties::kAggregatedTableProperties, &tp_string); db_->GetProperty(DB::Properties::kAggregatedTableProperties, &tp_string);
ParseTablePropertiesString(tp_string, &tp); 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.data_size, tp.data_size);
ASSERT_EQ(sum_tp.index_size, tp.index_size); ASSERT_EQ(sum_tp.index_size, tp.index_size);
ASSERT_EQ(sum_tp.filter_size, tp.filter_size); ASSERT_EQ(sum_tp.filter_size, tp.filter_size);
@@ -497,9 +499,9 @@ TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
ASSERT_EQ(sum_tp.num_data_blocks, tp.num_data_blocks); ASSERT_EQ(sum_tp.num_data_blocks, tp.num_data_blocks);
ASSERT_EQ(sum_tp.num_entries, tp.num_entries); ASSERT_EQ(sum_tp.num_entries, tp.num_entries);
if (table > 3) { if (table > 3) {
GetExpectedTableProperties(&expected_tp, kKeySize, kValueSize, GetExpectedTableProperties(
kKeysPerTable, table, kBloomBitsPerKey, &expected_tp, kKeySize, kValueSize, kKeysPerTable, table,
table_options.block_size); kBloomBitsPerKey, table_options.block_size, index_key_is_user_key);
// Gives larger bias here as index block size, filter 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. // and data block size become much harder to estimate in this test.
VerifyTableProperties(tp, expected_tp, 0.5, 0.4, 0.4, 0.25); VerifyTableProperties(tp, expected_tp, 0.5, 0.4, 0.4, 0.25);
+183 -9
View File
@@ -4607,6 +4607,181 @@ TEST_F(DBTest, FileCreationRandomFailure) {
} }
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
int CountIter(Iterator* iter, const Slice& key) {
int count = 0;
for (iter->Seek(key); iter->Valid() && iter->status() == Status::OK();
iter->Next()) {
count++;
}
return count;
}
// Create multiple SST files each with a different prefix_extractor config,
// verify iterators can read all SST files using the latest config.
TEST_F(DBTest, DynamicBloomFilterMultipleSST) {
Options options;
options.create_if_missing = true;
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
options.disable_auto_compactions = true;
// Enable prefix bloom for SST files
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(10, true));
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
DestroyAndReopen(options);
ReadOptions read_options;
read_options.prefix_same_as_start = true;
// first SST with fixed:1 BF
ASSERT_OK(Put("foo2", "bar2"));
ASSERT_OK(Put("foo", "bar"));
ASSERT_OK(Put("foq1", "bar1"));
ASSERT_OK(Put("fpa", "0"));
dbfull()->Flush(FlushOptions());
Iterator* iter_old = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter_old, "foo"), 4);
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "capped:3"}}));
ASSERT_EQ(0, strcmp(dbfull()->GetOptions().prefix_extractor->Name(),
"rocksdb.CappedPrefix.3"));
Iterator* iter = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter, "foo"), 2);
// second SST with capped:3 BF
ASSERT_OK(Put("foo3", "bar3"));
ASSERT_OK(Put("foo4", "bar4"));
ASSERT_OK(Put("foq5", "bar5"));
ASSERT_OK(Put("fpb", "1"));
dbfull()->Flush(FlushOptions());
// BF is cappped:3 now
Iterator* iter_tmp = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter_tmp, "foo"), 4);
delete iter_tmp;
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "fixed:2"}}));
ASSERT_EQ(0, strcmp(dbfull()->GetOptions().prefix_extractor->Name(),
"rocksdb.FixedPrefix.2"));
// third SST with fixed:2 BF
ASSERT_OK(Put("foo6", "bar6"));
ASSERT_OK(Put("foo7", "bar7"));
ASSERT_OK(Put("foq8", "bar8"));
ASSERT_OK(Put("fpc", "2"));
dbfull()->Flush(FlushOptions());
// BF is fixed:2 now
iter_tmp = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter_tmp, "foo"), 9);
delete iter_tmp;
// TODO(Zhongyi): verify existing iterator cannot see newly inserted keys
ASSERT_EQ(CountIter(iter_old, "foo"), 4);
ASSERT_EQ(CountIter(iter, "foo"), 2);
delete iter;
delete iter_old;
// keys in all three SSTs are visible to iterator
Iterator* iter_all = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter_all, "foo"), 9);
delete iter_all;
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "capped:3"}}));
ASSERT_EQ(0, strcmp(dbfull()->GetOptions().prefix_extractor->Name(),
"rocksdb.CappedPrefix.3"));
iter_all = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter_all, "foo"), 6);
delete iter_all;
// TODO(Zhongyi): add test for cases where certain SST are skipped
// Also verify BF related counters like BLOOM_FILTER_USEFUL
}
// Create a new column family in a running DB, change prefix_extractor
// dynamically, verify the iterator created on the new column family behaves
// as expected
TEST_F(DBTest, DynamicBloomFilterNewColumnFamily) {
Options options = CurrentOptions();
options.create_if_missing = true;
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
options.disable_auto_compactions = true;
// Enable prefix bloom for SST files
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(10, true));
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
CreateAndReopenWithCF({"pikachu"}, options);
ReadOptions read_options;
read_options.prefix_same_as_start = true;
// create a new CF and set prefix_extractor dynamically
options.prefix_extractor.reset(NewCappedPrefixTransform(3));
CreateColumnFamilies({"ramen_dojo"}, options);
ASSERT_EQ(0,
strcmp(dbfull()->GetOptions(handles_[2]).prefix_extractor->Name(),
"rocksdb.CappedPrefix.3"));
ASSERT_OK(Put(2, "foo3", "bar3"));
ASSERT_OK(Put(2, "foo4", "bar4"));
ASSERT_OK(Put(2, "foo5", "bar5"));
ASSERT_OK(Put(2, "foq6", "bar6"));
ASSERT_OK(Put(2, "fpq7", "bar7"));
dbfull()->Flush(FlushOptions());
Iterator* iter = db_->NewIterator(read_options, handles_[2]);
ASSERT_EQ(CountIter(iter, "foo"), 3);
delete iter;
ASSERT_OK(
dbfull()->SetOptions(handles_[2], {{"prefix_extractor", "fixed:2"}}));
ASSERT_EQ(0,
strcmp(dbfull()->GetOptions(handles_[2]).prefix_extractor->Name(),
"rocksdb.FixedPrefix.2"));
iter = db_->NewIterator(read_options, handles_[2]);
ASSERT_EQ(CountIter(iter, "foo"), 4);
delete iter;
}
// Verify it's possible to change prefix_extractor at runtime and iterators
// behaves as expected
TEST_F(DBTest, DynamicBloomFilterOptions) {
Options options;
options.create_if_missing = true;
options.prefix_extractor.reset(NewFixedPrefixTransform(1));
options.disable_auto_compactions = true;
// Enable prefix bloom for SST files
BlockBasedTableOptions table_options;
table_options.filter_policy.reset(NewBloomFilterPolicy(10, true));
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
DestroyAndReopen(options);
ASSERT_OK(Put("foo2", "bar2"));
ASSERT_OK(Put("foo", "bar"));
ASSERT_OK(Put("foo1", "bar1"));
ASSERT_OK(Put("fpa", "0"));
dbfull()->Flush(FlushOptions());
ASSERT_OK(Put("foo3", "bar3"));
ASSERT_OK(Put("foo4", "bar4"));
ASSERT_OK(Put("foo5", "bar5"));
ASSERT_OK(Put("fpb", "1"));
dbfull()->Flush(FlushOptions());
ASSERT_OK(Put("foo6", "bar6"));
ASSERT_OK(Put("foo7", "bar7"));
ASSERT_OK(Put("foo8", "bar8"));
ASSERT_OK(Put("fpc", "2"));
dbfull()->Flush(FlushOptions());
ReadOptions read_options;
read_options.prefix_same_as_start = true;
Iterator* iter = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter, "foo"), 12);
delete iter;
Iterator* iter_old = db_->NewIterator(read_options);
ASSERT_EQ(CountIter(iter_old, "foo"), 12);
ASSERT_OK(dbfull()->SetOptions({{"prefix_extractor", "capped:3"}}));
ASSERT_EQ(0, strcmp(dbfull()->GetOptions().prefix_extractor->Name(),
"rocksdb.CappedPrefix.3"));
iter = db_->NewIterator(read_options);
// "fp*" should be skipped
ASSERT_EQ(CountIter(iter, "foo"), 9);
delete iter;
// iterator created before should not be affected and see all keys
ASSERT_EQ(CountIter(iter_old, "foo"), 12);
delete iter_old;
}
TEST_F(DBTest, DynamicMiscOptions) { TEST_F(DBTest, DynamicMiscOptions) {
// Test max_sequential_skip_in_iterations // Test max_sequential_skip_in_iterations
Options options; Options options;
@@ -5445,18 +5620,17 @@ TEST_F(DBTest, HardLimit) {
#if !defined(ROCKSDB_LITE) && !defined(ROCKSDB_DISABLE_STALL_NOTIFICATION) #if !defined(ROCKSDB_LITE) && !defined(ROCKSDB_DISABLE_STALL_NOTIFICATION)
class WriteStallListener : public EventListener { class WriteStallListener : public EventListener {
public: public:
WriteStallListener() : cond_(&mutex_), WriteStallListener()
condition_(WriteStallCondition::kNormal), : cond_(&mutex_),
expected_(WriteStallCondition::kNormal), condition_(WriteStallCondition::kNormal),
expected_set_(false) expected_(WriteStallCondition::kNormal),
{} expected_set_(false) {}
void OnStallConditionsChanged(const WriteStallInfo& info) override { void OnStallConditionsChanged(const WriteStallInfo& info) override {
MutexLock l(&mutex_); MutexLock l(&mutex_);
condition_ = info.condition.cur; condition_ = info.condition.cur;
if (expected_set_ && if (expected_set_ && condition_ == expected_) {
condition_ == expected_) { cond_.Signal();
cond_.Signal(); expected_set_ = false;
expected_set_ = false;
} }
} }
bool CheckCondition(WriteStallCondition expected) { bool CheckCondition(WriteStallCondition expected) {
+11
View File
@@ -428,6 +428,17 @@ Options DBTestBase::GetOptions(
options.prefix_extractor.reset(NewNoopTransform()); options.prefix_extractor.reset(NewNoopTransform());
break; 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: { case kBlockBasedTableWithIndexRestartInterval: {
table_options.index_block_restart_interval = 8; table_options.index_block_restart_interval = 8;
break; break;
+14 -7
View File
@@ -694,13 +694,20 @@ class DBTestBase : public testing::Test {
kConcurrentSkipList = 29, kConcurrentSkipList = 29,
kPipelinedWrite = 30, kPipelinedWrite = 30,
kConcurrentWALWrites = 31, kConcurrentWALWrites = 31,
kEnd = 32, kDirectIO,
kDirectIO = 33, kLevelSubcompactions,
kLevelSubcompactions = 34, kBlockBasedTableWithIndexRestartInterval,
kUniversalSubcompactions = 35, kBlockBasedTableWithPartitionedIndex,
kBlockBasedTableWithIndexRestartInterval = 36, kBlockBasedTableWithPartitionedIndexFormat3,
kBlockBasedTableWithPartitionedIndex = 37, kPartitionedFilterWithNewTableReaderForCompactions,
kPartitionedFilterWithNewTableReaderForCompactions = 38,
// 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,
}; };
public: public:
+9 -6
View File
@@ -29,13 +29,13 @@
namespace rocksdb { namespace rocksdb {
Status ExternalSstFileIngestionJob::Prepare( Status ExternalSstFileIngestionJob::Prepare(
const std::vector<std::string>& external_files_paths) { const std::vector<std::string>& external_files_paths, SuperVersion* sv) {
Status status; Status status;
// Read the information of files we are ingesting // Read the information of files we are ingesting
for (const std::string& file_path : external_files_paths) { for (const std::string& file_path : external_files_paths) {
IngestedFileInfo file_to_ingest; IngestedFileInfo file_to_ingest;
status = GetIngestedFileInfo(file_path, &file_to_ingest); status = GetIngestedFileInfo(file_path, &file_to_ingest, sv);
if (!status.ok()) { if (!status.ok()) {
return status; return status;
} }
@@ -284,7 +284,8 @@ void ExternalSstFileIngestionJob::Cleanup(const Status& status) {
} }
Status ExternalSstFileIngestionJob::GetIngestedFileInfo( Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
const std::string& external_file, IngestedFileInfo* file_to_ingest) { const std::string& external_file, IngestedFileInfo* file_to_ingest,
SuperVersion* sv) {
file_to_ingest->external_file_path = external_file; file_to_ingest->external_file_path = external_file;
// Get external file size // Get external file size
@@ -306,8 +307,9 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
external_file)); external_file));
status = cfd_->ioptions()->table_factory->NewTableReader( status = cfd_->ioptions()->table_factory->NewTableReader(
TableReaderOptions(*cfd_->ioptions(), env_options_, TableReaderOptions(*cfd_->ioptions(),
cfd_->internal_comparator()), sv->mutable_cf_options.prefix_extractor.get(),
env_options_, cfd_->internal_comparator()),
std::move(sst_file_reader), file_to_ingest->file_size, &table_reader); std::move(sst_file_reader), file_to_ingest->file_size, &table_reader);
if (!status.ok()) { if (!status.ok()) {
return status; return status;
@@ -363,7 +365,8 @@ Status ExternalSstFileIngestionJob::GetIngestedFileInfo(
// We need to disable fill_cache so that we read from the file without // We need to disable fill_cache so that we read from the file without
// updating the block cache. // updating the block cache.
ro.fill_cache = false; ro.fill_cache = false;
std::unique_ptr<InternalIterator> iter(table_reader->NewIterator(ro)); std::unique_ptr<InternalIterator> iter(table_reader->NewIterator(
ro, sv->mutable_cf_options.prefix_extractor.get()));
// Get first (smallest) key from file // Get first (smallest) key from file
iter->SeekToFirst(); iter->SeekToFirst();
+4 -2
View File
@@ -86,7 +86,8 @@ class ExternalSstFileIngestionJob {
job_start_time_(env_->NowMicros()) {} job_start_time_(env_->NowMicros()) {}
// Prepare the job by copying external files into the DB. // Prepare the job by copying external files into the DB.
Status Prepare(const std::vector<std::string>& external_files_paths); Status Prepare(const std::vector<std::string>& external_files_paths,
SuperVersion* sv);
// Check if we need to flush the memtable before running the ingestion job // Check if we need to flush the memtable before running the ingestion job
// This will be true if the files we are ingesting are overlapping with any // This will be true if the files we are ingesting are overlapping with any
@@ -119,7 +120,8 @@ class ExternalSstFileIngestionJob {
// Open the external file and populate `file_to_ingest` with all the // Open the external file and populate `file_to_ingest` with all the
// external information we need to ingest this file. // external information we need to ingest this file.
Status GetIngestedFileInfo(const std::string& external_file, Status GetIngestedFileInfo(const std::string& external_file,
IngestedFileInfo* file_to_ingest); IngestedFileInfo* file_to_ingest,
SuperVersion* sv);
// Assign `file_to_ingest` the appropriate sequence number and the lowest // Assign `file_to_ingest` the appropriate sequence number and the lowest
// possible level that it can be ingested to according to compaction_style. // possible level that it can be ingested to according to compaction_style.
+16 -9
View File
@@ -33,14 +33,16 @@ class ForwardLevelIterator : public InternalIterator {
public: public:
ForwardLevelIterator(const ColumnFamilyData* const cfd, ForwardLevelIterator(const ColumnFamilyData* const cfd,
const ReadOptions& read_options, const ReadOptions& read_options,
const std::vector<FileMetaData*>& files) const std::vector<FileMetaData*>& files,
const SliceTransform* prefix_extractor)
: cfd_(cfd), : cfd_(cfd),
read_options_(read_options), read_options_(read_options),
files_(files), files_(files),
valid_(false), valid_(false),
file_index_(std::numeric_limits<uint32_t>::max()), file_index_(std::numeric_limits<uint32_t>::max()),
file_iter_(nullptr), file_iter_(nullptr),
pinned_iters_mgr_(nullptr) {} pinned_iters_mgr_(nullptr),
prefix_extractor_(prefix_extractor) {}
~ForwardLevelIterator() { ~ForwardLevelIterator() {
// Reset current pointer // Reset current pointer
@@ -75,7 +77,7 @@ class ForwardLevelIterator : public InternalIterator {
read_options_, *(cfd_->soptions()), cfd_->internal_comparator(), read_options_, *(cfd_->soptions()), cfd_->internal_comparator(),
files_[file_index_]->fd, files_[file_index_]->fd,
read_options_.ignore_range_deletions ? nullptr : &range_del_agg, read_options_.ignore_range_deletions ? nullptr : &range_del_agg,
nullptr /* table_reader_ptr */, nullptr, false); prefix_extractor_, nullptr /* table_reader_ptr */, nullptr, false);
file_iter_->SetPinnedItersMgr(pinned_iters_mgr_); file_iter_->SetPinnedItersMgr(pinned_iters_mgr_);
valid_ = false; valid_ = false;
if (!range_del_agg.IsEmpty()) { if (!range_del_agg.IsEmpty()) {
@@ -188,6 +190,7 @@ class ForwardLevelIterator : public InternalIterator {
Status status_; Status status_;
InternalIterator* file_iter_; InternalIterator* file_iter_;
PinnedIteratorsManager* pinned_iters_mgr_; PinnedIteratorsManager* pinned_iters_mgr_;
const SliceTransform* prefix_extractor_;
}; };
ForwardIterator::ForwardIterator(DBImpl* db, const ReadOptions& read_options, ForwardIterator::ForwardIterator(DBImpl* db, const ReadOptions& read_options,
@@ -196,7 +199,7 @@ ForwardIterator::ForwardIterator(DBImpl* db, const ReadOptions& read_options,
: db_(db), : db_(db),
read_options_(read_options), read_options_(read_options),
cfd_(cfd), cfd_(cfd),
prefix_extractor_(cfd->ioptions()->prefix_extractor), prefix_extractor_(current_sv->mutable_cf_options.prefix_extractor.get()),
user_comparator_(cfd->user_comparator()), user_comparator_(cfd->user_comparator()),
immutable_min_heap_(MinIterComparator(&cfd_->internal_comparator())), immutable_min_heap_(MinIterComparator(&cfd_->internal_comparator())),
sv_(current_sv), sv_(current_sv),
@@ -633,7 +636,8 @@ void ForwardIterator::RebuildIterators(bool refresh_sv) {
} }
l0_iters_.push_back(cfd_->table_cache()->NewIterator( l0_iters_.push_back(cfd_->table_cache()->NewIterator(
read_options_, *cfd_->soptions(), cfd_->internal_comparator(), l0->fd, read_options_, *cfd_->soptions(), cfd_->internal_comparator(), l0->fd,
read_options_.ignore_range_deletions ? nullptr : &range_del_agg)); read_options_.ignore_range_deletions ? nullptr : &range_del_agg,
sv_->mutable_cf_options.prefix_extractor.get()));
} }
BuildLevelIterators(vstorage); BuildLevelIterators(vstorage);
current_ = nullptr; current_ = nullptr;
@@ -703,7 +707,8 @@ void ForwardIterator::RenewIterators() {
l0_iters_new.push_back(cfd_->table_cache()->NewIterator( l0_iters_new.push_back(cfd_->table_cache()->NewIterator(
read_options_, *cfd_->soptions(), cfd_->internal_comparator(), read_options_, *cfd_->soptions(), cfd_->internal_comparator(),
l0_files_new[inew]->fd, l0_files_new[inew]->fd,
read_options_.ignore_range_deletions ? nullptr : &range_del_agg)); read_options_.ignore_range_deletions ? nullptr : &range_del_agg,
svnew->mutable_cf_options.prefix_extractor.get()));
} }
for (auto* f : l0_iters_) { for (auto* f : l0_iters_) {
@@ -744,8 +749,9 @@ void ForwardIterator::BuildLevelIterators(const VersionStorageInfo* vstorage) {
has_iter_trimmed_for_upper_bound_ = true; has_iter_trimmed_for_upper_bound_ = true;
} }
} else { } else {
level_iters_.push_back( level_iters_.push_back(new ForwardLevelIterator(
new ForwardLevelIterator(cfd_, read_options_, level_files)); cfd_, read_options_, level_files,
sv_->mutable_cf_options.prefix_extractor.get()));
} }
} }
} }
@@ -760,7 +766,8 @@ void ForwardIterator::ResetIncompleteIterators() {
DeleteIterator(l0_iters_[i]); DeleteIterator(l0_iters_[i]);
l0_iters_[i] = cfd_->table_cache()->NewIterator( l0_iters_[i] = cfd_->table_cache()->NewIterator(
read_options_, *cfd_->soptions(), cfd_->internal_comparator(), read_options_, *cfd_->soptions(), cfd_->internal_comparator(),
l0_files[i]->fd, nullptr /* range_del_agg */); l0_files[i]->fd, nullptr /* range_del_agg */,
sv_->mutable_cf_options.prefix_extractor.get());
l0_iters_[i]->SetPinnedItersMgr(pinned_iters_mgr_); l0_iters_[i]->SetPinnedItersMgr(pinned_iters_mgr_);
} }
+3 -3
View File
@@ -74,8 +74,8 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
: nullptr, : nullptr,
mutable_cf_options.memtable_huge_page_size), mutable_cf_options.memtable_huge_page_size),
table_(ioptions.memtable_factory->CreateMemTableRep( table_(ioptions.memtable_factory->CreateMemTableRep(
comparator_, &arena_, ioptions.prefix_extractor, ioptions.info_log, comparator_, &arena_, mutable_cf_options.prefix_extractor.get(),
column_family_id)), ioptions.info_log, column_family_id)),
range_del_table_(SkipListFactory().CreateMemTableRep( range_del_table_(SkipListFactory().CreateMemTableRep(
comparator_, &arena_, nullptr /* transform */, ioptions.info_log, comparator_, &arena_, nullptr /* transform */, ioptions.info_log,
column_family_id)), column_family_id)),
@@ -95,7 +95,7 @@ MemTable::MemTable(const InternalKeyComparator& cmp,
locks_(moptions_.inplace_update_support locks_(moptions_.inplace_update_support
? moptions_.inplace_update_num_locks ? moptions_.inplace_update_num_locks
: 0), : 0),
prefix_extractor_(ioptions.prefix_extractor), prefix_extractor_(mutable_cf_options.prefix_extractor.get()),
flush_state_(FLUSH_NOT_REQUESTED), flush_state_(FLUSH_NOT_REQUESTED),
env_(ioptions.env), env_(ioptions.env),
insert_with_hint_prefix_extractor_( insert_with_hint_prefix_extractor_(
+5 -2
View File
@@ -262,11 +262,13 @@ class TestPlainTableReader : public PlainTableReader {
const TableProperties* table_properties, const TableProperties* table_properties,
unique_ptr<RandomAccessFileReader>&& file, unique_ptr<RandomAccessFileReader>&& file,
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions,
const SliceTransform* prefix_extractor,
bool* expect_bloom_not_match, bool store_index_in_file, bool* expect_bloom_not_match, bool store_index_in_file,
uint32_t column_family_id, uint32_t column_family_id,
const std::string& column_family_name) const std::string& column_family_name)
: PlainTableReader(ioptions, std::move(file), env_options, icomparator, : PlainTableReader(ioptions, std::move(file), env_options, icomparator,
encoding_type, file_size, table_properties), encoding_type, file_size, table_properties,
prefix_extractor),
expect_bloom_not_match_(expect_bloom_not_match) { expect_bloom_not_match_(expect_bloom_not_match) {
Status s = MmapDataIfNeeded(); Status s = MmapDataIfNeeded();
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
@@ -360,7 +362,8 @@ class TestPlainTableFactory : public PlainTableFactory {
table_reader_options.env_options, table_reader_options.env_options,
table_reader_options.internal_comparator, encoding_type, file_size, table_reader_options.internal_comparator, encoding_type, file_size,
bloom_bits_per_key_, hash_table_ratio_, index_sparseness_, props, bloom_bits_per_key_, hash_table_ratio_, index_sparseness_, props,
std::move(file), table_reader_options.ioptions, expect_bloom_not_match_, std::move(file), table_reader_options.ioptions,
table_reader_options.prefix_extractor, expect_bloom_not_match_,
store_index_in_file_, column_family_id_, column_family_name_)); store_index_in_file_, column_family_id_, column_family_name_));
*table = std::move(new_reader); *table = std::move(new_reader);
+2 -1
View File
@@ -501,7 +501,8 @@ class Repairer {
if (status.ok()) { if (status.ok()) {
InternalIterator* iter = table_cache_->NewIterator( InternalIterator* iter = table_cache_->NewIterator(
ReadOptions(), env_options_, cfd->internal_comparator(), t->meta.fd, ReadOptions(), env_options_, cfd->internal_comparator(), t->meta.fd,
nullptr /* range_del_agg */); nullptr /* range_del_agg */,
cfd->GetLatestMutableCFOptions()->prefix_extractor.get());
bool empty = true; bool empty = true;
ParsedInternalKey parsed; ParsedInternalKey parsed;
t->min_sequence = 0; t->min_sequence = 0;
+34 -25
View File
@@ -89,8 +89,8 @@ Status TableCache::GetTableReader(
const InternalKeyComparator& internal_comparator, const FileDescriptor& fd, const InternalKeyComparator& internal_comparator, const FileDescriptor& fd,
bool sequential_mode, size_t readahead, bool record_read_stats, bool sequential_mode, size_t readahead, bool record_read_stats,
HistogramImpl* file_read_hist, unique_ptr<TableReader>* table_reader, HistogramImpl* file_read_hist, unique_ptr<TableReader>* table_reader,
bool skip_filters, int level, bool prefetch_index_and_filter_in_cache, const SliceTransform* prefix_extractor, bool skip_filters, int level,
bool for_compaction) { bool prefetch_index_and_filter_in_cache, bool for_compaction) {
std::string fname = std::string fname =
TableFileName(ioptions_.cf_paths, fd.GetNumber(), fd.GetPathId()); TableFileName(ioptions_.cf_paths, fd.GetNumber(), fd.GetPathId());
unique_ptr<RandomAccessFile> file; unique_ptr<RandomAccessFile> file;
@@ -115,8 +115,8 @@ Status TableCache::GetTableReader(
record_read_stats ? ioptions_.statistics : nullptr, SST_READ_MICROS, record_read_stats ? ioptions_.statistics : nullptr, SST_READ_MICROS,
file_read_hist, ioptions_.rate_limiter, for_compaction)); file_read_hist, ioptions_.rate_limiter, for_compaction));
s = ioptions_.table_factory->NewTableReader( s = ioptions_.table_factory->NewTableReader(
TableReaderOptions(ioptions_, env_options, internal_comparator, TableReaderOptions(ioptions_, prefix_extractor, env_options,
skip_filters, level), internal_comparator, skip_filters, level),
std::move(file_reader), fd.GetFileSize(), table_reader, std::move(file_reader), fd.GetFileSize(), table_reader,
prefetch_index_and_filter_in_cache); prefetch_index_and_filter_in_cache);
TEST_SYNC_POINT("TableCache::GetTableReader:0"); TEST_SYNC_POINT("TableCache::GetTableReader:0");
@@ -134,6 +134,7 @@ void TableCache::EraseHandle(const FileDescriptor& fd, Cache::Handle* handle) {
Status TableCache::FindTable(const EnvOptions& env_options, Status TableCache::FindTable(const EnvOptions& env_options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& fd, Cache::Handle** handle, const FileDescriptor& fd, Cache::Handle** handle,
const SliceTransform* prefix_extractor,
const bool no_io, bool record_read_stats, const bool no_io, bool record_read_stats,
HistogramImpl* file_read_hist, bool skip_filters, HistogramImpl* file_read_hist, bool skip_filters,
int level, int level,
@@ -154,7 +155,8 @@ Status TableCache::FindTable(const EnvOptions& env_options,
s = GetTableReader(env_options, internal_comparator, fd, s = GetTableReader(env_options, internal_comparator, fd,
false /* sequential mode */, 0 /* readahead */, false /* sequential mode */, 0 /* readahead */,
record_read_stats, file_read_hist, &table_reader, record_read_stats, file_read_hist, &table_reader,
skip_filters, level, prefetch_index_and_filter_in_cache); prefix_extractor, skip_filters, level,
prefetch_index_and_filter_in_cache);
if (!s.ok()) { if (!s.ok()) {
assert(table_reader == nullptr); assert(table_reader == nullptr);
RecordTick(ioptions_.statistics, NO_FILE_ERRORS); RecordTick(ioptions_.statistics, NO_FILE_ERRORS);
@@ -175,9 +177,9 @@ Status TableCache::FindTable(const EnvOptions& env_options,
InternalIterator* TableCache::NewIterator( InternalIterator* TableCache::NewIterator(
const ReadOptions& options, const EnvOptions& env_options, const ReadOptions& options, const EnvOptions& env_options,
const InternalKeyComparator& icomparator, const FileDescriptor& fd, const InternalKeyComparator& icomparator, const FileDescriptor& fd,
RangeDelAggregator* range_del_agg, TableReader** table_reader_ptr, RangeDelAggregator* range_del_agg, const SliceTransform* prefix_extractor,
HistogramImpl* file_read_hist, bool for_compaction, Arena* arena, TableReader** table_reader_ptr, HistogramImpl* file_read_hist,
bool skip_filters, int level) { bool for_compaction, Arena* arena, bool skip_filters, int level) {
PERF_TIMER_GUARD(new_table_iterator_nanos); PERF_TIMER_GUARD(new_table_iterator_nanos);
Status s; Status s;
@@ -210,7 +212,7 @@ InternalIterator* TableCache::NewIterator(
s = GetTableReader( s = GetTableReader(
env_options, icomparator, fd, true /* sequential_mode */, readahead, env_options, icomparator, fd, true /* sequential_mode */, readahead,
!for_compaction /* record stats */, nullptr, &table_reader_unique_ptr, !for_compaction /* record stats */, nullptr, &table_reader_unique_ptr,
false /* skip_filters */, level, prefix_extractor, false /* skip_filters */, level,
true /* prefetch_index_and_filter_in_cache */, for_compaction); true /* prefetch_index_and_filter_in_cache */, for_compaction);
if (s.ok()) { if (s.ok()) {
table_reader = table_reader_unique_ptr.release(); table_reader = table_reader_unique_ptr.release();
@@ -218,7 +220,7 @@ InternalIterator* TableCache::NewIterator(
} else { } else {
table_reader = fd.table_reader; table_reader = fd.table_reader;
if (table_reader == nullptr) { if (table_reader == nullptr) {
s = FindTable(env_options, icomparator, fd, &handle, s = FindTable(env_options, icomparator, fd, &handle, prefix_extractor,
options.read_tier == kBlockCacheTier /* no_io */, options.read_tier == kBlockCacheTier /* no_io */,
!for_compaction /* record read_stats */, file_read_hist, !for_compaction /* record read_stats */, file_read_hist,
skip_filters, level); skip_filters, level);
@@ -233,7 +235,8 @@ InternalIterator* TableCache::NewIterator(
!options.table_filter(*table_reader->GetTableProperties())) { !options.table_filter(*table_reader->GetTableProperties())) {
result = NewEmptyInternalIterator(arena); result = NewEmptyInternalIterator(arena);
} else { } else {
result = table_reader->NewIterator(options, arena, skip_filters); result = table_reader->NewIterator(options, prefix_extractor, arena,
skip_filters);
} }
if (create_new_table_reader) { if (create_new_table_reader) {
assert(handle == nullptr); assert(handle == nullptr);
@@ -276,12 +279,13 @@ InternalIterator* TableCache::NewIterator(
InternalIterator* TableCache::NewRangeTombstoneIterator( InternalIterator* TableCache::NewRangeTombstoneIterator(
const ReadOptions& options, const EnvOptions& env_options, const ReadOptions& options, const EnvOptions& env_options,
const InternalKeyComparator& icomparator, const FileDescriptor& fd, const InternalKeyComparator& icomparator, const FileDescriptor& fd,
HistogramImpl* file_read_hist, bool skip_filters, int level) { HistogramImpl* file_read_hist, bool skip_filters, int level,
const SliceTransform* prefix_extractor) {
Status s; Status s;
Cache::Handle* handle = nullptr; Cache::Handle* handle = nullptr;
TableReader* table_reader = fd.table_reader; TableReader* table_reader = fd.table_reader;
if (table_reader == nullptr) { if (table_reader == nullptr) {
s = FindTable(env_options, icomparator, fd, &handle, s = FindTable(env_options, icomparator, fd, &handle, prefix_extractor,
options.read_tier == kBlockCacheTier /* no_io */, options.read_tier == kBlockCacheTier /* no_io */,
true /* record read_stats */, file_read_hist, skip_filters, true /* record read_stats */, file_read_hist, skip_filters,
level); level);
@@ -313,8 +317,10 @@ InternalIterator* TableCache::NewRangeTombstoneIterator(
Status TableCache::Get(const ReadOptions& options, Status TableCache::Get(const ReadOptions& options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& fd, const Slice& k, const FileDescriptor& fd, const Slice& k,
GetContext* get_context, HistogramImpl* file_read_hist, GetContext* get_context,
bool skip_filters, int level) { const SliceTransform* prefix_extractor,
HistogramImpl* file_read_hist, bool skip_filters,
int level) {
std::string* row_cache_entry = nullptr; std::string* row_cache_entry = nullptr;
bool done = false; bool done = false;
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
@@ -378,10 +384,10 @@ Status TableCache::Get(const ReadOptions& options,
Cache::Handle* handle = nullptr; Cache::Handle* handle = nullptr;
if (!done && s.ok()) { if (!done && s.ok()) {
if (t == nullptr) { if (t == nullptr) {
s = FindTable(env_options_, internal_comparator, fd, &handle, s = FindTable(
options.read_tier == kBlockCacheTier /* no_io */, env_options_, internal_comparator, fd, &handle, prefix_extractor,
true /* record_read_stats */, file_read_hist, skip_filters, options.read_tier == kBlockCacheTier /* no_io */,
level); true /* record_read_stats */, file_read_hist, skip_filters, level);
if (s.ok()) { if (s.ok()) {
t = GetTableReaderFromHandle(handle); t = GetTableReaderFromHandle(handle);
} }
@@ -400,7 +406,7 @@ Status TableCache::Get(const ReadOptions& options,
} }
if (s.ok()) { if (s.ok()) {
get_context->SetReplayLog(row_cache_entry); // nullptr if no cache. get_context->SetReplayLog(row_cache_entry); // nullptr if no cache.
s = t->Get(options, k, get_context, skip_filters); s = t->Get(options, k, get_context, prefix_extractor, skip_filters);
get_context->SetReplayLog(nullptr); get_context->SetReplayLog(nullptr);
} else if (options.read_tier == kBlockCacheTier && s.IsIncomplete()) { } else if (options.read_tier == kBlockCacheTier && s.IsIncomplete()) {
// Couldn't find Table in cache but treat as kFound if no_io set // Couldn't find Table in cache but treat as kFound if no_io set
@@ -430,7 +436,8 @@ Status TableCache::Get(const ReadOptions& options,
Status TableCache::GetTableProperties( Status TableCache::GetTableProperties(
const EnvOptions& env_options, const EnvOptions& env_options,
const InternalKeyComparator& internal_comparator, const FileDescriptor& fd, const InternalKeyComparator& internal_comparator, const FileDescriptor& fd,
std::shared_ptr<const TableProperties>* properties, bool no_io) { std::shared_ptr<const TableProperties>* properties,
const SliceTransform* prefix_extractor, bool no_io) {
Status s; Status s;
auto table_reader = fd.table_reader; auto table_reader = fd.table_reader;
// table already been pre-loaded? // table already been pre-loaded?
@@ -441,7 +448,8 @@ Status TableCache::GetTableProperties(
} }
Cache::Handle* table_handle = nullptr; Cache::Handle* table_handle = nullptr;
s = FindTable(env_options, internal_comparator, fd, &table_handle, no_io); s = FindTable(env_options, internal_comparator, fd, &table_handle,
prefix_extractor, no_io);
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
@@ -454,8 +462,8 @@ Status TableCache::GetTableProperties(
size_t TableCache::GetMemoryUsageByTableReader( size_t TableCache::GetMemoryUsageByTableReader(
const EnvOptions& env_options, const EnvOptions& env_options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator, const FileDescriptor& fd,
const FileDescriptor& fd) { const SliceTransform* prefix_extractor) {
Status s; Status s;
auto table_reader = fd.table_reader; auto table_reader = fd.table_reader;
// table already been pre-loaded? // table already been pre-loaded?
@@ -464,7 +472,8 @@ size_t TableCache::GetMemoryUsageByTableReader(
} }
Cache::Handle* table_handle = nullptr; Cache::Handle* table_handle = nullptr;
s = FindTable(env_options, internal_comparator, fd, &table_handle, true); s = FindTable(env_options, internal_comparator, fd, &table_handle,
prefix_extractor, true);
if (!s.ok()) { if (!s.ok()) {
return 0; return 0;
} }
+12 -4
View File
@@ -54,6 +54,7 @@ class TableCache {
const ReadOptions& options, const EnvOptions& toptions, const ReadOptions& options, const EnvOptions& toptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& file_fd, RangeDelAggregator* range_del_agg, const FileDescriptor& file_fd, RangeDelAggregator* range_del_agg,
const SliceTransform* prefix_extractor = nullptr,
TableReader** table_reader_ptr = nullptr, TableReader** table_reader_ptr = nullptr,
HistogramImpl* file_read_hist = nullptr, bool for_compaction = false, HistogramImpl* file_read_hist = nullptr, bool for_compaction = false,
Arena* arena = nullptr, bool skip_filters = false, int level = -1); Arena* arena = nullptr, bool skip_filters = false, int level = -1);
@@ -62,7 +63,8 @@ class TableCache {
const ReadOptions& options, const EnvOptions& toptions, const ReadOptions& options, const EnvOptions& toptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& file_fd, HistogramImpl* file_read_hist, const FileDescriptor& file_fd, HistogramImpl* file_read_hist,
bool skip_filters, int level); bool skip_filters, int level,
const SliceTransform* prefix_extractor = nullptr);
// If a seek to internal key "k" in specified file finds an entry, // If a seek to internal key "k" in specified file finds an entry,
// call (*handle_result)(arg, found_key, found_value) repeatedly until // call (*handle_result)(arg, found_key, found_value) repeatedly until
@@ -75,8 +77,10 @@ class TableCache {
Status Get(const ReadOptions& options, Status Get(const ReadOptions& options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& file_fd, const Slice& k, const FileDescriptor& file_fd, const Slice& k,
GetContext* get_context, HistogramImpl* file_read_hist = nullptr, GetContext* get_context,
bool skip_filters = false, int level = -1); const SliceTransform* prefix_extractor = nullptr,
HistogramImpl* file_read_hist = nullptr, bool skip_filters = false,
int level = -1);
// Evict any entry for the specified file number // Evict any entry for the specified file number
static void Evict(Cache* cache, uint64_t file_number); static void Evict(Cache* cache, uint64_t file_number);
@@ -91,6 +95,7 @@ class TableCache {
Status FindTable(const EnvOptions& toptions, Status FindTable(const EnvOptions& toptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& file_fd, Cache::Handle**, const FileDescriptor& file_fd, Cache::Handle**,
const SliceTransform* prefix_extractor = nullptr,
const bool no_io = false, bool record_read_stats = true, const bool no_io = false, bool record_read_stats = true,
HistogramImpl* file_read_hist = nullptr, HistogramImpl* file_read_hist = nullptr,
bool skip_filters = false, int level = -1, bool skip_filters = false, int level = -1,
@@ -109,6 +114,7 @@ class TableCache {
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& file_meta, const FileDescriptor& file_meta,
std::shared_ptr<const TableProperties>* properties, std::shared_ptr<const TableProperties>* properties,
const SliceTransform* prefix_extractor = nullptr,
bool no_io = false); bool no_io = false);
// Return total memory usage of the table reader of the file. // Return total memory usage of the table reader of the file.
@@ -116,7 +122,8 @@ class TableCache {
size_t GetMemoryUsageByTableReader( size_t GetMemoryUsageByTableReader(
const EnvOptions& toptions, const EnvOptions& toptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const FileDescriptor& fd); const FileDescriptor& fd,
const SliceTransform* prefix_extractor = nullptr);
// Release the handle from a cache // Release the handle from a cache
void ReleaseHandle(Cache::Handle* handle); void ReleaseHandle(Cache::Handle* handle);
@@ -133,6 +140,7 @@ class TableCache {
size_t readahead, bool record_read_stats, size_t readahead, bool record_read_stats,
HistogramImpl* file_read_hist, HistogramImpl* file_read_hist,
unique_ptr<TableReader>* table_reader, unique_ptr<TableReader>* table_reader,
const SliceTransform* prefix_extractor = nullptr,
bool skip_filters = false, int level = -1, bool skip_filters = false, int level = -1,
bool prefetch_index_and_filter_in_cache = true, bool prefetch_index_and_filter_in_cache = true,
bool for_compaction = false); bool for_compaction = false);
+9 -7
View File
@@ -39,6 +39,7 @@ static const uint32_t kTestColumnFamilyId = 66;
static const std::string kTestColumnFamilyName = "test_column_fam"; static const std::string kTestColumnFamilyName = "test_column_fam";
void MakeBuilder(const Options& options, const ImmutableCFOptions& ioptions, void MakeBuilder(const Options& options, const ImmutableCFOptions& ioptions,
const MutableCFOptions& moptions,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories, int_tbl_prop_collector_factories,
@@ -48,10 +49,9 @@ void MakeBuilder(const Options& options, const ImmutableCFOptions& ioptions,
writable->reset(new WritableFileWriter(std::move(wf), EnvOptions())); writable->reset(new WritableFileWriter(std::move(wf), EnvOptions()));
int unknown_level = -1; int unknown_level = -1;
builder->reset(NewTableBuilder( builder->reset(NewTableBuilder(
ioptions, internal_comparator, int_tbl_prop_collector_factories, ioptions, moptions, internal_comparator, int_tbl_prop_collector_factories,
kTestColumnFamilyId, kTestColumnFamilyName, kTestColumnFamilyId, kTestColumnFamilyName, writable->get(),
writable->get(), options.compression, options.compression_opts, options.compression, options.compression_opts, unknown_level));
unknown_level));
} }
} // namespace } // namespace
@@ -251,6 +251,7 @@ void TestCustomizedTablePropertiesCollector(
std::unique_ptr<TableBuilder> builder; std::unique_ptr<TableBuilder> builder;
std::unique_ptr<WritableFileWriter> writer; std::unique_ptr<WritableFileWriter> writer;
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
const MutableCFOptions moptions(options);
std::vector<std::unique_ptr<IntTblPropCollectorFactory>> std::vector<std::unique_ptr<IntTblPropCollectorFactory>>
int_tbl_prop_collector_factories; int_tbl_prop_collector_factories;
if (test_int_tbl_prop_collector) { if (test_int_tbl_prop_collector) {
@@ -259,7 +260,7 @@ void TestCustomizedTablePropertiesCollector(
} else { } else {
GetIntTblPropCollectorFactory(ioptions, &int_tbl_prop_collector_factories); GetIntTblPropCollectorFactory(ioptions, &int_tbl_prop_collector_factories);
} }
MakeBuilder(options, ioptions, internal_comparator, MakeBuilder(options, ioptions, moptions, internal_comparator,
&int_tbl_prop_collector_factories, &writer, &builder); &int_tbl_prop_collector_factories, &writer, &builder);
SequenceNumber seqNum = 0U; SequenceNumber seqNum = 0U;
@@ -401,10 +402,11 @@ void TestInternalKeyPropertiesCollector(
new InternalKeyPropertiesCollectorFactory); new InternalKeyPropertiesCollectorFactory);
} }
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
MutableCFOptions moptions(options);
for (int iter = 0; iter < 2; ++iter) { for (int iter = 0; iter < 2; ++iter) {
MakeBuilder(options, ioptions, pikc, &int_tbl_prop_collector_factories, MakeBuilder(options, ioptions, moptions, pikc,
&writable, &builder); &int_tbl_prop_collector_factories, &writable, &builder);
for (const auto& k : keys) { for (const auto& k : keys) {
builder->Add(k.Encode(), "val"); builder->Add(k.Encode(), "val");
} }
+13 -11
View File
@@ -368,7 +368,8 @@ class VersionBuilder::Rep {
} }
void LoadTableHandlers(InternalStats* internal_stats, int max_threads, void LoadTableHandlers(InternalStats* internal_stats, int max_threads,
bool prefetch_index_and_filter_in_cache) { bool prefetch_index_and_filter_in_cache,
const SliceTransform* prefix_extractor) {
assert(table_cache_ != nullptr); assert(table_cache_ != nullptr);
// <file metadata, level> // <file metadata, level>
std::vector<std::pair<FileMetaData*, int>> files_meta; std::vector<std::pair<FileMetaData*, int>> files_meta;
@@ -390,12 +391,12 @@ class VersionBuilder::Rep {
auto* file_meta = files_meta[file_idx].first; auto* file_meta = files_meta[file_idx].first;
int level = files_meta[file_idx].second; int level = files_meta[file_idx].second;
table_cache_->FindTable(env_options_, table_cache_->FindTable(
*(base_vstorage_->InternalComparator()), env_options_, *(base_vstorage_->InternalComparator()),
file_meta->fd, &file_meta->table_reader_handle, file_meta->fd, &file_meta->table_reader_handle, prefix_extractor,
false /*no_io */, true /* record_read_stats */, false /*no_io */, true /* record_read_stats */,
internal_stats->GetFileReadHist(level), false, internal_stats->GetFileReadHist(level), false, level,
level, prefetch_index_and_filter_in_cache); prefetch_index_and_filter_in_cache);
if (file_meta->table_reader_handle != nullptr) { if (file_meta->table_reader_handle != nullptr) {
// Load table_reader // Load table_reader
file_meta->fd.table_reader = table_cache_->GetTableReaderFromHandle( file_meta->fd.table_reader = table_cache_->GetTableReaderFromHandle(
@@ -455,11 +456,12 @@ void VersionBuilder::SaveTo(VersionStorageInfo* vstorage) {
rep_->SaveTo(vstorage); rep_->SaveTo(vstorage);
} }
void VersionBuilder::LoadTableHandlers( void VersionBuilder::LoadTableHandlers(InternalStats* internal_stats,
InternalStats* internal_stats, int max_threads, int max_threads,
bool prefetch_index_and_filter_in_cache) { bool prefetch_index_and_filter_in_cache,
const SliceTransform* prefix_extractor) {
rep_->LoadTableHandlers(internal_stats, max_threads, rep_->LoadTableHandlers(internal_stats, max_threads,
prefetch_index_and_filter_in_cache); prefetch_index_and_filter_in_cache, prefix_extractor);
} }
void VersionBuilder::MaybeAddFile(VersionStorageInfo* vstorage, int level, void VersionBuilder::MaybeAddFile(VersionStorageInfo* vstorage, int level,
+3 -1
View File
@@ -9,6 +9,7 @@
// //
#pragma once #pragma once
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "rocksdb/slice_transform.h"
namespace rocksdb { namespace rocksdb {
@@ -33,7 +34,8 @@ class VersionBuilder {
void Apply(VersionEdit* edit); void Apply(VersionEdit* edit);
void SaveTo(VersionStorageInfo* vstorage); void SaveTo(VersionStorageInfo* vstorage);
void LoadTableHandlers(InternalStats* internal_stats, int max_threads, void LoadTableHandlers(InternalStats* internal_stats, int max_threads,
bool prefetch_index_and_filter_in_cache); bool prefetch_index_and_filter_in_cache,
const SliceTransform* prefix_extractor);
void MaybeAddFile(VersionStorageInfo* vstorage, int level, FileMetaData* f); void MaybeAddFile(VersionStorageInfo* vstorage, int level, FileMetaData* f);
private: private:
+45 -25
View File
@@ -463,7 +463,8 @@ class LevelIterator final : public InternalIterator {
LevelIterator(TableCache* table_cache, const ReadOptions& read_options, LevelIterator(TableCache* table_cache, const ReadOptions& read_options,
const EnvOptions& env_options, const EnvOptions& env_options,
const InternalKeyComparator& icomparator, const InternalKeyComparator& icomparator,
const LevelFilesBrief* flevel, bool should_sample, const LevelFilesBrief* flevel,
const SliceTransform* prefix_extractor, bool should_sample,
HistogramImpl* file_read_hist, bool for_compaction, HistogramImpl* file_read_hist, bool for_compaction,
bool skip_filters, int level, RangeDelAggregator* range_del_agg) bool skip_filters, int level, RangeDelAggregator* range_del_agg)
: table_cache_(table_cache), : table_cache_(table_cache),
@@ -471,6 +472,7 @@ class LevelIterator final : public InternalIterator {
env_options_(env_options), env_options_(env_options),
icomparator_(icomparator), icomparator_(icomparator),
flevel_(flevel), flevel_(flevel),
prefix_extractor_(prefix_extractor),
file_read_hist_(file_read_hist), file_read_hist_(file_read_hist),
should_sample_(should_sample), should_sample_(should_sample),
for_compaction_(for_compaction), for_compaction_(for_compaction),
@@ -547,8 +549,9 @@ class LevelIterator final : public InternalIterator {
return table_cache_->NewIterator( return table_cache_->NewIterator(
read_options_, env_options_, icomparator_, file_meta.fd, range_del_agg_, read_options_, env_options_, icomparator_, file_meta.fd, range_del_agg_,
nullptr /* don't need reference to table */, file_read_hist_, prefix_extractor_, nullptr /* don't need reference to table */,
for_compaction_, nullptr /* arena */, skip_filters_, level_); file_read_hist_, for_compaction_, nullptr /* arena */, skip_filters_,
level_);
} }
TableCache* table_cache_; TableCache* table_cache_;
@@ -557,6 +560,7 @@ class LevelIterator final : public InternalIterator {
const InternalKeyComparator& icomparator_; const InternalKeyComparator& icomparator_;
const LevelFilesBrief* flevel_; const LevelFilesBrief* flevel_;
mutable FileDescriptor current_value_; mutable FileDescriptor current_value_;
const SliceTransform* prefix_extractor_;
HistogramImpl* file_read_hist_; HistogramImpl* file_read_hist_;
bool should_sample_; bool should_sample_;
@@ -722,8 +726,8 @@ Status Version::GetTableProperties(std::shared_ptr<const TableProperties>* tp,
auto table_cache = cfd_->table_cache(); auto table_cache = cfd_->table_cache();
auto ioptions = cfd_->ioptions(); auto ioptions = cfd_->ioptions();
Status s = table_cache->GetTableProperties( Status s = table_cache->GetTableProperties(
env_options_, cfd_->internal_comparator(), file_meta->fd, env_options_, cfd_->internal_comparator(), file_meta->fd, tp,
tp, true /* no io */); mutable_cf_options_.prefix_extractor.get(), true /* no io */);
if (s.ok()) { if (s.ok()) {
return s; return s;
} }
@@ -857,8 +861,8 @@ size_t Version::GetMemoryUsageByTableReaders() {
for (auto& file_level : storage_info_.level_files_brief_) { for (auto& file_level : storage_info_.level_files_brief_) {
for (size_t i = 0; i < file_level.num_files; i++) { for (size_t i = 0; i < file_level.num_files; i++) {
total_usage += cfd_->table_cache()->GetMemoryUsageByTableReader( total_usage += cfd_->table_cache()->GetMemoryUsageByTableReader(
env_options_, cfd_->internal_comparator(), env_options_, cfd_->internal_comparator(), file_level.files[i].fd,
file_level.files[i].fd); mutable_cf_options_.prefix_extractor.get());
} }
} }
return total_usage; return total_usage;
@@ -996,8 +1000,9 @@ void Version::AddIteratorsForLevel(const ReadOptions& read_options,
const auto& file = storage_info_.LevelFilesBrief(0).files[i]; const auto& file = storage_info_.LevelFilesBrief(0).files[i];
merge_iter_builder->AddIterator(cfd_->table_cache()->NewIterator( merge_iter_builder->AddIterator(cfd_->table_cache()->NewIterator(
read_options, soptions, cfd_->internal_comparator(), file.fd, read_options, soptions, cfd_->internal_comparator(), file.fd,
range_del_agg, nullptr, cfd_->internal_stats()->GetFileReadHist(0), range_del_agg, mutable_cf_options_.prefix_extractor.get(), nullptr,
false, arena, false /* skip_filters */, 0 /* level */)); cfd_->internal_stats()->GetFileReadHist(0), false, arena,
false /* skip_filters */, 0 /* level */));
} }
if (should_sample) { if (should_sample) {
// Count ones for every L0 files. This is done per iterator creation // Count ones for every L0 files. This is done per iterator creation
@@ -1016,7 +1021,7 @@ void Version::AddIteratorsForLevel(const ReadOptions& read_options,
merge_iter_builder->AddIterator(new (mem) LevelIterator( merge_iter_builder->AddIterator(new (mem) LevelIterator(
cfd_->table_cache(), read_options, soptions, cfd_->table_cache(), read_options, soptions,
cfd_->internal_comparator(), &storage_info_.LevelFilesBrief(level), cfd_->internal_comparator(), &storage_info_.LevelFilesBrief(level),
should_sample_file_read(), mutable_cf_options_.prefix_extractor.get(), should_sample_file_read(),
cfd_->internal_stats()->GetFileReadHist(level), cfd_->internal_stats()->GetFileReadHist(level),
false /* for_compaction */, IsFilterSkipped(level), level, false /* for_compaction */, IsFilterSkipped(level), level,
range_del_agg)); range_del_agg));
@@ -1048,8 +1053,9 @@ Status Version::OverlapWithLevelIterator(const ReadOptions& read_options,
} }
ScopedArenaIterator iter(cfd_->table_cache()->NewIterator( ScopedArenaIterator iter(cfd_->table_cache()->NewIterator(
read_options, env_options, cfd_->internal_comparator(), file->fd, read_options, env_options, cfd_->internal_comparator(), file->fd,
&range_del_agg, nullptr, cfd_->internal_stats()->GetFileReadHist(0), &range_del_agg, mutable_cf_options_.prefix_extractor.get(), nullptr,
false, &arena, false /* skip_filters */, 0 /* level */)); cfd_->internal_stats()->GetFileReadHist(0), false, &arena,
false /* skip_filters */, 0 /* level */));
status = OverlapWithIterator( status = OverlapWithIterator(
ucmp, smallest_user_key, largest_user_key, iter.get(), overlap); ucmp, smallest_user_key, largest_user_key, iter.get(), overlap);
if (!status.ok() || *overlap) { if (!status.ok() || *overlap) {
@@ -1061,7 +1067,7 @@ Status Version::OverlapWithLevelIterator(const ReadOptions& read_options,
ScopedArenaIterator iter(new (mem) LevelIterator( ScopedArenaIterator iter(new (mem) LevelIterator(
cfd_->table_cache(), read_options, env_options, cfd_->table_cache(), read_options, env_options,
cfd_->internal_comparator(), &storage_info_.LevelFilesBrief(level), cfd_->internal_comparator(), &storage_info_.LevelFilesBrief(level),
should_sample_file_read(), mutable_cf_options_.prefix_extractor.get(), should_sample_file_read(),
cfd_->internal_stats()->GetFileReadHist(level), cfd_->internal_stats()->GetFileReadHist(level),
false /* for_compaction */, IsFilterSkipped(level), level, false /* for_compaction */, IsFilterSkipped(level), level,
&range_del_agg)); &range_del_agg));
@@ -1122,7 +1128,9 @@ VersionStorageInfo::VersionStorageInfo(
} }
Version::Version(ColumnFamilyData* column_family_data, VersionSet* vset, Version::Version(ColumnFamilyData* column_family_data, VersionSet* vset,
const EnvOptions& env_opt, uint64_t version_number) const EnvOptions& env_opt,
const MutableCFOptions mutable_cf_options,
uint64_t version_number)
: env_(vset->env_), : env_(vset->env_),
cfd_(column_family_data), cfd_(column_family_data),
info_log_((cfd_ == nullptr) ? nullptr : cfd_->ioptions()->info_log), info_log_((cfd_ == nullptr) ? nullptr : cfd_->ioptions()->info_log),
@@ -1146,6 +1154,7 @@ Version::Version(ColumnFamilyData* column_family_data, VersionSet* vset,
prev_(this), prev_(this),
refs_(0), refs_(0),
env_options_(env_opt), env_options_(env_opt),
mutable_cf_options_(mutable_cf_options),
version_number_(version_number) {} version_number_(version_number) {}
void Version::Get(const ReadOptions& read_options, const LookupKey& k, void Version::Get(const ReadOptions& read_options, const LookupKey& k,
@@ -1189,6 +1198,7 @@ void Version::Get(const ReadOptions& read_options, const LookupKey& k,
*status = table_cache_->Get( *status = table_cache_->Get(
read_options, *internal_comparator(), f->fd, ikey, &get_context, read_options, *internal_comparator(), f->fd, ikey, &get_context,
mutable_cf_options_.prefix_extractor.get(),
cfd_->internal_stats()->GetFileReadHist(fp.GetHitFileLevel()), cfd_->internal_stats()->GetFileReadHist(fp.GetHitFileLevel()),
IsFilterSkipped(static_cast<int>(fp.GetHitFileLevel()), IsFilterSkipped(static_cast<int>(fp.GetHitFileLevel()),
fp.IsHitFileLastInLevel()), fp.IsHitFileLastInLevel()),
@@ -2775,7 +2785,7 @@ Status VersionSet::LogAndApply(ColumnFamilyData* column_family_data,
LogAndApplyCFHelper(w.edit_list.front()); LogAndApplyCFHelper(w.edit_list.front());
batch_edits.push_back(w.edit_list.front()); batch_edits.push_back(w.edit_list.front());
} else { } else {
v = new Version(column_family_data, this, env_options_, v = new Version(column_family_data, this, env_options_, mutable_cf_options,
current_version_number_++); current_version_number_++);
builder_guard.reset(new BaseReferencedVersionBuilder(column_family_data)); builder_guard.reset(new BaseReferencedVersionBuilder(column_family_data));
auto* builder = builder_guard->version_builder(); auto* builder = builder_guard->version_builder();
@@ -2836,7 +2846,8 @@ Status VersionSet::LogAndApply(ColumnFamilyData* column_family_data,
builder_guard->version_builder()->LoadTableHandlers( builder_guard->version_builder()->LoadTableHandlers(
column_family_data->internal_stats(), column_family_data->internal_stats(),
column_family_data->ioptions()->optimize_filters_for_hits, column_family_data->ioptions()->optimize_filters_for_hits,
true /* prefetch_index_and_filter_in_cache */); true /* prefetch_index_and_filter_in_cache */,
mutable_cf_options.prefix_extractor.get());
} }
// This is fine because everything inside of this block is serialized -- // This is fine because everything inside of this block is serialized --
@@ -3327,11 +3338,13 @@ Status VersionSet::Recover(
// Need to do it out of the mutex. // Need to do it out of the mutex.
builder->LoadTableHandlers( builder->LoadTableHandlers(
cfd->internal_stats(), db_options_->max_file_opening_threads, cfd->internal_stats(), db_options_->max_file_opening_threads,
false /* prefetch_index_and_filter_in_cache */); false /* prefetch_index_and_filter_in_cache */,
cfd->GetLatestMutableCFOptions()->prefix_extractor.get());
} }
Version* v = Version* v = new Version(cfd, this, env_options_,
new Version(cfd, this, env_options_, current_version_number_++); *cfd->GetLatestMutableCFOptions(),
current_version_number_++);
builder->SaveTo(v->storage_info()); builder->SaveTo(v->storage_info());
// Install recovered version // Install recovered version
@@ -3696,8 +3709,9 @@ Status VersionSet::DumpManifest(Options& options, std::string& dscname,
assert(builders_iter != builders.end()); assert(builders_iter != builders.end());
auto builder = builders_iter->second->version_builder(); auto builder = builders_iter->second->version_builder();
Version* v = Version* v = new Version(cfd, this, env_options_,
new Version(cfd, this, env_options_, current_version_number_++); *cfd->GetLatestMutableCFOptions(),
current_version_number_++);
builder->SaveTo(v->storage_info()); builder->SaveTo(v->storage_info());
v->PrepareApply(*cfd->GetLatestMutableCFOptions(), false); v->PrepareApply(*cfd->GetLatestMutableCFOptions(), false);
@@ -3920,7 +3934,8 @@ uint64_t VersionSet::ApproximateSize(Version* v, const FdWithKeyRange& f,
TableReader* table_reader_ptr; TableReader* table_reader_ptr;
InternalIterator* iter = v->cfd_->table_cache()->NewIterator( InternalIterator* iter = v->cfd_->table_cache()->NewIterator(
ReadOptions(), v->env_options_, v->cfd_->internal_comparator(), f.fd, ReadOptions(), v->env_options_, v->cfd_->internal_comparator(), f.fd,
nullptr /* range_del_agg */, &table_reader_ptr); nullptr /* range_del_agg */,
v->GetMutableCFOptions().prefix_extractor.get(), &table_reader_ptr);
if (table_reader_ptr != nullptr) { if (table_reader_ptr != nullptr) {
result = table_reader_ptr->ApproximateOffsetOf(key); result = table_reader_ptr->ApproximateOffsetOf(key);
} }
@@ -4000,6 +4015,7 @@ InternalIterator* VersionSet::MakeInputIterator(
list[num++] = cfd->table_cache()->NewIterator( list[num++] = cfd->table_cache()->NewIterator(
read_options, env_options_compactions, cfd->internal_comparator(), read_options, env_options_compactions, cfd->internal_comparator(),
flevel->files[i].fd, range_del_agg, flevel->files[i].fd, range_del_agg,
c->mutable_cf_options()->prefix_extractor.get(),
nullptr /* table_reader_ptr */, nullptr /* table_reader_ptr */,
nullptr /* no per level latency histogram */, nullptr /* no per level latency histogram */,
true /* for_compaction */, nullptr /* arena */, true /* for_compaction */, nullptr /* arena */,
@@ -4010,6 +4026,7 @@ InternalIterator* VersionSet::MakeInputIterator(
list[num++] = new LevelIterator( list[num++] = new LevelIterator(
cfd->table_cache(), read_options, env_options_compactions, cfd->table_cache(), read_options, env_options_compactions,
cfd->internal_comparator(), c->input_levels(which), cfd->internal_comparator(), c->input_levels(which),
c->mutable_cf_options()->prefix_extractor.get(),
false /* should_sample */, false /* should_sample */,
nullptr /* no per level latency histogram */, nullptr /* no per level latency histogram */,
true /* for_compaction */, false /* skip_filters */, true /* for_compaction */, false /* skip_filters */,
@@ -4149,7 +4166,9 @@ ColumnFamilyData* VersionSet::CreateColumnFamily(
const ColumnFamilyOptions& cf_options, VersionEdit* edit) { const ColumnFamilyOptions& cf_options, VersionEdit* edit) {
assert(edit->is_column_family_add_); assert(edit->is_column_family_add_);
Version* dummy_versions = new Version(nullptr, this, env_options_); MutableCFOptions dummy_cf_options;
Version* dummy_versions =
new Version(nullptr, this, env_options_, dummy_cf_options);
// Ref() dummy version once so that later we can call Unref() to delete it // Ref() dummy version once so that later we can call Unref() to delete it
// by avoiding calling "delete" explicitly (~Version is private) // by avoiding calling "delete" explicitly (~Version is private)
dummy_versions->Ref(); dummy_versions->Ref();
@@ -4157,8 +4176,9 @@ ColumnFamilyData* VersionSet::CreateColumnFamily(
edit->column_family_name_, edit->column_family_, dummy_versions, edit->column_family_name_, edit->column_family_, dummy_versions,
cf_options); cf_options);
Version* v = Version* v = new Version(new_cfd, this, env_options_,
new Version(new_cfd, this, env_options_, current_version_number_++); *new_cfd->GetLatestMutableCFOptions(),
current_version_number_++);
// Fill level target base information. // Fill level target base information.
v->storage_info()->CalculateBaseBytes(*new_cfd->ioptions(), v->storage_info()->CalculateBaseBytes(*new_cfd->ioptions(),
+4 -1
View File
@@ -633,6 +633,8 @@ class Version {
uint64_t GetSstFilesSize(); uint64_t GetSstFilesSize();
MutableCFOptions GetMutableCFOptions() { return mutable_cf_options_; }
private: private:
Env* env_; Env* env_;
friend class VersionSet; friend class VersionSet;
@@ -680,13 +682,14 @@ class Version {
Version* prev_; // Previous version in linked list Version* prev_; // Previous version in linked list
int refs_; // Number of live refs to this version int refs_; // Number of live refs to this version
const EnvOptions env_options_; const EnvOptions env_options_;
const MutableCFOptions mutable_cf_options_;
// A version number that uniquely represents this version. This is // A version number that uniquely represents this version. This is
// used for debugging and logging purposes only. // used for debugging and logging purposes only.
uint64_t version_number_; uint64_t version_number_;
Version(ColumnFamilyData* cfd, VersionSet* vset, const EnvOptions& env_opt, Version(ColumnFamilyData* cfd, VersionSet* vset, const EnvOptions& env_opt,
uint64_t version_number = 0); MutableCFOptions mutable_cf_options, uint64_t version_number = 0);
~Version(); ~Version();
+1
View File
@@ -138,6 +138,7 @@
block_restart_interval=16 block_restart_interval=16
cache_index_and_filter_blocks=false cache_index_and_filter_blocks=false
pin_l0_filter_and_index_blocks_in_cache=false pin_l0_filter_and_index_blocks_in_cache=false
pin_top_level_index_and_filter=false
index_type=kBinarySearch index_type=kBinarySearch
hash_index_allow_collision=true hash_index_allow_collision=true
flush_block_policy_factory=FlushBlockBySizePolicyFactory flush_block_policy_factory=FlushBlockBySizePolicyFactory
+3
View File
@@ -692,6 +692,9 @@ rocksdb_block_based_options_set_cache_index_and_filter_blocks_with_high_priority
extern ROCKSDB_LIBRARY_API void extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache( rocksdb_block_based_options_set_pin_l0_filter_and_index_blocks_in_cache(
rocksdb_block_based_table_options_t*, unsigned char); 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( extern ROCKSDB_LIBRARY_API void rocksdb_options_set_block_based_table_factory(
rocksdb_options_t* opt, rocksdb_block_based_table_options_t* table_options); rocksdb_options_t* opt, rocksdb_block_based_table_options_t* table_options);
+3 -2
View File
@@ -98,12 +98,13 @@ class SstFileManager {
// DeleteScheduler immediately // DeleteScheduler immediately
// @param bytes_max_delete_chunk: if a single file is larger than delete chunk, // @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 // ftruncate the file by this size each time, rather than dropping the whole
// file. 0 means to always delete the whole file. // 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.
extern SstFileManager* NewSstFileManager( extern SstFileManager* NewSstFileManager(
Env* env, std::shared_ptr<Logger> info_log = nullptr, Env* env, std::shared_ptr<Logger> info_log = nullptr,
std::string trash_dir = "", int64_t rate_bytes_per_sec = 0, std::string trash_dir = "", int64_t rate_bytes_per_sec = 0,
bool delete_existing_trash = true, Status* status = nullptr, bool delete_existing_trash = true, Status* status = nullptr,
double max_trash_db_ratio = 0.25, double max_trash_db_ratio = 0.25,
uint64_t bytes_max_delete_chunk = 64 * 1024 * 1024); uint64_t bytes_max_delete_chunk = 0);
} // namespace rocksdb } // namespace rocksdb
+12 -2
View File
@@ -77,6 +77,13 @@ struct BlockBasedTableOptions {
// evicted from cache when the table reader is freed. // evicted from cache when the table reader is freed.
bool pin_l0_filter_and_index_blocks_in_cache = false; 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. // The index type that will be used for this table.
enum IndexType : char { enum IndexType : char {
// A space efficient index block that is optimized for // A space efficient index block that is optimized for
@@ -214,8 +221,11 @@ struct BlockBasedTableOptions {
// encode compressed blocks with LZ4, BZip2 and Zlib compression. If you // 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 // don't plan to run RocksDB before version 3.10, you should probably use
// this. // this.
// This option only affects newly written tables. When reading existing tables, // 3 -- Can be read by RocksDB's versions since 5.15. Changes the way we
// the information about version is read from the footer. // 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.
uint32_t format_version = 2; uint32_t format_version = 2;
// Store index blocks on disk in compressed format. Changing this option to // Store index blocks on disk in compressed format. Changing this option to
+4
View File
@@ -33,6 +33,7 @@ struct TablePropertiesNames {
static const std::string kIndexSize; static const std::string kIndexSize;
static const std::string kIndexPartitions; static const std::string kIndexPartitions;
static const std::string kTopLevelIndexSize; static const std::string kTopLevelIndexSize;
static const std::string kIndexKeyIsUserKey;
static const std::string kFilterSize; static const std::string kFilterSize;
static const std::string kRawKeySize; static const std::string kRawKeySize;
static const std::string kRawValueSize; static const std::string kRawValueSize;
@@ -134,6 +135,9 @@ struct TableProperties {
uint64_t index_partitions = 0; uint64_t index_partitions = 0;
// Size of the top-level index if kTwoLevelIndexSearch is used // Size of the top-level index if kTwoLevelIndexSearch is used
uint64_t top_level_index_size = 0; 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. // the size of filter block.
uint64_t filter_size = 0; uint64_t filter_size = 0;
// total raw key size // total raw key size
+15 -3
View File
@@ -137,6 +137,15 @@ struct TransactionOptions {
// The maximum number of bytes used for the write batch. 0 means no limit. // The maximum number of bytes used for the write batch. 0 means no limit.
size_t max_write_batch_size = 0; 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 // The per-write optimizations that do not involve transactions. TransactionDB
@@ -169,12 +178,15 @@ struct DeadlockInfo {
struct DeadlockPath { struct DeadlockPath {
std::vector<DeadlockInfo> path; std::vector<DeadlockInfo> path;
bool limit_exceeded; bool limit_exceeded;
int64_t deadlock_time;
explicit DeadlockPath(std::vector<DeadlockInfo> path_entry) explicit DeadlockPath(
: path(path_entry), limit_exceeded(false) {} std::vector<DeadlockInfo> path_entry, const int64_t& dl_time)
: path(path_entry), limit_exceeded(false), deadlock_time(dl_time) {}
// empty path, limit exceeded constructor and default constructor // empty path, limit exceeded constructor and default constructor
explicit DeadlockPath(bool limit = false) : path(0), limit_exceeded(limit) {} explicit DeadlockPath(const int64_t& dl_time = 0, bool limit = false)
: path(0), limit_exceeded(limit), deadlock_time(dl_time) {}
bool empty() { return path.empty() && !limit_exceeded; } bool empty() { return path.empty() && !limit_exceeded; }
}; };
+1 -1
View File
@@ -6,7 +6,7 @@
#define ROCKSDB_MAJOR 5 #define ROCKSDB_MAJOR 5
#define ROCKSDB_MINOR 14 #define ROCKSDB_MINOR 14
#define ROCKSDB_PATCH 0 #define ROCKSDB_PATCH 4
// Do not use these. We made the mistake of declaring macros starting with // 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 // 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, JNIEnv* /*env*/, jobject /*jobj*/, jlong jopt_handle,
jlong jcompactionfilterfactory_handle) { jlong jcompactionfilterfactory_handle) {
auto* cff_factory = auto* cff_factory =
reinterpret_cast<std::shared_ptr<rocksdb::CompactionFilterFactory>*>( reinterpret_cast<std::shared_ptr<rocksdb::CompactionFilterFactoryJniCallback>*>(
jcompactionfilterfactory_handle); jcompactionfilterfactory_handle);
reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jopt_handle) reinterpret_cast<rocksdb::ColumnFamilyOptions*>(jopt_handle)
->compaction_filter_factory = *cff_factory; ->compaction_filter_factory = *cff_factory;
+49 -34
View File
@@ -4292,25 +4292,12 @@ class JniUtil {
* @param bytes The bytes to copy * @param bytes The bytes to copy
* *
* @return the Java byte[] or nullptr if an exception occurs * @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) { static jbyteArray copyBytes(JNIEnv* env, std::string bytes) {
const jsize jlen = static_cast<jsize>(bytes.size()); return createJavaByteArrayWithSizeCheck(env, bytes.c_str(), 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;
} }
/** /**
@@ -4473,6 +4460,47 @@ class JniUtil {
return jbyte_strings; 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 * Copies bytes from a rocksdb::Slice to a jByteArray
@@ -4481,25 +4509,12 @@ class JniUtil {
* @param bytes The bytes to copy * @param bytes The bytes to copy
* *
* @return the Java byte[] or nullptr if an exception occurs * @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) { static jbyteArray copyBytes(JNIEnv* env, const Slice& bytes) {
const jsize jlen = static_cast<jsize>(bytes.size()); return createJavaByteArrayWithSizeCheck(env, bytes.data(), 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> const rocksdb::HashMapJni::FnMapKV<const std::string, const uint64_t>
fn_map_kv = fn_map_kv =
[env, &tracked_files]( [env](
const std::pair<const std::string, const uint64_t>& pair) { const std::pair<const std::string, const uint64_t>& pair) {
const jstring jtracked_file_path = const jstring jtracked_file_path =
env->NewStringUTF(pair.first.c_str()); 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) { jlong jtxn_notifier_handle) {
auto* txn = reinterpret_cast<rocksdb::Transaction*>(jhandle); auto* txn = reinterpret_cast<rocksdb::Transaction*>(jhandle);
auto* txn_notifier = auto* txn_notifier =
reinterpret_cast<std::shared_ptr<rocksdb::TransactionNotifier>*>( reinterpret_cast<std::shared_ptr<rocksdb::TransactionNotifierJniCallback>*>(
jtxn_notifier_handle); jtxn_notifier_handle);
txn->SetSnapshotOnNextOperation(*txn_notifier); txn->SetSnapshotOnNextOperation(*txn_notifier);
} }
+1 -1
View File
@@ -309,7 +309,7 @@ jobject Java_org_rocksdb_TransactionDB_getLockStatusData(JNIEnv* env,
const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo> const rocksdb::HashMapJni::FnMapKV<const int32_t, const rocksdb::KeyLockInfo>
fn_map_kv = fn_map_kv =
[env, txn_db, &lock_status_data]( [env](
const std::pair<const int32_t, const rocksdb::KeyLockInfo>& const std::pair<const int32_t, const rocksdb::KeyLockInfo>&
pair) { pair) {
const jobject jlong_column_family_id = const jobject jlong_column_family_id =
@@ -28,8 +28,10 @@ public class ColumnFamilyHandle extends RocksObject {
* Gets the name of the Column Family. * Gets the name of the Column Family.
* *
* @return 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() { public byte[] getName() throws RocksDBException {
return getName(nativeHandle_); return getName(nativeHandle_);
} }
@@ -71,14 +73,22 @@ public class ColumnFamilyHandle extends RocksObject {
} }
final ColumnFamilyHandle that = (ColumnFamilyHandle) o; final ColumnFamilyHandle that = (ColumnFamilyHandle) o;
return rocksDB_.nativeHandle_ == that.rocksDB_.nativeHandle_ && try {
getID() == that.getID() && return rocksDB_.nativeHandle_ == that.rocksDB_.nativeHandle_ &&
Arrays.equals(getName(), that.getName()); getID() == that.getID() &&
Arrays.equals(getName(), that.getName());
} catch (RocksDBException e) {
throw new RuntimeException("Cannot compare column family handles", e);
}
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(getName(), getID(), rocksDB_.nativeHandle_); try {
return Objects.hash(getName(), getID(), rocksDB_.nativeHandle_);
} catch (RocksDBException e) {
throw new RuntimeException("Cannot calculate hash code of column family handle", e);
}
} }
/** /**
@@ -96,7 +106,7 @@ public class ColumnFamilyHandle extends RocksObject {
} }
} }
private native byte[] getName(final long handle); private native byte[] getName(final long handle) throws RocksDBException;
private native int getID(final long handle); private native int getID(final long handle);
private native ColumnFamilyDescriptor getDescriptor(final long handle) throws RocksDBException; private native ColumnFamilyDescriptor getDescriptor(final long handle) throws RocksDBException;
@Override protected final native void disposeInternal(final long handle); @Override protected final native void disposeInternal(final long handle);
@@ -65,8 +65,11 @@ public class WriteBatch extends AbstractWriteBatch {
* Retrieve the serialized version of this batch. * Retrieve the serialized version of this batch.
* *
* @return the serialized representation of this write batch. * @return the serialized representation of this write batch.
*
* @throws RocksDBException if an error occurs whilst retrieving
* the serialized batch data.
*/ */
public byte[] data() { public byte[] data() throws RocksDBException {
return data(nativeHandle_); return data(nativeHandle_);
} }
@@ -253,7 +256,7 @@ public class WriteBatch extends AbstractWriteBatch {
final int serializedLength); final int serializedLength);
private native void iterate(final long handle, final long handlerHandle) private native void iterate(final long handle, final long handlerHandle)
throws RocksDBException; throws RocksDBException;
private native byte[] data(final long nativeHandle); private native byte[] data(final long nativeHandle) throws RocksDBException;
private native long getDataSize(final long nativeHandle); private native long getDataSize(final long nativeHandle);
private native boolean hasPut(final long nativeHandle); private native boolean hasPut(final long nativeHandle);
private native boolean hasDelete(final long nativeHandle); private native boolean hasDelete(final long nativeHandle);
@@ -4,9 +4,11 @@
// (found in the LICENSE.Apache file in the root directory). // (found in the LICENSE.Apache file in the root directory).
package org.rocksdb; package org.rocksdb;
import org.junit.Assume;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import java.util.*; import java.util.*;
@@ -143,6 +145,39 @@ 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 @Test
public void multiGet() throws RocksDBException, InterruptedException { public void multiGet() throws RocksDBException, InterruptedException {
try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath()); try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
+6 -1
View File
@@ -27,7 +27,6 @@ ImmutableCFOptions::ImmutableCFOptions(const ImmutableDBOptions& db_options,
const ColumnFamilyOptions& cf_options) const ColumnFamilyOptions& cf_options)
: compaction_style(cf_options.compaction_style), : compaction_style(cf_options.compaction_style),
compaction_pri(cf_options.compaction_pri), compaction_pri(cf_options.compaction_pri),
prefix_extractor(cf_options.prefix_extractor.get()),
user_comparator(cf_options.comparator), user_comparator(cf_options.comparator),
internal_comparator(InternalKeyComparator(cf_options.comparator)), internal_comparator(InternalKeyComparator(cf_options.comparator)),
merge_operator(cf_options.merge_operator.get()), merge_operator(cf_options.merge_operator.get()),
@@ -143,6 +142,9 @@ void MutableCFOptions::Dump(Logger* log) const {
ROCKS_LOG_INFO(log, ROCKS_LOG_INFO(log,
" inplace_update_num_locks: %" ROCKSDB_PRIszt, " inplace_update_num_locks: %" ROCKSDB_PRIszt,
inplace_update_num_locks); inplace_update_num_locks);
ROCKS_LOG_INFO(
log, " prefix_extractor: %s",
prefix_extractor == nullptr ? "nullptr" : prefix_extractor->Name());
ROCKS_LOG_INFO(log, " disable_auto_compactions: %d", ROCKS_LOG_INFO(log, " disable_auto_compactions: %d",
disable_auto_compactions); disable_auto_compactions);
ROCKS_LOG_INFO(log, " soft_pending_compaction_bytes_limit: %" PRIu64, ROCKS_LOG_INFO(log, " soft_pending_compaction_bytes_limit: %" PRIu64,
@@ -189,4 +191,7 @@ void MutableCFOptions::Dump(Logger* log) const {
static_cast<int>(compression)); static_cast<int>(compression));
} }
MutableCFOptions::MutableCFOptions(const Options& options)
: MutableCFOptions(ColumnFamilyOptions(options)) {}
} // namespace rocksdb } // namespace rocksdb
+5 -2
View File
@@ -30,8 +30,6 @@ struct ImmutableCFOptions {
CompactionPri compaction_pri; CompactionPri compaction_pri;
const SliceTransform* prefix_extractor;
const Comparator* user_comparator; const Comparator* user_comparator;
InternalKeyComparator internal_comparator; InternalKeyComparator internal_comparator;
@@ -134,6 +132,7 @@ struct MutableCFOptions {
memtable_huge_page_size(options.memtable_huge_page_size), memtable_huge_page_size(options.memtable_huge_page_size),
max_successive_merges(options.max_successive_merges), max_successive_merges(options.max_successive_merges),
inplace_update_num_locks(options.inplace_update_num_locks), inplace_update_num_locks(options.inplace_update_num_locks),
prefix_extractor(options.prefix_extractor),
disable_auto_compactions(options.disable_auto_compactions), disable_auto_compactions(options.disable_auto_compactions),
soft_pending_compaction_bytes_limit( soft_pending_compaction_bytes_limit(
options.soft_pending_compaction_bytes_limit), options.soft_pending_compaction_bytes_limit),
@@ -168,6 +167,7 @@ struct MutableCFOptions {
memtable_huge_page_size(0), memtable_huge_page_size(0),
max_successive_merges(0), max_successive_merges(0),
inplace_update_num_locks(0), inplace_update_num_locks(0),
prefix_extractor(nullptr),
disable_auto_compactions(false), disable_auto_compactions(false),
soft_pending_compaction_bytes_limit(0), soft_pending_compaction_bytes_limit(0),
hard_pending_compaction_bytes_limit(0), hard_pending_compaction_bytes_limit(0),
@@ -185,6 +185,8 @@ struct MutableCFOptions {
report_bg_io_stats(false), report_bg_io_stats(false),
compression(Snappy_Supported() ? kSnappyCompression : kNoCompression) {} compression(Snappy_Supported() ? kSnappyCompression : kNoCompression) {}
explicit MutableCFOptions(const Options& options);
// Must be called after any change to MutableCFOptions // Must be called after any change to MutableCFOptions
void RefreshDerivedOptions(int num_levels, CompactionStyle compaction_style); void RefreshDerivedOptions(int num_levels, CompactionStyle compaction_style);
@@ -210,6 +212,7 @@ struct MutableCFOptions {
size_t memtable_huge_page_size; size_t memtable_huge_page_size;
size_t max_successive_merges; size_t max_successive_merges;
size_t inplace_update_num_locks; size_t inplace_update_num_locks;
std::shared_ptr<const SliceTransform> prefix_extractor;
// Compaction related options // Compaction related options
bool disable_auto_compactions; bool disable_auto_compactions;
+8 -2
View File
@@ -145,6 +145,7 @@ ColumnFamilyOptions BuildColumnFamilyOptions(
cf_opts.max_successive_merges = mutable_cf_options.max_successive_merges; cf_opts.max_successive_merges = mutable_cf_options.max_successive_merges;
cf_opts.inplace_update_num_locks = cf_opts.inplace_update_num_locks =
mutable_cf_options.inplace_update_num_locks; mutable_cf_options.inplace_update_num_locks;
cf_opts.prefix_extractor = mutable_cf_options.prefix_extractor;
// Compaction related options // Compaction related options
cf_opts.disable_auto_compactions = cf_opts.disable_auto_compactions =
@@ -383,7 +384,8 @@ bool ParseSliceTransformHelper(
const std::string& kFixedPrefixName, const std::string& kCappedPrefixName, const std::string& kFixedPrefixName, const std::string& kCappedPrefixName,
const std::string& value, const std::string& value,
std::shared_ptr<const SliceTransform>* slice_transform) { std::shared_ptr<const SliceTransform>* slice_transform) {
const char* no_op_name = "rocksdb.Noop";
size_t no_op_length = strlen(no_op_name);
auto& pe_value = value; auto& pe_value = value;
if (pe_value.size() > kFixedPrefixName.size() && if (pe_value.size() > kFixedPrefixName.size() &&
pe_value.compare(0, kFixedPrefixName.size(), kFixedPrefixName) == 0) { pe_value.compare(0, kFixedPrefixName.size(), kFixedPrefixName) == 0) {
@@ -395,6 +397,10 @@ bool ParseSliceTransformHelper(
int prefix_length = int prefix_length =
ParseInt(trim(pe_value.substr(kCappedPrefixName.size()))); ParseInt(trim(pe_value.substr(kCappedPrefixName.size())));
slice_transform->reset(NewCappedPrefixTransform(prefix_length)); slice_transform->reset(NewCappedPrefixTransform(prefix_length));
} else if (pe_value.size() == no_op_length &&
pe_value.compare(0, no_op_length, no_op_name) == 0) {
const SliceTransform* no_op_transform = NewNoopTransform();
slice_transform->reset(no_op_transform);
} else if (value == kNullptrString) { } else if (value == kNullptrString) {
slice_transform->reset(); slice_transform->reset();
} else { } else {
@@ -1791,7 +1797,7 @@ std::unordered_map<std::string, OptionTypeInfo>
{"prefix_extractor", {"prefix_extractor",
{offset_of(&ColumnFamilyOptions::prefix_extractor), {offset_of(&ColumnFamilyOptions::prefix_extractor),
OptionType::kSliceTransform, OptionVerificationType::kByNameAllowNull, OptionType::kSliceTransform, OptionVerificationType::kByNameAllowNull,
false, 0}}, true, offsetof(struct MutableCFOptions, prefix_extractor)}},
{"memtable_insert_with_hint_prefix_extractor", {"memtable_insert_with_hint_prefix_extractor",
{offset_of( {offset_of(
&ColumnFamilyOptions::memtable_insert_with_hint_prefix_extractor), &ColumnFamilyOptions::memtable_insert_with_hint_prefix_extractor),
+1
View File
@@ -140,6 +140,7 @@ TEST_F(OptionsSettableTest, BlockBasedTableOptionsAllFieldsSettable) {
"cache_index_and_filter_blocks=1;" "cache_index_and_filter_blocks=1;"
"cache_index_and_filter_blocks_with_high_priority=true;" "cache_index_and_filter_blocks_with_high_priority=true;"
"pin_l0_filter_and_index_blocks_in_cache=1;" "pin_l0_filter_and_index_blocks_in_cache=1;"
"pin_top_level_index_and_filter=1;"
"index_type=kHashSearch;" "index_type=kHashSearch;"
"checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;" "checksum=kxxHash;hash_index_allow_collision=1;no_block_cache=1;"
"block_cache=1M;block_cache_compressed=1k;block_size=1024;" "block_cache=1M;block_cache_compressed=1k;block_size=1024;"
+46 -16
View File
@@ -87,7 +87,11 @@ void BlockIter::Prev() {
const Slice current_key(key_ptr, current_prev_entry.key_size); const Slice current_key(key_ptr, current_prev_entry.key_size);
current_ = current_prev_entry.offset; current_ = current_prev_entry.offset;
key_.SetInternalKey(current_key, false /* copy */); if (key_includes_seq_) {
key_.SetInternalKey(current_key, false /* copy */);
} else {
key_.SetUserKey(current_key, false /* copy */);
}
value_ = current_prev_entry.value; value_ = current_prev_entry.value;
return; return;
@@ -136,6 +140,10 @@ void BlockIter::Prev() {
} }
void BlockIter::Seek(const Slice& target) { void BlockIter::Seek(const Slice& target) {
Slice seek_key = target;
if (!key_includes_seq_) {
seek_key = ExtractUserKey(target);
}
PERF_TIMER_GUARD(block_seek_nanos); PERF_TIMER_GUARD(block_seek_nanos);
if (data_ == nullptr) { // Not init yet if (data_ == nullptr) { // Not init yet
return; return;
@@ -145,7 +153,7 @@ void BlockIter::Seek(const Slice& target) {
if (prefix_index_) { if (prefix_index_) {
ok = PrefixSeek(target, &index); ok = PrefixSeek(target, &index);
} else { } else {
ok = BinarySeek(target, 0, num_restarts_ - 1, &index); ok = BinarySeek(seek_key, 0, num_restarts_ - 1, &index);
} }
if (!ok) { if (!ok) {
@@ -155,7 +163,7 @@ void BlockIter::Seek(const Slice& target) {
// Linear search (within restart block) for first key >= target // Linear search (within restart block) for first key >= target
while (true) { while (true) {
if (!ParseNextKey() || Compare(key_.GetInternalKey(), target) >= 0) { if (!ParseNextKey() || Compare(key_, seek_key) >= 0) {
return; return;
} }
} }
@@ -163,24 +171,28 @@ void BlockIter::Seek(const Slice& target) {
void BlockIter::SeekForPrev(const Slice& target) { void BlockIter::SeekForPrev(const Slice& target) {
PERF_TIMER_GUARD(block_seek_nanos); PERF_TIMER_GUARD(block_seek_nanos);
Slice seek_key = target;
if (!key_includes_seq_) {
seek_key = ExtractUserKey(target);
}
if (data_ == nullptr) { // Not init yet if (data_ == nullptr) { // Not init yet
return; return;
} }
uint32_t index = 0; uint32_t index = 0;
bool ok = BinarySeek(target, 0, num_restarts_ - 1, &index); bool ok = BinarySeek(seek_key, 0, num_restarts_ - 1, &index);
if (!ok) { if (!ok) {
return; return;
} }
SeekToRestartPoint(index); SeekToRestartPoint(index);
// Linear search (within restart block) for first key >= target // Linear search (within restart block) for first key >= seek_key
while (ParseNextKey() && Compare(key_.GetInternalKey(), target) < 0) { while (ParseNextKey() && Compare(key_, seek_key) < 0) {
} }
if (!Valid()) { if (!Valid()) {
SeekToLast(); SeekToLast();
} else { } else {
while (Valid() && Compare(key_.GetInternalKey(), target) > 0) { while (Valid() && Compare(key_, seek_key) > 0) {
Prev(); Prev();
} }
} }
@@ -233,7 +245,11 @@ bool BlockIter::ParseNextKey() {
if (shared == 0) { if (shared == 0) {
// If this key dont share any bytes with prev key then we dont need // 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. // to decode it and can use it's address in the block directly.
key_.SetInternalKey(Slice(p, non_shared), false /* copy */); if (key_includes_seq_) {
key_.SetInternalKey(Slice(p, non_shared), false /* copy */);
} else {
key_.SetUserKey(Slice(p, non_shared), false /* copy */);
}
key_pinned_ = true; key_pinned_ = true;
} else { } else {
// This key share `shared` bytes with prev key, we need to decode it // This key share `shared` bytes with prev key, we need to decode it
@@ -380,6 +396,10 @@ bool BlockIter::BinaryBlockIndexSeek(const Slice& target, uint32_t* block_ids,
bool BlockIter::PrefixSeek(const Slice& target, uint32_t* index) { bool BlockIter::PrefixSeek(const Slice& target, uint32_t* index) {
assert(prefix_index_); assert(prefix_index_);
Slice seek_key = target;
if (!key_includes_seq_) {
seek_key = ExtractUserKey(target);
}
uint32_t* block_ids = nullptr; uint32_t* block_ids = nullptr;
uint32_t num_blocks = prefix_index_->GetBlocks(target, &block_ids); uint32_t num_blocks = prefix_index_->GetBlocks(target, &block_ids);
@@ -387,7 +407,7 @@ bool BlockIter::PrefixSeek(const Slice& target, uint32_t* index) {
current_ = restarts_; current_ = restarts_;
return false; return false;
} else { } else {
return BinaryBlockIndexSeek(target, block_ids, 0, num_blocks - 1, index); return BinaryBlockIndexSeek(seek_key, block_ids, 0, num_blocks - 1, index);
} }
} }
@@ -402,12 +422,14 @@ Block::Block(BlockContents&& contents, SequenceNumber _global_seqno,
data_(contents_.data.data()), data_(contents_.data.data()),
size_(contents_.data.size()), size_(contents_.data.size()),
restart_offset_(0), restart_offset_(0),
num_restarts_(0),
global_seqno_(_global_seqno) { global_seqno_(_global_seqno) {
if (size_ < sizeof(uint32_t)) { if (size_ < sizeof(uint32_t)) {
size_ = 0; // Error marker size_ = 0; // Error marker
} else { } else {
num_restarts_ = NumRestarts();
restart_offset_ = restart_offset_ =
static_cast<uint32_t>(size_) - (1 + NumRestarts()) * sizeof(uint32_t); static_cast<uint32_t>(size_) - (1 + num_restarts_) * sizeof(uint32_t);
if (restart_offset_ > size_ - sizeof(uint32_t)) { if (restart_offset_ > size_ - sizeof(uint32_t)) {
// The size is too small for NumRestarts() and therefore // The size is too small for NumRestarts() and therefore
// restart_offset_ wrapped around. // restart_offset_ wrapped around.
@@ -420,8 +442,9 @@ Block::Block(BlockContents&& contents, SequenceNumber _global_seqno,
} }
} }
BlockIter* Block::NewIterator(const Comparator* cmp, BlockIter* iter, BlockIter* Block::NewIterator(const Comparator* cmp, const Comparator* ucmp,
bool total_order_seek, Statistics* stats) { BlockIter* iter, bool total_order_seek,
Statistics* stats, bool key_includes_seq) {
BlockIter* ret_iter; BlockIter* ret_iter;
if (iter != nullptr) { if (iter != nullptr) {
ret_iter = iter; ret_iter = iter;
@@ -432,17 +455,16 @@ BlockIter* Block::NewIterator(const Comparator* cmp, BlockIter* iter,
ret_iter->Invalidate(Status::Corruption("bad block contents")); ret_iter->Invalidate(Status::Corruption("bad block contents"));
return ret_iter; return ret_iter;
} }
const uint32_t num_restarts = NumRestarts(); if (num_restarts_ == 0) {
if (num_restarts == 0) {
// Empty block. // Empty block.
ret_iter->Invalidate(Status::OK()); ret_iter->Invalidate(Status::OK());
return ret_iter; return ret_iter;
} else { } else {
BlockPrefixIndex* prefix_index_ptr = BlockPrefixIndex* prefix_index_ptr =
total_order_seek ? nullptr : prefix_index_.get(); total_order_seek ? nullptr : prefix_index_.get();
ret_iter->Initialize(cmp, data_, restart_offset_, num_restarts, ret_iter->Initialize(cmp, ucmp, data_, restart_offset_, num_restarts_,
prefix_index_ptr, global_seqno_, prefix_index_ptr, global_seqno_,
read_amp_bitmap_.get()); read_amp_bitmap_.get(), key_includes_seq);
if (read_amp_bitmap_) { if (read_amp_bitmap_) {
if (read_amp_bitmap_->GetStatistics() != stats) { if (read_amp_bitmap_->GetStatistics() != stats) {
@@ -461,9 +483,17 @@ void Block::SetBlockPrefixIndex(BlockPrefixIndex* prefix_index) {
size_t Block::ApproximateMemoryUsage() const { size_t Block::ApproximateMemoryUsage() const {
size_t usage = usable_size(); 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_) { if (prefix_index_) {
usage += prefix_index_->ApproximateMemoryUsage(); usage += prefix_index_->ApproximateMemoryUsage();
} }
if (read_amp_bitmap_) {
usage += read_amp_bitmap_->ApproximateMemoryUsage();
}
return usage; return usage;
} }
+54 -19
View File
@@ -104,6 +104,13 @@ class BlockReadAmpBitmap {
uint32_t GetBytesPerBit() { return 1 << bytes_per_bit_pow_; } 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: private:
// Get the current value of bit at `bit_idx` and set it to 1 // Get the current value of bit at `bit_idx` and set it to 1
inline bool GetAndSet(uint32_t bit_idx) { inline bool GetAndSet(uint32_t bit_idx) {
@@ -142,14 +149,8 @@ class Block {
size_t size() const { return size_; } size_t size() const { return size_; }
const char* data() const { return data_; } const char* data() const { return data_; }
bool cachable() const { return contents_.cachable; } bool cachable() const { return contents_.cachable; }
size_t usable_size() const { // The additional memory space taken by the block data.
#ifdef ROCKSDB_MALLOC_USABLE_SIZE size_t usable_size() const { return contents_.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; uint32_t NumRestarts() const;
CompressionType compression_type() const { CompressionType compression_type() const {
return contents_.compression_type; return contents_.compression_type;
@@ -162,6 +163,9 @@ class Block {
// the iterator will simply be set as "invalid", rather than returning // the iterator will simply be set as "invalid", rather than returning
// the key that is just pass the target key. // 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 null, return new Iterator
// If iter is not null, update this one and return it as Iterator* // If iter is not null, update this one and return it as Iterator*
// //
@@ -169,9 +173,11 @@ class Block {
// This option only applies for index block. For data block, hash_index_ // This option only applies for index block. For data block, hash_index_
// and prefix_index_ are null, so this option does not matter. // and prefix_index_ are null, so this option does not matter.
BlockIter* NewIterator(const Comparator* comparator, BlockIter* NewIterator(const Comparator* comparator,
const Comparator* user_comparator,
BlockIter* iter = nullptr, BlockIter* iter = nullptr,
bool total_order_seek = true, bool total_order_seek = true,
Statistics* stats = nullptr); Statistics* stats = nullptr,
bool key_includes_seq = true);
void SetBlockPrefixIndex(BlockPrefixIndex* prefix_index); void SetBlockPrefixIndex(BlockPrefixIndex* prefix_index);
// Report an approximation of how much memory has been used. // Report an approximation of how much memory has been used.
@@ -184,6 +190,7 @@ class Block {
const char* data_; // contents_.data.data() const char* data_; // contents_.data.data()
size_t size_; // contents_.data.size() size_t size_; // contents_.data.size()
uint32_t restart_offset_; // Offset in data_ of restart array uint32_t restart_offset_; // Offset in data_ of restart array
uint32_t num_restarts_;
std::unique_ptr<BlockPrefixIndex> prefix_index_; std::unique_ptr<BlockPrefixIndex> prefix_index_;
std::unique_ptr<BlockReadAmpBitmap> read_amp_bitmap_; std::unique_ptr<BlockReadAmpBitmap> read_amp_bitmap_;
// All keys in the block will have seqno = global_seqno_, regardless of // All keys in the block will have seqno = global_seqno_, regardless of
@@ -202,6 +209,7 @@ class BlockIter final : public InternalIterator {
// and status() is OK. // and status() is OK.
BlockIter() BlockIter()
: comparator_(nullptr), : comparator_(nullptr),
user_comparator_(nullptr),
data_(nullptr), data_(nullptr),
restarts_(0), restarts_(0),
num_restarts_(0), num_restarts_(0),
@@ -210,26 +218,30 @@ class BlockIter final : public InternalIterator {
status_(Status::OK()), status_(Status::OK()),
prefix_index_(nullptr), prefix_index_(nullptr),
key_pinned_(false), key_pinned_(false),
key_includes_seq_(true),
global_seqno_(kDisableGlobalSequenceNumber), global_seqno_(kDisableGlobalSequenceNumber),
read_amp_bitmap_(nullptr), read_amp_bitmap_(nullptr),
last_bitmap_offset_(0) {} last_bitmap_offset_(0) {}
BlockIter(const Comparator* comparator, const char* data, uint32_t restarts, BlockIter(const Comparator* comparator, const Comparator* user_comparator,
uint32_t num_restarts, BlockPrefixIndex* prefix_index, const char* data, uint32_t restarts, uint32_t num_restarts,
SequenceNumber global_seqno, BlockReadAmpBitmap* read_amp_bitmap) BlockPrefixIndex* prefix_index, SequenceNumber global_seqno,
BlockReadAmpBitmap* read_amp_bitmap, bool key_includes_seq)
: BlockIter() { : BlockIter() {
Initialize(comparator, data, restarts, num_restarts, prefix_index, Initialize(comparator, user_comparator, data, restarts, num_restarts,
global_seqno, read_amp_bitmap); prefix_index, global_seqno, read_amp_bitmap, key_includes_seq);
} }
void Initialize(const Comparator* comparator, const char* data, void Initialize(const Comparator* comparator,
const Comparator* user_comparator, const char* data,
uint32_t restarts, uint32_t num_restarts, uint32_t restarts, uint32_t num_restarts,
BlockPrefixIndex* prefix_index, SequenceNumber global_seqno, BlockPrefixIndex* prefix_index, SequenceNumber global_seqno,
BlockReadAmpBitmap* read_amp_bitmap) { BlockReadAmpBitmap* read_amp_bitmap, bool key_includes_seq) {
assert(data_ == nullptr); // Ensure it is called only once assert(data_ == nullptr); // Ensure it is called only once
assert(num_restarts > 0); // Ensure the param is valid assert(num_restarts > 0); // Ensure the param is valid
comparator_ = comparator; comparator_ = comparator;
user_comparator_ = user_comparator;
data_ = data; data_ = data;
restarts_ = restarts; restarts_ = restarts;
num_restarts_ = num_restarts; num_restarts_ = num_restarts;
@@ -239,10 +251,11 @@ class BlockIter final : public InternalIterator {
global_seqno_ = global_seqno; global_seqno_ = global_seqno;
read_amp_bitmap_ = read_amp_bitmap; read_amp_bitmap_ = read_amp_bitmap;
last_bitmap_offset_ = current_ + 1; last_bitmap_offset_ = current_ + 1;
key_includes_seq_ = key_includes_seq;
} }
// Makes Valid() return false, status() return `s`, and Seek()/Prev()/etc do // Makes Valid() return false, status() return `s`, and Seek()/Prev()/etc do
// nothing. // nothing. Calls cleanup functions.
void Invalidate(Status s) { void Invalidate(Status s) {
// Assert that the BlockIter is never deleted while Pinning is Enabled. // Assert that the BlockIter is never deleted while Pinning is Enabled.
assert(!pinned_iters_mgr_ || assert(!pinned_iters_mgr_ ||
@@ -252,6 +265,9 @@ class BlockIter final : public InternalIterator {
current_ = restarts_; current_ = restarts_;
status_ = s; status_ = s;
// Call cleanup callbacks.
Cleanable::Reset();
// Clear prev entries cache. // Clear prev entries cache.
prev_entries_keys_buff_.clear(); prev_entries_keys_buff_.clear();
prev_entries_.clear(); prev_entries_.clear();
@@ -262,7 +278,7 @@ class BlockIter final : public InternalIterator {
virtual Status status() const override { return status_; } virtual Status status() const override { return status_; }
virtual Slice key() const override { virtual Slice key() const override {
assert(Valid()); assert(Valid());
return key_.GetInternalKey(); return key_includes_seq_ ? key_.GetInternalKey() : key_.GetUserKey();
} }
virtual Slice value() const override { virtual Slice value() const override {
assert(Valid()); assert(Valid());
@@ -311,7 +327,11 @@ class BlockIter final : public InternalIterator {
} }
private: private:
// Note: The type could be changed to InternalKeyComparator but we see a weird
// performance drop by that.
const Comparator* comparator_; const Comparator* comparator_;
// Same as comparator_ if comparator_ is not InernalKeyComparator
const Comparator* user_comparator_;
const char* data_; // underlying block contents const char* data_; // underlying block contents
uint32_t restarts_; // Offset of restart array (list of fixed32) uint32_t restarts_; // Offset of restart array (list of fixed32)
uint32_t num_restarts_; // Number of uint32_t entries in restart array uint32_t num_restarts_; // Number of uint32_t entries in restart array
@@ -324,8 +344,11 @@ class BlockIter final : public InternalIterator {
Status status_; Status status_;
BlockPrefixIndex* prefix_index_; BlockPrefixIndex* prefix_index_;
bool key_pinned_; bool key_pinned_;
// Key is in InternalKey format
bool key_includes_seq_;
SequenceNumber global_seqno_; SequenceNumber global_seqno_;
public:
// read-amp bitmap // read-amp bitmap
BlockReadAmpBitmap* read_amp_bitmap_; BlockReadAmpBitmap* read_amp_bitmap_;
// last `current_` value we report to read-amp bitmp // last `current_` value we report to read-amp bitmp
@@ -356,7 +379,19 @@ class BlockIter final : public InternalIterator {
int32_t prev_entries_idx_ = -1; int32_t prev_entries_idx_ = -1;
inline int Compare(const Slice& a, const Slice& b) const { inline int Compare(const Slice& a, const Slice& b) const {
return comparator_->Compare(a, b); 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 the offset in data_ just past the end of the current entry. // Return the offset in data_ just past the end of the current entry.
+4 -2
View File
@@ -186,7 +186,8 @@ BlockBasedFilterBlockReader::BlockBasedFilterBlockReader(
} }
bool BlockBasedFilterBlockReader::KeyMayMatch( bool BlockBasedFilterBlockReader::KeyMayMatch(
const Slice& key, uint64_t block_offset, const bool /*no_io*/, const Slice& key, const SliceTransform* /* prefix_extractor */,
uint64_t block_offset, const bool /*no_io*/,
const Slice* const /*const_ikey_ptr*/) { const Slice* const /*const_ikey_ptr*/) {
assert(block_offset != kNotValid); assert(block_offset != kNotValid);
if (!whole_key_filtering_) { if (!whole_key_filtering_) {
@@ -196,7 +197,8 @@ bool BlockBasedFilterBlockReader::KeyMayMatch(
} }
bool BlockBasedFilterBlockReader::PrefixMayMatch( bool BlockBasedFilterBlockReader::PrefixMayMatch(
const Slice& prefix, uint64_t block_offset, const bool /*no_io*/, const Slice& prefix, const SliceTransform* /* prefix_extractor */,
uint64_t block_offset, const bool /*no_io*/,
const Slice* const /*const_ikey_ptr*/) { const Slice* const /*const_ikey_ptr*/) {
assert(block_offset != kNotValid); assert(block_offset != kNotValid);
if (!prefix_extractor_) { if (!prefix_extractor_) {
+5 -4
View File
@@ -83,13 +83,14 @@ class BlockBasedFilterBlockReader : public FilterBlockReader {
bool whole_key_filtering, bool whole_key_filtering,
BlockContents&& contents, Statistics* statistics); BlockContents&& contents, Statistics* statistics);
virtual bool IsBlockBased() override { return true; } virtual bool IsBlockBased() override { return true; }
virtual bool KeyMayMatch( virtual bool KeyMayMatch(
const Slice& key, uint64_t block_offset = kNotValid, const Slice& key, const SliceTransform* prefix_extractor,
const bool no_io = false, uint64_t block_offset = kNotValid, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) override; const Slice* const const_ikey_ptr = nullptr) override;
virtual bool PrefixMayMatch( virtual bool PrefixMayMatch(
const Slice& prefix, uint64_t block_offset = kNotValid, const Slice& prefix, const SliceTransform* prefix_extractor,
const bool no_io = false, uint64_t block_offset = kNotValid, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) override; const Slice* const const_ikey_ptr = nullptr) override;
virtual size_t ApproximateMemoryUsage() const override; virtual size_t ApproximateMemoryUsage() const override;
+50 -50
View File
@@ -59,8 +59,8 @@ TEST_F(FilterBlockTest, EmptyBuilder) {
ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block.data)); ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block.data));
BlockBasedFilterBlockReader reader(nullptr, table_options_, true, BlockBasedFilterBlockReader reader(nullptr, table_options_, true,
std::move(block), nullptr); std::move(block), nullptr);
ASSERT_TRUE(reader.KeyMayMatch("foo", 0)); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr, uint64_t{0}));
ASSERT_TRUE(reader.KeyMayMatch("foo", 100000)); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr, 100000));
} }
TEST_F(FilterBlockTest, SingleChunk) { TEST_F(FilterBlockTest, SingleChunk) {
@@ -78,13 +78,13 @@ TEST_F(FilterBlockTest, SingleChunk) {
BlockContents block(builder.Finish(), false, kNoCompression); BlockContents block(builder.Finish(), false, kNoCompression);
BlockBasedFilterBlockReader reader(nullptr, table_options_, true, BlockBasedFilterBlockReader reader(nullptr, table_options_, true,
std::move(block), nullptr); std::move(block), nullptr);
ASSERT_TRUE(reader.KeyMayMatch("foo", 100)); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr, 100));
ASSERT_TRUE(reader.KeyMayMatch("bar", 100)); ASSERT_TRUE(reader.KeyMayMatch("bar", nullptr, 100));
ASSERT_TRUE(reader.KeyMayMatch("box", 100)); ASSERT_TRUE(reader.KeyMayMatch("box", nullptr, 100));
ASSERT_TRUE(reader.KeyMayMatch("hello", 100)); ASSERT_TRUE(reader.KeyMayMatch("hello", nullptr, 100));
ASSERT_TRUE(reader.KeyMayMatch("foo", 100)); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr, 100));
ASSERT_TRUE(!reader.KeyMayMatch("missing", 100)); ASSERT_TRUE(!reader.KeyMayMatch("missing", nullptr, 100));
ASSERT_TRUE(!reader.KeyMayMatch("other", 100)); ASSERT_TRUE(!reader.KeyMayMatch("other", nullptr, 100));
} }
TEST_F(FilterBlockTest, MultiChunk) { TEST_F(FilterBlockTest, MultiChunk) {
@@ -112,28 +112,28 @@ TEST_F(FilterBlockTest, MultiChunk) {
std::move(block), nullptr); std::move(block), nullptr);
// Check first filter // Check first filter
ASSERT_TRUE(reader.KeyMayMatch("foo", 0)); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr, uint64_t{0}));
ASSERT_TRUE(reader.KeyMayMatch("bar", 2000)); ASSERT_TRUE(reader.KeyMayMatch("bar", nullptr, 2000));
ASSERT_TRUE(!reader.KeyMayMatch("box", 0)); ASSERT_TRUE(!reader.KeyMayMatch("box", nullptr, uint64_t{0}));
ASSERT_TRUE(!reader.KeyMayMatch("hello", 0)); ASSERT_TRUE(!reader.KeyMayMatch("hello", nullptr, uint64_t{0}));
// Check second filter // Check second filter
ASSERT_TRUE(reader.KeyMayMatch("box", 3100)); ASSERT_TRUE(reader.KeyMayMatch("box", nullptr, 3100));
ASSERT_TRUE(!reader.KeyMayMatch("foo", 3100)); ASSERT_TRUE(!reader.KeyMayMatch("foo", nullptr, 3100));
ASSERT_TRUE(!reader.KeyMayMatch("bar", 3100)); ASSERT_TRUE(!reader.KeyMayMatch("bar", nullptr, 3100));
ASSERT_TRUE(!reader.KeyMayMatch("hello", 3100)); ASSERT_TRUE(!reader.KeyMayMatch("hello", nullptr, 3100));
// Check third filter (empty) // Check third filter (empty)
ASSERT_TRUE(!reader.KeyMayMatch("foo", 4100)); ASSERT_TRUE(!reader.KeyMayMatch("foo", nullptr, 4100));
ASSERT_TRUE(!reader.KeyMayMatch("bar", 4100)); ASSERT_TRUE(!reader.KeyMayMatch("bar", nullptr, 4100));
ASSERT_TRUE(!reader.KeyMayMatch("box", 4100)); ASSERT_TRUE(!reader.KeyMayMatch("box", nullptr, 4100));
ASSERT_TRUE(!reader.KeyMayMatch("hello", 4100)); ASSERT_TRUE(!reader.KeyMayMatch("hello", nullptr, 4100));
// Check last filter // Check last filter
ASSERT_TRUE(reader.KeyMayMatch("box", 9000)); ASSERT_TRUE(reader.KeyMayMatch("box", nullptr, 9000));
ASSERT_TRUE(reader.KeyMayMatch("hello", 9000)); ASSERT_TRUE(reader.KeyMayMatch("hello", nullptr, 9000));
ASSERT_TRUE(!reader.KeyMayMatch("foo", 9000)); ASSERT_TRUE(!reader.KeyMayMatch("foo", nullptr, 9000));
ASSERT_TRUE(!reader.KeyMayMatch("bar", 9000)); ASSERT_TRUE(!reader.KeyMayMatch("bar", nullptr, 9000));
} }
// Test for block based filter block // Test for block based filter block
@@ -156,8 +156,8 @@ TEST_F(BlockBasedFilterBlockTest, BlockBasedEmptyBuilder) {
ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block.data)); ASSERT_EQ("\\x00\\x00\\x00\\x00\\x0b", EscapeString(block.data));
FilterBlockReader* reader = new BlockBasedFilterBlockReader( FilterBlockReader* reader = new BlockBasedFilterBlockReader(
nullptr, table_options_, true, std::move(block), nullptr); nullptr, table_options_, true, std::move(block), nullptr);
ASSERT_TRUE(reader->KeyMayMatch("foo", 0)); ASSERT_TRUE(reader->KeyMayMatch("foo", nullptr, uint64_t{0}));
ASSERT_TRUE(reader->KeyMayMatch("foo", 100000)); ASSERT_TRUE(reader->KeyMayMatch("foo", nullptr, 100000));
delete builder; delete builder;
delete reader; delete reader;
@@ -177,13 +177,13 @@ TEST_F(BlockBasedFilterBlockTest, BlockBasedSingleChunk) {
BlockContents block(builder->Finish(), false, kNoCompression); BlockContents block(builder->Finish(), false, kNoCompression);
FilterBlockReader* reader = new BlockBasedFilterBlockReader( FilterBlockReader* reader = new BlockBasedFilterBlockReader(
nullptr, table_options_, true, std::move(block), nullptr); nullptr, table_options_, true, std::move(block), nullptr);
ASSERT_TRUE(reader->KeyMayMatch("foo", 100)); ASSERT_TRUE(reader->KeyMayMatch("foo", nullptr, 100));
ASSERT_TRUE(reader->KeyMayMatch("bar", 100)); ASSERT_TRUE(reader->KeyMayMatch("bar", nullptr, 100));
ASSERT_TRUE(reader->KeyMayMatch("box", 100)); ASSERT_TRUE(reader->KeyMayMatch("box", nullptr, 100));
ASSERT_TRUE(reader->KeyMayMatch("hello", 100)); ASSERT_TRUE(reader->KeyMayMatch("hello", nullptr, 100));
ASSERT_TRUE(reader->KeyMayMatch("foo", 100)); ASSERT_TRUE(reader->KeyMayMatch("foo", nullptr, 100));
ASSERT_TRUE(!reader->KeyMayMatch("missing", 100)); ASSERT_TRUE(!reader->KeyMayMatch("missing", nullptr, 100));
ASSERT_TRUE(!reader->KeyMayMatch("other", 100)); ASSERT_TRUE(!reader->KeyMayMatch("other", nullptr, 100));
delete builder; delete builder;
delete reader; delete reader;
@@ -215,28 +215,28 @@ TEST_F(BlockBasedFilterBlockTest, BlockBasedMultiChunk) {
nullptr, table_options_, true, std::move(block), nullptr); nullptr, table_options_, true, std::move(block), nullptr);
// Check first filter // Check first filter
ASSERT_TRUE(reader->KeyMayMatch("foo", 0)); ASSERT_TRUE(reader->KeyMayMatch("foo", nullptr, uint64_t{0}));
ASSERT_TRUE(reader->KeyMayMatch("bar", 2000)); ASSERT_TRUE(reader->KeyMayMatch("bar", nullptr, 2000));
ASSERT_TRUE(!reader->KeyMayMatch("box", 0)); ASSERT_TRUE(!reader->KeyMayMatch("box", nullptr, uint64_t{0}));
ASSERT_TRUE(!reader->KeyMayMatch("hello", 0)); ASSERT_TRUE(!reader->KeyMayMatch("hello", nullptr, uint64_t{0}));
// Check second filter // Check second filter
ASSERT_TRUE(reader->KeyMayMatch("box", 3100)); ASSERT_TRUE(reader->KeyMayMatch("box", nullptr, 3100));
ASSERT_TRUE(!reader->KeyMayMatch("foo", 3100)); ASSERT_TRUE(!reader->KeyMayMatch("foo", nullptr, 3100));
ASSERT_TRUE(!reader->KeyMayMatch("bar", 3100)); ASSERT_TRUE(!reader->KeyMayMatch("bar", nullptr, 3100));
ASSERT_TRUE(!reader->KeyMayMatch("hello", 3100)); ASSERT_TRUE(!reader->KeyMayMatch("hello", nullptr, 3100));
// Check third filter (empty) // Check third filter (empty)
ASSERT_TRUE(!reader->KeyMayMatch("foo", 4100)); ASSERT_TRUE(!reader->KeyMayMatch("foo", nullptr, 4100));
ASSERT_TRUE(!reader->KeyMayMatch("bar", 4100)); ASSERT_TRUE(!reader->KeyMayMatch("bar", nullptr, 4100));
ASSERT_TRUE(!reader->KeyMayMatch("box", 4100)); ASSERT_TRUE(!reader->KeyMayMatch("box", nullptr, 4100));
ASSERT_TRUE(!reader->KeyMayMatch("hello", 4100)); ASSERT_TRUE(!reader->KeyMayMatch("hello", nullptr, 4100));
// Check last filter // Check last filter
ASSERT_TRUE(reader->KeyMayMatch("box", 9000)); ASSERT_TRUE(reader->KeyMayMatch("box", nullptr, 9000));
ASSERT_TRUE(reader->KeyMayMatch("hello", 9000)); ASSERT_TRUE(reader->KeyMayMatch("hello", nullptr, 9000));
ASSERT_TRUE(!reader->KeyMayMatch("foo", 9000)); ASSERT_TRUE(!reader->KeyMayMatch("foo", nullptr, 9000));
ASSERT_TRUE(!reader->KeyMayMatch("bar", 9000)); ASSERT_TRUE(!reader->KeyMayMatch("bar", nullptr, 9000));
delete builder; delete builder;
delete reader; delete reader;
+25 -19
View File
@@ -62,14 +62,16 @@ namespace {
// Create a filter block builder based on its type. // Create a filter block builder based on its type.
FilterBlockBuilder* CreateFilterBlockBuilder( FilterBlockBuilder* CreateFilterBlockBuilder(
const ImmutableCFOptions& opt, const BlockBasedTableOptions& table_opt, const ImmutableCFOptions& /*opt*/, const MutableCFOptions& mopt,
const BlockBasedTableOptions& table_opt,
PartitionedIndexBuilder* const p_index_builder) { PartitionedIndexBuilder* const p_index_builder) {
if (table_opt.filter_policy == nullptr) return nullptr; if (table_opt.filter_policy == nullptr) return nullptr;
FilterBitsBuilder* filter_bits_builder = FilterBitsBuilder* filter_bits_builder =
table_opt.filter_policy->GetFilterBitsBuilder(); table_opt.filter_policy->GetFilterBitsBuilder();
if (filter_bits_builder == nullptr) { if (filter_bits_builder == nullptr) {
return new BlockBasedFilterBlockBuilder(opt.prefix_extractor, table_opt); return new BlockBasedFilterBlockBuilder(mopt.prefix_extractor.get(),
table_opt);
} else { } else {
if (table_opt.partition_filters) { if (table_opt.partition_filters) {
assert(p_index_builder != nullptr); assert(p_index_builder != nullptr);
@@ -82,11 +84,11 @@ FilterBlockBuilder* CreateFilterBlockBuilder(
(100 - table_opt.block_size_deviation)) + 99) / 100); (100 - table_opt.block_size_deviation)) + 99) / 100);
partition_size = std::max(partition_size, static_cast<uint32_t>(1)); partition_size = std::max(partition_size, static_cast<uint32_t>(1));
return new PartitionedFilterBlockBuilder( return new PartitionedFilterBlockBuilder(
opt.prefix_extractor, table_opt.whole_key_filtering, mopt.prefix_extractor.get(), table_opt.whole_key_filtering,
filter_bits_builder, table_opt.index_block_restart_interval, filter_bits_builder, table_opt.index_block_restart_interval,
p_index_builder, partition_size); p_index_builder, partition_size);
} else { } else {
return new FullFilterBlockBuilder(opt.prefix_extractor, return new FullFilterBlockBuilder(mopt.prefix_extractor.get(),
table_opt.whole_key_filtering, table_opt.whole_key_filtering,
filter_bits_builder); filter_bits_builder);
} }
@@ -244,6 +246,7 @@ class BlockBasedTableBuilder::BlockBasedTablePropertiesCollector
struct BlockBasedTableBuilder::Rep { struct BlockBasedTableBuilder::Rep {
const ImmutableCFOptions ioptions; const ImmutableCFOptions ioptions;
const MutableCFOptions moptions;
const BlockBasedTableOptions table_options; const BlockBasedTableOptions table_options;
const InternalKeyComparator& internal_comparator; const InternalKeyComparator& internal_comparator;
WritableFileWriter* file; WritableFileWriter* file;
@@ -280,7 +283,7 @@ struct BlockBasedTableBuilder::Rep {
std::vector<std::unique_ptr<IntTblPropCollector>> table_properties_collectors; std::vector<std::unique_ptr<IntTblPropCollector>> table_properties_collectors;
Rep(const ImmutableCFOptions& _ioptions, Rep(const ImmutableCFOptions& _ioptions, const MutableCFOptions& _moptions,
const BlockBasedTableOptions& table_opt, const BlockBasedTableOptions& table_opt,
const InternalKeyComparator& icomparator, const InternalKeyComparator& icomparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
@@ -292,6 +295,7 @@ struct BlockBasedTableBuilder::Rep {
const std::string& _column_family_name, const uint64_t _creation_time, const std::string& _column_family_name, const uint64_t _creation_time,
const uint64_t _oldest_key_time) const uint64_t _oldest_key_time)
: ioptions(_ioptions), : ioptions(_ioptions),
moptions(_moptions),
table_options(table_opt), table_options(table_opt),
internal_comparator(icomparator), internal_comparator(icomparator),
file(f), file(f),
@@ -300,8 +304,8 @@ struct BlockBasedTableBuilder::Rep {
: 0), : 0),
data_block(table_options.block_restart_interval, data_block(table_options.block_restart_interval,
table_options.use_delta_encoding), table_options.use_delta_encoding),
range_del_block(1), // TODO(andrewkr): restart_interval unnecessary range_del_block(1 /* block_restart_interval */),
internal_prefix_transform(_ioptions.prefix_extractor), internal_prefix_transform(_moptions.prefix_extractor.get()),
compression_type(_compression_type), compression_type(_compression_type),
compression_opts(_compression_opts), compression_opts(_compression_opts),
compression_dict(_compression_dict), compression_dict(_compression_dict),
@@ -326,8 +330,8 @@ struct BlockBasedTableBuilder::Rep {
if (skip_filters) { if (skip_filters) {
filter_builder = nullptr; filter_builder = nullptr;
} else { } else {
filter_builder.reset( filter_builder.reset(CreateFilterBlockBuilder(
CreateFilterBlockBuilder(_ioptions, table_options, p_index_builder_)); _ioptions, _moptions, table_options, p_index_builder_));
} }
for (auto& collector_factories : *int_tbl_prop_collector_factories) { for (auto& collector_factories : *int_tbl_prop_collector_factories) {
@@ -337,12 +341,12 @@ struct BlockBasedTableBuilder::Rep {
table_properties_collectors.emplace_back( table_properties_collectors.emplace_back(
new BlockBasedTablePropertiesCollector( new BlockBasedTablePropertiesCollector(
table_options.index_type, table_options.whole_key_filtering, table_options.index_type, table_options.whole_key_filtering,
_ioptions.prefix_extractor != nullptr)); _moptions.prefix_extractor != nullptr));
} }
}; };
BlockBasedTableBuilder::BlockBasedTableBuilder( BlockBasedTableBuilder::BlockBasedTableBuilder(
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions, const MutableCFOptions& moptions,
const BlockBasedTableOptions& table_options, const BlockBasedTableOptions& table_options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
@@ -365,11 +369,11 @@ BlockBasedTableBuilder::BlockBasedTableBuilder(
sanitized_table_options.format_version = 1; sanitized_table_options.format_version = 1;
} }
rep_ = new Rep(ioptions, sanitized_table_options, internal_comparator, rep_ =
int_tbl_prop_collector_factories, column_family_id, file, new Rep(ioptions, moptions, sanitized_table_options, internal_comparator,
compression_type, compression_opts, compression_dict, int_tbl_prop_collector_factories, column_family_id, file,
skip_filters, column_family_name, creation_time, compression_type, compression_opts, compression_dict,
oldest_key_time); skip_filters, column_family_name, creation_time, oldest_key_time);
if (rep_->filter_builder != nullptr) { if (rep_->filter_builder != nullptr) {
rep_->filter_builder->StartBlock(0); rep_->filter_builder->StartBlock(0);
@@ -639,7 +643,7 @@ Status BlockBasedTableBuilder::InsertBlockInCache(const Slice& block_contents,
(end - r->compressed_cache_key_prefix)); (end - r->compressed_cache_key_prefix));
// Insert into compressed block cache. // Insert into compressed block cache.
block_cache_compressed->Insert(key, block, block->usable_size(), block_cache_compressed->Insert(key, block, block->ApproximateMemoryUsage(),
&DeleteCachedBlock); &DeleteCachedBlock);
// Invalidate OS cache. // Invalidate OS cache.
@@ -737,8 +741,8 @@ Status BlockBasedTableBuilder::Finish() {
: "nullptr"; : "nullptr";
r->props.compression_name = CompressionTypeToString(r->compression_type); r->props.compression_name = CompressionTypeToString(r->compression_type);
r->props.prefix_extractor_name = r->props.prefix_extractor_name =
r->ioptions.prefix_extractor != nullptr r->moptions.prefix_extractor != nullptr
? r->ioptions.prefix_extractor->Name() ? r->moptions.prefix_extractor->Name()
: "nullptr"; : "nullptr";
std::string property_collectors_names = "["; std::string property_collectors_names = "[";
@@ -759,6 +763,8 @@ Status BlockBasedTableBuilder::Finish() {
r->props.top_level_index_size = r->props.top_level_index_size =
r->p_index_builder_->EstimateTopLevelIndexSize(r->offset); 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.creation_time = r->creation_time;
r->props.oldest_key_time = r->oldest_key_time; r->props.oldest_key_time = r->oldest_key_time;
+1 -1
View File
@@ -38,7 +38,7 @@ class BlockBasedTableBuilder : public TableBuilder {
// @param compression_dict Data for presetting the compression library's // @param compression_dict Data for presetting the compression library's
// dictionary, or nullptr. // dictionary, or nullptr.
BlockBasedTableBuilder( BlockBasedTableBuilder(
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions, const MutableCFOptions& moptions,
const BlockBasedTableOptions& table_options, const BlockBasedTableOptions& table_options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
+8 -4
View File
@@ -69,16 +69,17 @@ Status BlockBasedTableFactory::NewTableReader(
return BlockBasedTable::Open( return BlockBasedTable::Open(
table_reader_options.ioptions, table_reader_options.env_options, table_reader_options.ioptions, table_reader_options.env_options,
table_options_, table_reader_options.internal_comparator, std::move(file), table_options_, table_reader_options.internal_comparator, std::move(file),
file_size, table_reader, prefetch_index_and_filter_in_cache, file_size, table_reader, table_reader_options.prefix_extractor,
table_reader_options.skip_filters, table_reader_options.level); prefetch_index_and_filter_in_cache, table_reader_options.skip_filters,
table_reader_options.level);
} }
TableBuilder* BlockBasedTableFactory::NewTableBuilder( TableBuilder* BlockBasedTableFactory::NewTableBuilder(
const TableBuilderOptions& table_builder_options, uint32_t column_family_id, const TableBuilderOptions& table_builder_options, uint32_t column_family_id,
WritableFileWriter* file) const { WritableFileWriter* file) const {
auto table_builder = new BlockBasedTableBuilder( auto table_builder = new BlockBasedTableBuilder(
table_builder_options.ioptions, table_options_, table_builder_options.ioptions, table_builder_options.moptions,
table_builder_options.internal_comparator, table_options_, table_builder_options.internal_comparator,
table_builder_options.int_tbl_prop_collector_factories, column_family_id, table_builder_options.int_tbl_prop_collector_factories, column_family_id,
file, table_builder_options.compression_type, file, table_builder_options.compression_type,
table_builder_options.compression_opts, table_builder_options.compression_opts,
@@ -150,6 +151,9 @@ std::string BlockBasedTableFactory::GetPrintableTableOptions() const {
" pin_l0_filter_and_index_blocks_in_cache: %d\n", " pin_l0_filter_and_index_blocks_in_cache: %d\n",
table_options_.pin_l0_filter_and_index_blocks_in_cache); table_options_.pin_l0_filter_and_index_blocks_in_cache);
ret.append(buffer); 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", snprintf(buffer, kBufferSize, " index_type: %d\n",
table_options_.index_type); table_options_.index_type);
ret.append(buffer); ret.append(buffer);
+4
View File
@@ -158,6 +158,10 @@ static std::unordered_map<std::string, OptionTypeInfo>
OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}}, OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}},
{"block_align", {"block_align",
{offsetof(struct BlockBasedTableOptions, 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}}}; OptionType::kBoolean, OptionVerificationType::kNormal, false, 0}}};
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
} // namespace rocksdb } // namespace rocksdb
File diff suppressed because it is too large Load Diff
+54 -26
View File
@@ -90,25 +90,29 @@ class BlockBasedTable : public TableReader {
const InternalKeyComparator& internal_key_comparator, const InternalKeyComparator& internal_key_comparator,
unique_ptr<RandomAccessFileReader>&& file, unique_ptr<RandomAccessFileReader>&& file,
uint64_t file_size, unique_ptr<TableReader>* table_reader, uint64_t file_size, unique_ptr<TableReader>* table_reader,
const SliceTransform* prefix_extractor = nullptr,
bool prefetch_index_and_filter_in_cache = true, bool prefetch_index_and_filter_in_cache = true,
bool skip_filters = false, int level = -1); bool skip_filters = false, int level = -1);
bool PrefixMayMatch(const Slice& internal_key); bool PrefixMayMatch(const Slice& internal_key,
const SliceTransform* prefix_extractor = nullptr);
// Returns a new iterator over the table contents. // Returns a new iterator over the table contents.
// The result of NewIterator() is initially invalid (caller must // The result of NewIterator() is initially invalid (caller must
// call one of the Seek methods on the iterator before using it). // call one of the Seek methods on the iterator before using it).
// @param skip_filters Disables loading/accessing the filter block // @param skip_filters Disables loading/accessing the filter block
InternalIterator* NewIterator( InternalIterator* NewIterator(const ReadOptions&,
const ReadOptions&, Arena* arena = nullptr, const SliceTransform* prefix_extractor,
bool skip_filters = false) override; Arena* arena = nullptr,
bool skip_filters = false) override;
InternalIterator* NewRangeTombstoneIterator( InternalIterator* NewRangeTombstoneIterator(
const ReadOptions& read_options) override; const ReadOptions& read_options) override;
// @param skip_filters Disables loading/accessing the filter block // @param skip_filters Disables loading/accessing the filter block
Status Get(const ReadOptions& readOptions, const Slice& key, Status Get(const ReadOptions& readOptions, const Slice& key,
GetContext* get_context, bool skip_filters = false) override; GetContext* get_context, const SliceTransform* prefix_extractor,
bool skip_filters = false) override;
// Pre-fetch the disk blocks that correspond to the key range specified by // Pre-fetch the disk blocks that correspond to the key range specified by
// (kbegin, kend). The call will return error status in the event of // (kbegin, kend). The call will return error status in the event of
@@ -136,7 +140,8 @@ class BlockBasedTable : public TableReader {
size_t ApproximateMemoryUsage() const override; size_t ApproximateMemoryUsage() const override;
// convert SST file to a human readable form // convert SST file to a human readable form
Status DumpTable(WritableFile* out_file) override; Status DumpTable(WritableFile* out_file,
const SliceTransform* prefix_extractor = nullptr) override;
Status VerifyChecksum() override; Status VerifyChecksum() override;
@@ -212,11 +217,13 @@ class BlockBasedTable : public TableReader {
const Slice& index_value, const Slice& index_value,
BlockIter* input_iter = nullptr, BlockIter* input_iter = nullptr,
bool is_index = false, bool is_index = false,
bool key_includes_seq = true,
GetContext* get_context = nullptr); GetContext* get_context = nullptr);
static BlockIter* NewDataBlockIterator(Rep* rep, const ReadOptions& ro, static BlockIter* NewDataBlockIterator(Rep* rep, const ReadOptions& ro,
const BlockHandle& block_hanlde, const BlockHandle& block_hanlde,
BlockIter* input_iter = nullptr, BlockIter* input_iter = nullptr,
bool is_index = false, bool is_index = false,
bool key_includes_seq = true,
GetContext* get_context = nullptr, GetContext* get_context = nullptr,
Status s = Status()); Status s = Status());
@@ -253,12 +260,13 @@ class BlockBasedTable : public TableReader {
// if `no_io == true`, we will not try to read filter/index from sst file // if `no_io == true`, we will not try to read filter/index from sst file
// were they not present in cache yet. // were they not present in cache yet.
CachableEntry<FilterBlockReader> GetFilter( CachableEntry<FilterBlockReader> GetFilter(
const SliceTransform* prefix_extractor = nullptr,
FilePrefetchBuffer* prefetch_buffer = nullptr, bool no_io = false, FilePrefetchBuffer* prefetch_buffer = nullptr, bool no_io = false,
GetContext* get_context = nullptr) const; GetContext* get_context = nullptr) const;
virtual CachableEntry<FilterBlockReader> GetFilter( virtual CachableEntry<FilterBlockReader> GetFilter(
FilePrefetchBuffer* prefetch_buffer, const BlockHandle& filter_blk_handle, FilePrefetchBuffer* prefetch_buffer, const BlockHandle& filter_blk_handle,
const bool is_a_filter_partition, bool no_io, const bool is_a_filter_partition, bool no_io, GetContext* get_context,
GetContext* get_context) const; const SliceTransform* prefix_extractor = nullptr) const;
// Get the iterator from the index reader. // Get the iterator from the index reader.
// If input_iter is not set, return new Iterator // If input_iter is not set, return new Iterator
@@ -271,7 +279,8 @@ class BlockBasedTable : public TableReader {
// 3. We disallowed any io to be performed, that is, read_options == // 3. We disallowed any io to be performed, that is, read_options ==
// kBlockCacheTier // kBlockCacheTier
InternalIterator* NewIndexIterator( InternalIterator* NewIndexIterator(
const ReadOptions& read_options, BlockIter* input_iter = nullptr, const ReadOptions& read_options, bool prefix_extractor_changed = false,
BlockIter* input_iter = nullptr,
CachableEntry<IndexReader>* index_entry = nullptr, CachableEntry<IndexReader>* index_entry = nullptr,
GetContext* get_context = nullptr); GetContext* get_context = nullptr);
@@ -316,6 +325,9 @@ class BlockBasedTable : public TableReader {
void ReadMeta(const Footer& footer); 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. // 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 // Optionally, user can pass a preloaded meta_index_iter for the index that
// need to access extra meta blocks for index construction. This parameter // need to access extra meta blocks for index construction. This parameter
@@ -325,9 +337,10 @@ class BlockBasedTable : public TableReader {
InternalIterator* preloaded_meta_index_iter = nullptr, InternalIterator* preloaded_meta_index_iter = nullptr,
const int level = -1); const int level = -1);
bool FullFilterKeyMayMatch(const ReadOptions& read_options, bool FullFilterKeyMayMatch(
FilterBlockReader* filter, const Slice& user_key, const ReadOptions& read_options, FilterBlockReader* filter,
const bool no_io) const; const Slice& user_key, const bool no_io,
const SliceTransform* prefix_extractor = nullptr) const;
// Read the meta block from sst. // Read the meta block from sst.
static Status ReadMetaBlock(Rep* rep, FilePrefetchBuffer* prefetch_buffer, static Status ReadMetaBlock(Rep* rep, FilePrefetchBuffer* prefetch_buffer,
@@ -337,9 +350,10 @@ class BlockBasedTable : public TableReader {
Status VerifyChecksumInBlocks(InternalIterator* index_iter); Status VerifyChecksumInBlocks(InternalIterator* index_iter);
// Create the filter from the filter block. // Create the filter from the filter block.
FilterBlockReader* ReadFilter(FilePrefetchBuffer* prefetch_buffer, FilterBlockReader* ReadFilter(
const BlockHandle& filter_handle, FilePrefetchBuffer* prefetch_buffer, const BlockHandle& filter_handle,
const bool is_a_filter_partition) const; const bool is_a_filter_partition,
const SliceTransform* prefix_extractor = nullptr) const;
static void SetupCacheKeyPrefix(Rep* rep, uint64_t file_size); static void SetupCacheKeyPrefix(Rep* rep, uint64_t file_size);
@@ -369,13 +383,15 @@ class BlockBasedTable::PartitionedIndexIteratorState
public: public:
PartitionedIndexIteratorState( PartitionedIndexIteratorState(
BlockBasedTable* table, BlockBasedTable* table,
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map = nullptr); std::unordered_map<uint64_t, CachableEntry<Block>>* block_map,
const bool index_key_includes_seq);
InternalIterator* NewSecondaryIterator(const Slice& index_value) override; InternalIterator* NewSecondaryIterator(const Slice& index_value) override;
private: private:
// Don't own table_ // Don't own table_
BlockBasedTable* table_; BlockBasedTable* table_;
std::unordered_map<uint64_t, CachableEntry<Block>>* block_map_; 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. // CachableEntry represents the entries that *may* be fetched from block cache.
@@ -420,7 +436,7 @@ struct BlockBasedTable::Rep {
const ImmutableCFOptions& ioptions; const ImmutableCFOptions& ioptions;
const EnvOptions& env_options; const EnvOptions& env_options;
const BlockBasedTableOptions& table_options; const BlockBasedTableOptions table_options;
const FilterPolicy* const filter_policy; const FilterPolicy* const filter_policy;
const InternalKeyComparator& internal_comparator; const InternalKeyComparator& internal_comparator;
Status status; Status status;
@@ -468,11 +484,12 @@ struct BlockBasedTable::Rep {
// block to extract prefix without knowing if a key is internal or not. // block to extract prefix without knowing if a key is internal or not.
unique_ptr<SliceTransform> internal_prefix_transform; unique_ptr<SliceTransform> internal_prefix_transform;
// only used in level 0 files: // only used in level 0 files when pin_l0_filter_and_index_blocks_in_cache is
// when pin_l0_filter_and_index_blocks_in_cache is true, we do use the // true or in all levels when pin_top_level_index_and_filter is set in
// LRU cache, but we always keep the filter & idndex block's handle checked // combination with partitioned index/filters: then we do use the LRU cache,
// out here (=we don't call Release()), plus the parsed out objects // but we always keep the filter & index block's handle checked out here (=we
// the LRU cache will never push flush them out, hence they're pinned // 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<FilterBlockReader> filter_entry;
CachableEntry<IndexReader> index_entry; CachableEntry<IndexReader> index_entry;
// range deletion meta-block is pinned through reader's lifetime when LRU // range deletion meta-block is pinned through reader's lifetime when LRU
@@ -499,14 +516,19 @@ class BlockBasedTableIterator : public InternalIterator {
BlockBasedTableIterator(BlockBasedTable* table, BlockBasedTableIterator(BlockBasedTable* table,
const ReadOptions& read_options, const ReadOptions& read_options,
const InternalKeyComparator& icomp, const InternalKeyComparator& icomp,
InternalIterator* index_iter, bool check_filter) InternalIterator* index_iter, bool check_filter,
const SliceTransform* prefix_extractor, bool is_index,
bool key_includes_seq = true)
: table_(table), : table_(table),
read_options_(read_options), read_options_(read_options),
icomp_(icomp), icomp_(icomp),
index_iter_(index_iter), index_iter_(index_iter),
pinned_iters_mgr_(nullptr), pinned_iters_mgr_(nullptr),
block_iter_points_to_real_block_(false), block_iter_points_to_real_block_(false),
check_filter_(check_filter) {} check_filter_(check_filter),
is_index_(is_index),
key_includes_seq_(key_includes_seq),
prefix_extractor_(prefix_extractor) {}
~BlockBasedTableIterator() { delete index_iter_; } ~BlockBasedTableIterator() { delete index_iter_; }
@@ -552,8 +574,9 @@ class BlockBasedTableIterator : public InternalIterator {
block_iter_points_to_real_block_; block_iter_points_to_real_block_;
} }
bool CheckPrefixMayMatch(const Slice& ikey) { bool CheckPrefixMayMatch(const Slice& ikey,
if (check_filter_ && !table_->PrefixMayMatch(ikey)) { const SliceTransform* prefix_extractor = nullptr) {
if (check_filter_ && !table_->PrefixMayMatch(ikey, prefix_extractor)) {
// TODO remember the iterator is invalidated because of prefix // TODO remember the iterator is invalidated because of prefix
// match. This can avoid the upper level file iterator to falsely // match. This can avoid the upper level file iterator to falsely
// believe the position is the end of the SST file and move to // believe the position is the end of the SST file and move to
@@ -597,8 +620,13 @@ class BlockBasedTableIterator : public InternalIterator {
bool block_iter_points_to_real_block_; bool block_iter_points_to_real_block_;
bool is_out_of_bound_ = false; bool is_out_of_bound_ = false;
bool check_filter_; 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 // TODO use block offset instead
std::string prev_index_value_; std::string prev_index_value_;
const SliceTransform* prefix_extractor_;
static const size_t kInitReadaheadSize = 8 * 1024; static const size_t kInitReadaheadSize = 8 * 1024;
// Found that 256 KB readahead size provides the best performance, based on // Found that 256 KB readahead size provides the best performance, based on
+10 -9
View File
@@ -99,7 +99,8 @@ TEST_F(BlockTest, SimpleTest) {
// read contents of block sequentially // read contents of block sequentially
int count = 0; int count = 0;
InternalIterator *iter = reader.NewIterator(options.comparator); InternalIterator *iter =
reader.NewIterator(options.comparator, options.comparator);
for (iter->SeekToFirst();iter->Valid(); count++, iter->Next()) { for (iter->SeekToFirst();iter->Valid(); count++, iter->Next()) {
// read kv from block // read kv from block
@@ -113,7 +114,7 @@ TEST_F(BlockTest, SimpleTest) {
delete iter; delete iter;
// read block contents randomly // read block contents randomly
iter = reader.NewIterator(options.comparator); iter = reader.NewIterator(options.comparator, options.comparator);
for (int i = 0; i < num_records; i++) { for (int i = 0; i < num_records; i++) {
// find a random key in the lookaside array // find a random key in the lookaside array
@@ -163,7 +164,7 @@ void CheckBlockContents(BlockContents contents, const int max_key,
NewFixedPrefixTransform(prefix_size)); NewFixedPrefixTransform(prefix_size));
std::unique_ptr<InternalIterator> regular_iter( std::unique_ptr<InternalIterator> regular_iter(
reader2.NewIterator(BytewiseComparator())); reader2.NewIterator(BytewiseComparator(), BytewiseComparator()));
// Seek existent keys // Seek existent keys
for (size_t i = 0; i < keys.size(); i++) { for (size_t i = 0; i < keys.size(); i++) {
@@ -388,8 +389,8 @@ TEST_F(BlockTest, BlockWithReadAmpBitmap) {
// read contents of block sequentially // read contents of block sequentially
size_t read_bytes = 0; size_t read_bytes = 0;
BlockIter *iter = static_cast<BlockIter *>( BlockIter *iter = static_cast<BlockIter *>(reader.NewIterator(
reader.NewIterator(options.comparator, nullptr, true, stats.get())); options.comparator, options.comparator, nullptr, true, stats.get()));
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
iter->value(); iter->value();
read_bytes += iter->TEST_CurrentEntrySize(); read_bytes += iter->TEST_CurrentEntrySize();
@@ -421,8 +422,8 @@ TEST_F(BlockTest, BlockWithReadAmpBitmap) {
kBytesPerBit, stats.get()); kBytesPerBit, stats.get());
size_t read_bytes = 0; size_t read_bytes = 0;
BlockIter *iter = static_cast<BlockIter *>( BlockIter *iter = static_cast<BlockIter *>(reader.NewIterator(
reader.NewIterator(options.comparator, nullptr, true, stats.get())); options.comparator, options.comparator, nullptr, true, stats.get()));
for (int i = 0; i < num_records; i++) { for (int i = 0; i < num_records; i++) {
Slice k(keys[i]); Slice k(keys[i]);
@@ -457,8 +458,8 @@ TEST_F(BlockTest, BlockWithReadAmpBitmap) {
kBytesPerBit, stats.get()); kBytesPerBit, stats.get());
size_t read_bytes = 0; size_t read_bytes = 0;
BlockIter *iter = static_cast<BlockIter *>( BlockIter *iter = static_cast<BlockIter *>(reader.NewIterator(
reader.NewIterator(options.comparator, nullptr, true, stats.get())); options.comparator, options.comparator, nullptr, true, stats.get()));
std::unordered_set<int> read_keys; std::unordered_set<int> read_keys;
for (int i = 0; i < num_records; i++) { for (int i = 0; i < num_records; i++) {
int index = rnd.Uniform(num_records); int index = rnd.Uniform(num_records);
+4 -1
View File
@@ -141,6 +141,7 @@ CuckooTableReader::CuckooTableReader(
Status CuckooTableReader::Get(const ReadOptions& /*readOptions*/, Status CuckooTableReader::Get(const ReadOptions& /*readOptions*/,
const Slice& key, GetContext* get_context, const Slice& key, GetContext* get_context,
const SliceTransform* /* prefix_extractor */,
bool /*skip_filters*/) { bool /*skip_filters*/) {
assert(key.size() == key_length_ + (is_last_level_ ? 8 : 0)); assert(key.size() == key_length_ + (is_last_level_ ? 8 : 0));
Slice user_key = ExtractUserKey(key); Slice user_key = ExtractUserKey(key);
@@ -377,7 +378,9 @@ extern InternalIterator* NewErrorInternalIterator(const Status& status,
Arena* arena); Arena* arena);
InternalIterator* CuckooTableReader::NewIterator( InternalIterator* CuckooTableReader::NewIterator(
const ReadOptions& /*read_options*/, Arena* arena, bool /*skip_filters*/) { const ReadOptions& /*read_options*/,
const SliceTransform* /* prefix_extractor */, Arena* arena,
bool /*skip_filters*/) {
if (!status().ok()) { if (!status().ok()) {
return NewErrorInternalIterator( return NewErrorInternalIterator(
Status::Corruption("CuckooTableReader status is not okay."), arena); Status::Corruption("CuckooTableReader status is not okay."), arena);
+7 -5
View File
@@ -42,12 +42,14 @@ class CuckooTableReader: public TableReader {
Status status() const { return status_; } Status status() const { return status_; }
Status Get(const ReadOptions& read_options, const Slice& key, Status Get(const ReadOptions& readOptions, const Slice& key,
GetContext* get_context, bool skip_filters = false) override; GetContext* get_context, const SliceTransform* prefix_extractor,
bool skip_filters = false) override;
InternalIterator* NewIterator( InternalIterator* NewIterator(const ReadOptions&,
const ReadOptions&, Arena* arena = nullptr, const SliceTransform* prefix_extractor,
bool skip_filters = false) override; Arena* arena = nullptr,
bool skip_filters = false) override;
void Prepare(const Slice& target) override; void Prepare(const Slice& target) override;
// Report an approximation of how much memory has been used. // Report an approximation of how much memory has been used.
+14 -9
View File
@@ -127,7 +127,8 @@ class CuckooReaderTest : public testing::Test {
GetContext get_context(ucomp, nullptr, nullptr, nullptr, GetContext get_context(ucomp, nullptr, nullptr, nullptr,
GetContext::kNotFound, Slice(user_keys[i]), &value, GetContext::kNotFound, Slice(user_keys[i]), &value,
nullptr, nullptr, nullptr, nullptr); nullptr, nullptr, nullptr, nullptr);
ASSERT_OK(reader.Get(ReadOptions(), Slice(keys[i]), &get_context)); ASSERT_OK(
reader.Get(ReadOptions(), Slice(keys[i]), &get_context, nullptr));
ASSERT_STREQ(values[i].c_str(), value.data()); ASSERT_STREQ(values[i].c_str(), value.data());
} }
} }
@@ -149,7 +150,8 @@ class CuckooReaderTest : public testing::Test {
CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucomp, CuckooTableReader reader(ioptions, std::move(file_reader), file_size, ucomp,
GetSliceHash); GetSliceHash);
ASSERT_OK(reader.status()); ASSERT_OK(reader.status());
InternalIterator* it = reader.NewIterator(ReadOptions(), nullptr); InternalIterator* it =
reader.NewIterator(ReadOptions(), nullptr, nullptr, false);
ASSERT_OK(it->status()); ASSERT_OK(it->status());
ASSERT_TRUE(!it->Valid()); ASSERT_TRUE(!it->Valid());
it->SeekToFirst(); it->SeekToFirst();
@@ -188,7 +190,7 @@ class CuckooReaderTest : public testing::Test {
delete it; delete it;
Arena arena; Arena arena;
it = reader.NewIterator(ReadOptions(), &arena); it = reader.NewIterator(ReadOptions(), nullptr, &arena);
ASSERT_OK(it->status()); ASSERT_OK(it->status());
ASSERT_TRUE(!it->Valid()); ASSERT_TRUE(!it->Valid());
it->Seek(keys[num_items/2]); it->Seek(keys[num_items/2]);
@@ -337,7 +339,8 @@ TEST_F(CuckooReaderTest, WhenKeyNotFound) {
GetContext get_context(ucmp, nullptr, nullptr, nullptr, GetContext::kNotFound, GetContext get_context(ucmp, nullptr, nullptr, nullptr, GetContext::kNotFound,
Slice(not_found_key), &value, nullptr, nullptr, Slice(not_found_key), &value, nullptr, nullptr,
nullptr, nullptr); nullptr, nullptr);
ASSERT_OK(reader.Get(ReadOptions(), Slice(not_found_key), &get_context)); ASSERT_OK(
reader.Get(ReadOptions(), Slice(not_found_key), &get_context, nullptr));
ASSERT_TRUE(value.empty()); ASSERT_TRUE(value.empty());
ASSERT_OK(reader.status()); ASSERT_OK(reader.status());
// Search for a key with an independent hash value. // Search for a key with an independent hash value.
@@ -350,7 +353,8 @@ TEST_F(CuckooReaderTest, WhenKeyNotFound) {
GetContext get_context2(ucmp, nullptr, nullptr, nullptr, GetContext get_context2(ucmp, nullptr, nullptr, nullptr,
GetContext::kNotFound, Slice(not_found_key2), &value, GetContext::kNotFound, Slice(not_found_key2), &value,
nullptr, nullptr, nullptr, nullptr); nullptr, nullptr, nullptr, nullptr);
ASSERT_OK(reader.Get(ReadOptions(), Slice(not_found_key2), &get_context2)); ASSERT_OK(
reader.Get(ReadOptions(), Slice(not_found_key2), &get_context2, nullptr));
ASSERT_TRUE(value.empty()); ASSERT_TRUE(value.empty());
ASSERT_OK(reader.status()); ASSERT_OK(reader.status());
@@ -365,7 +369,8 @@ TEST_F(CuckooReaderTest, WhenKeyNotFound) {
GetContext get_context3(ucmp, nullptr, nullptr, nullptr, GetContext get_context3(ucmp, nullptr, nullptr, nullptr,
GetContext::kNotFound, Slice(unused_key), &value, GetContext::kNotFound, Slice(unused_key), &value,
nullptr, nullptr, nullptr, nullptr); nullptr, nullptr, nullptr, nullptr);
ASSERT_OK(reader.Get(ReadOptions(), Slice(unused_key), &get_context3)); ASSERT_OK(
reader.Get(ReadOptions(), Slice(unused_key), &get_context3, nullptr));
ASSERT_TRUE(value.empty()); ASSERT_TRUE(value.empty());
ASSERT_OK(reader.status()); ASSERT_OK(reader.status());
} }
@@ -443,7 +448,7 @@ void WriteFile(const std::vector<std::string>& keys,
for (uint64_t i = 0; i < num; ++i) { for (uint64_t i = 0; i < num; ++i) {
value.Reset(); value.Reset();
value.clear(); value.clear();
ASSERT_OK(reader.Get(r_options, Slice(keys[i]), &get_context)); ASSERT_OK(reader.Get(r_options, Slice(keys[i]), &get_context, nullptr));
ASSERT_TRUE(Slice(keys[i]) == Slice(&keys[i][0], 4)); ASSERT_TRUE(Slice(keys[i]) == Slice(&keys[i][0], 4));
} }
} }
@@ -496,13 +501,13 @@ void ReadKeys(uint64_t num, uint32_t batch_size) {
} }
for (uint64_t j = i; j < i+batch_size && j < num; ++j) { for (uint64_t j = i; j < i+batch_size && j < num; ++j) {
reader.Get(r_options, Slice(reinterpret_cast<char*>(&keys[j]), 16), reader.Get(r_options, Slice(reinterpret_cast<char*>(&keys[j]), 16),
&get_context); &get_context, nullptr);
} }
} }
} else { } else {
for (uint64_t i = 0; i < num; i++) { for (uint64_t i = 0; i < num; i++) {
reader.Get(r_options, Slice(reinterpret_cast<char*>(&keys[i]), 16), reader.Get(r_options, Slice(reinterpret_cast<char*>(&keys[i]), 16),
&get_context); &get_context, nullptr);
} }
} }
float time_per_op = (env->NowMicros() - start_time) * 1.0f / num; float time_per_op = (env->NowMicros() - start_time) * 1.0f / num;
+8 -2
View File
@@ -93,16 +93,21 @@ class FilterBlockReader {
* built upon InternalKey and must be provided via const_ikey_ptr when running * built upon InternalKey and must be provided via const_ikey_ptr when running
* queries. * queries.
*/ */
virtual bool KeyMayMatch(const Slice& key, uint64_t block_offset = kNotValid, virtual bool KeyMayMatch(const Slice& key,
const SliceTransform* prefix_extractor,
uint64_t block_offset = kNotValid,
const bool no_io = false, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) = 0; const Slice* const const_ikey_ptr = nullptr) = 0;
/** /**
* no_io and const_ikey_ptr here means the same as in KeyMayMatch * no_io and const_ikey_ptr here means the same as in KeyMayMatch
*/ */
virtual bool PrefixMayMatch(const Slice& prefix, virtual bool PrefixMayMatch(const Slice& prefix,
const SliceTransform* prefix_extractor,
uint64_t block_offset = kNotValid, uint64_t block_offset = kNotValid,
const bool no_io = false, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) = 0; const Slice* const const_ikey_ptr = nullptr) = 0;
virtual size_t ApproximateMemoryUsage() const = 0; virtual size_t ApproximateMemoryUsage() const = 0;
virtual size_t size() const { return size_; } virtual size_t size() const { return size_; }
virtual Statistics* statistics() const { return statistics_; } virtual Statistics* statistics() const { return statistics_; }
@@ -115,7 +120,8 @@ class FilterBlockReader {
return error_msg; return error_msg;
} }
virtual void CacheDependencies(bool /*pin*/) {} virtual void CacheDependencies(bool /*pin*/,
const SliceTransform* /*prefix_extractor*/) {}
protected: protected:
bool whole_key_filtering_; bool whole_key_filtering_;
+21 -1
View File
@@ -10,6 +10,13 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <string> #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/options.h"
#include "rocksdb/slice.h" #include "rocksdb/slice.h"
#include "rocksdb/status.h" #include "rocksdb/status.h"
@@ -83,7 +90,7 @@ inline uint32_t GetCompressFormatForVersion(
} }
inline bool BlockBasedTableSupportedVersion(uint32_t version) { inline bool BlockBasedTableSupportedVersion(uint32_t version) {
return version <= 2; return version <= 3;
} }
// Footer encapsulates the fixed information stored at the tail // Footer encapsulates the fixed information stored at the tail
@@ -199,6 +206,19 @@ struct BlockContents {
compression_type(_compression_type), compression_type(_compression_type),
allocation(std::move(_data)) {} 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 { BlockContents(BlockContents&& other) ROCKSDB_NOEXCEPT {
*this = std::move(other); *this = std::move(other);
} }
+29 -5
View File
@@ -5,6 +5,14 @@
#include "table/full_filter_block.h" #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 "monitoring/perf_context_imp.h"
#include "port/port.h" #include "port/port.h"
#include "rocksdb/filter_policy.h" #include "rocksdb/filter_policy.h"
@@ -72,8 +80,14 @@ 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*/, Slice FullFilterBlockBuilder::Finish(const BlockHandle& /*tmp*/,
Status* status) { Status* status) {
Reset();
// In this impl we ignore BlockHandle // In this impl we ignore BlockHandle
*status = Status::OK(); *status = Status::OK();
if (num_added_ != 0) { if (num_added_ != 0) {
@@ -103,9 +117,10 @@ FullFilterBlockReader::FullFilterBlockReader(
block_contents_ = std::move(contents); block_contents_ = std::move(contents);
} }
bool FullFilterBlockReader::KeyMayMatch(const Slice& key, uint64_t block_offset, bool FullFilterBlockReader::KeyMayMatch(
const bool /*no_io*/, const Slice& key, const SliceTransform* /*prefix_extractor*/,
const Slice* const /*const_ikey_ptr*/) { uint64_t block_offset, const bool /*no_io*/,
const Slice* const /*const_ikey_ptr*/) {
#ifdef NDEBUG #ifdef NDEBUG
(void)block_offset; (void)block_offset;
#endif #endif
@@ -117,7 +132,8 @@ bool FullFilterBlockReader::KeyMayMatch(const Slice& key, uint64_t block_offset,
} }
bool FullFilterBlockReader::PrefixMayMatch( bool FullFilterBlockReader::PrefixMayMatch(
const Slice& prefix, uint64_t block_offset, const bool /*no_io*/, const Slice& prefix, const SliceTransform* /* prefix_extractor */,
uint64_t block_offset, const bool /*no_io*/,
const Slice* const /*const_ikey_ptr*/) { const Slice* const /*const_ikey_ptr*/) {
#ifdef NDEBUG #ifdef NDEBUG
(void)block_offset; (void)block_offset;
@@ -143,6 +159,14 @@ bool FullFilterBlockReader::MayMatch(const Slice& entry) {
} }
size_t FullFilterBlockReader::ApproximateMemoryUsage() const { size_t FullFilterBlockReader::ApproximateMemoryUsage() const {
return contents_.size(); 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;
} }
} // namespace rocksdb } // namespace rocksdb
+7 -5
View File
@@ -52,6 +52,7 @@ class FullFilterBlockBuilder : public FilterBlockBuilder {
protected: protected:
virtual void AddKey(const Slice& key); virtual void AddKey(const Slice& key);
std::unique_ptr<FilterBitsBuilder> filter_bits_builder_; std::unique_ptr<FilterBitsBuilder> filter_bits_builder_;
virtual void Reset();
private: private:
// important: all of these might point to invalid addresses // important: all of these might point to invalid addresses
@@ -96,13 +97,15 @@ class FullFilterBlockReader : public FilterBlockReader {
~FullFilterBlockReader() {} ~FullFilterBlockReader() {}
virtual bool IsBlockBased() override { return false; } virtual bool IsBlockBased() override { return false; }
virtual bool KeyMayMatch( virtual bool KeyMayMatch(
const Slice& key, uint64_t block_offset = kNotValid, const Slice& key, const SliceTransform* prefix_extractor,
const bool no_io = false, uint64_t block_offset = kNotValid, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) override; const Slice* const const_ikey_ptr = nullptr) override;
virtual bool PrefixMayMatch( virtual bool PrefixMayMatch(
const Slice& prefix, uint64_t block_offset = kNotValid, const Slice& prefix, const SliceTransform* prefix_extractor,
const bool no_io = false, uint64_t block_offset = kNotValid, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) override; const Slice* const const_ikey_ptr = nullptr) override;
virtual size_t ApproximateMemoryUsage() const override; virtual size_t ApproximateMemoryUsage() const override;
@@ -111,7 +114,6 @@ class FullFilterBlockReader : public FilterBlockReader {
Slice contents_; Slice contents_;
std::unique_ptr<FilterBitsReader> filter_bits_reader_; std::unique_ptr<FilterBitsReader> filter_bits_reader_;
BlockContents block_contents_; BlockContents block_contents_;
std::unique_ptr<const char[]> filter_data_;
// No copying allowed // No copying allowed
FullFilterBlockReader(const FullFilterBlockReader&); FullFilterBlockReader(const FullFilterBlockReader&);
+16 -16
View File
@@ -113,7 +113,7 @@ TEST_F(PluginFullFilterBlockTest, PluginEmptyBuilder) {
nullptr, true, block, nullptr, true, block,
table_options_.filter_policy->GetFilterBitsReader(block), nullptr); table_options_.filter_policy->GetFilterBitsReader(block), nullptr);
// Remain same symantic with blockbased filter // Remain same symantic with blockbased filter
ASSERT_TRUE(reader.KeyMayMatch("foo")); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr));
} }
TEST_F(PluginFullFilterBlockTest, PluginSingleChunk) { TEST_F(PluginFullFilterBlockTest, PluginSingleChunk) {
@@ -128,13 +128,13 @@ TEST_F(PluginFullFilterBlockTest, PluginSingleChunk) {
FullFilterBlockReader reader( FullFilterBlockReader reader(
nullptr, true, block, nullptr, true, block,
table_options_.filter_policy->GetFilterBitsReader(block), nullptr); table_options_.filter_policy->GetFilterBitsReader(block), nullptr);
ASSERT_TRUE(reader.KeyMayMatch("foo")); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("bar")); ASSERT_TRUE(reader.KeyMayMatch("bar", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("box")); ASSERT_TRUE(reader.KeyMayMatch("box", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("hello")); ASSERT_TRUE(reader.KeyMayMatch("hello", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("foo")); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr));
ASSERT_TRUE(!reader.KeyMayMatch("missing")); ASSERT_TRUE(!reader.KeyMayMatch("missing", nullptr));
ASSERT_TRUE(!reader.KeyMayMatch("other")); ASSERT_TRUE(!reader.KeyMayMatch("other", nullptr));
} }
class FullFilterBlockTest : public testing::Test { class FullFilterBlockTest : public testing::Test {
@@ -158,7 +158,7 @@ TEST_F(FullFilterBlockTest, EmptyBuilder) {
nullptr, true, block, nullptr, true, block,
table_options_.filter_policy->GetFilterBitsReader(block), nullptr); table_options_.filter_policy->GetFilterBitsReader(block), nullptr);
// Remain same symantic with blockbased filter // Remain same symantic with blockbased filter
ASSERT_TRUE(reader.KeyMayMatch("foo")); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr));
} }
TEST_F(FullFilterBlockTest, DuplicateEntries) { TEST_F(FullFilterBlockTest, DuplicateEntries) {
@@ -208,13 +208,13 @@ TEST_F(FullFilterBlockTest, SingleChunk) {
FullFilterBlockReader reader( FullFilterBlockReader reader(
nullptr, true, block, nullptr, true, block,
table_options_.filter_policy->GetFilterBitsReader(block), nullptr); table_options_.filter_policy->GetFilterBitsReader(block), nullptr);
ASSERT_TRUE(reader.KeyMayMatch("foo")); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("bar")); ASSERT_TRUE(reader.KeyMayMatch("bar", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("box")); ASSERT_TRUE(reader.KeyMayMatch("box", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("hello")); ASSERT_TRUE(reader.KeyMayMatch("hello", nullptr));
ASSERT_TRUE(reader.KeyMayMatch("foo")); ASSERT_TRUE(reader.KeyMayMatch("foo", nullptr));
ASSERT_TRUE(!reader.KeyMayMatch("missing")); ASSERT_TRUE(!reader.KeyMayMatch("missing", nullptr));
ASSERT_TRUE(!reader.KeyMayMatch("other")); ASSERT_TRUE(!reader.KeyMayMatch("other", nullptr));
} }
} // namespace rocksdb } // namespace rocksdb
+36 -8
View File
@@ -31,13 +31,15 @@ IndexBuilder* IndexBuilder::CreateIndexBuilder(
IndexBuilder* result = nullptr; IndexBuilder* result = nullptr;
switch (index_type) { switch (index_type) {
case BlockBasedTableOptions::kBinarySearch: { case BlockBasedTableOptions::kBinarySearch: {
result = new ShortenedIndexBuilder(comparator, result = new ShortenedIndexBuilder(comparator,
table_opt.index_block_restart_interval); table_opt.index_block_restart_interval,
table_opt.format_version);
} }
break; break;
case BlockBasedTableOptions::kHashSearch: { case BlockBasedTableOptions::kHashSearch: {
result = new HashIndexBuilder(comparator, int_key_slice_transform, result = new HashIndexBuilder(comparator, int_key_slice_transform,
table_opt.index_block_restart_interval); table_opt.index_block_restart_interval,
table_opt.format_version);
} }
break; break;
case BlockBasedTableOptions::kTwoLevelIndexSearch: { case BlockBasedTableOptions::kTwoLevelIndexSearch: {
@@ -62,9 +64,13 @@ PartitionedIndexBuilder::PartitionedIndexBuilder(
const InternalKeyComparator* comparator, const InternalKeyComparator* comparator,
const BlockBasedTableOptions& table_opt) const BlockBasedTableOptions& table_opt)
: IndexBuilder(comparator), : IndexBuilder(comparator),
index_block_builder_(table_opt.index_block_restart_interval), 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),
sub_index_builder_(nullptr), sub_index_builder_(nullptr),
table_opt_(table_opt) {} table_opt_(table_opt),
seperator_is_key_plus_seq_(false) {}
PartitionedIndexBuilder::~PartitionedIndexBuilder() { PartitionedIndexBuilder::~PartitionedIndexBuilder() {
delete sub_index_builder_; delete sub_index_builder_;
@@ -73,7 +79,8 @@ PartitionedIndexBuilder::~PartitionedIndexBuilder() {
void PartitionedIndexBuilder::MakeNewSubIndexBuilder() { void PartitionedIndexBuilder::MakeNewSubIndexBuilder() {
assert(sub_index_builder_ == nullptr); assert(sub_index_builder_ == nullptr);
sub_index_builder_ = new ShortenedIndexBuilder( sub_index_builder_ = new ShortenedIndexBuilder(
comparator_, table_opt_.index_block_restart_interval); comparator_, table_opt_.index_block_restart_interval,
table_opt_.format_version);
flush_policy_.reset(FlushBlockBySizePolicyFactory::NewFlushBlockPolicy( flush_policy_.reset(FlushBlockBySizePolicyFactory::NewFlushBlockPolicy(
table_opt_.metadata_block_size, table_opt_.block_size_deviation, table_opt_.metadata_block_size, table_opt_.block_size_deviation,
sub_index_builder_->index_block_builder_)); sub_index_builder_->index_block_builder_));
@@ -95,6 +102,10 @@ void PartitionedIndexBuilder::AddIndexEntry(
} }
sub_index_builder_->AddIndexEntry(last_key_in_current_block, sub_index_builder_->AddIndexEntry(last_key_in_current_block,
first_key_in_next_block, block_handle); 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); sub_index_last_key_ = std::string(*last_key_in_current_block);
entries_.push_back( entries_.push_back(
{sub_index_last_key_, {sub_index_last_key_,
@@ -123,6 +134,10 @@ void PartitionedIndexBuilder::AddIndexEntry(
sub_index_builder_->AddIndexEntry(last_key_in_current_block, sub_index_builder_->AddIndexEntry(last_key_in_current_block,
first_key_in_next_block, block_handle); first_key_in_next_block, block_handle);
sub_index_last_key_ = std::string(*last_key_in_current_block); 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;
}
} }
} }
@@ -136,16 +151,27 @@ Status PartitionedIndexBuilder::Finish(
std::string handle_encoding; std::string handle_encoding;
last_partition_block_handle.EncodeTo(&handle_encoding); last_partition_block_handle.EncodeTo(&handle_encoding);
index_block_builder_.Add(last_entry.key, 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(); entries_.pop_front();
} }
// If there is no sub_index left, then return the 2nd level index. // If there is no sub_index left, then return the 2nd level index.
if (UNLIKELY(entries_.empty())) { if (UNLIKELY(entries_.empty())) {
index_blocks->index_block_contents = index_block_builder_.Finish(); 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();
}
return Status::OK(); return Status::OK();
} else { } else {
// Finish the next partition index in line and Incomplete() to indicate we // Finish the next partition index in line and Incomplete() to indicate we
// expect more calls to Finish // expect more calls to Finish
Entry& entry = entries_.front(); 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); auto s = entry.value->Finish(index_blocks);
finishing_indexes = true; finishing_indexes = true;
return s.ok() ? Status::Incomplete() : s; return s.ok() ? Status::Incomplete() : s;
@@ -177,7 +203,9 @@ size_t PartitionedIndexBuilder::EstimateTopLevelIndexSize(
uint64_t size = it->value->EstimatedSize(); uint64_t size = it->value->EstimatedSize();
BlockHandle tmp_block_handle(offset, size); BlockHandle tmp_block_handle(offset, size);
tmp_block_handle.EncodeTo(&tmp_handle_encoding); tmp_block_handle.EncodeTo(&tmp_handle_encoding);
tmp_builder.Add(it->key, tmp_handle_encoding); tmp_builder.Add(
seperator_is_key_plus_seq_ ? it->key : ExtractUserKey(it->key),
tmp_handle_encoding);
offset += size; offset += size;
} }
return tmp_builder.CurrentSizeEstimate(); return tmp_builder.CurrentSizeEstimate();
+52 -7
View File
@@ -99,6 +99,8 @@ class IndexBuilder {
// Get the estimated size for index block. // Get the estimated size for index block.
virtual size_t EstimatedSize() const = 0; virtual size_t EstimatedSize() const = 0;
virtual bool seperator_is_key_plus_seq() { return true; }
protected: protected:
const InternalKeyComparator* comparator_; const InternalKeyComparator* comparator_;
}; };
@@ -115,9 +117,14 @@ class IndexBuilder {
class ShortenedIndexBuilder : public IndexBuilder { class ShortenedIndexBuilder : public IndexBuilder {
public: public:
explicit ShortenedIndexBuilder(const InternalKeyComparator* comparator, explicit ShortenedIndexBuilder(const InternalKeyComparator* comparator,
int index_block_restart_interval) int index_block_restart_interval,
uint32_t format_version)
: IndexBuilder(comparator), : IndexBuilder(comparator),
index_block_builder_(index_block_restart_interval) {} 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);
}
virtual void AddIndexEntry(std::string* last_key_in_current_block, virtual void AddIndexEntry(std::string* last_key_in_current_block,
const Slice* first_key_in_next_block, const Slice* first_key_in_next_block,
@@ -125,31 +132,57 @@ class ShortenedIndexBuilder : public IndexBuilder {
if (first_key_in_next_block != nullptr) { if (first_key_in_next_block != nullptr) {
comparator_->FindShortestSeparator(last_key_in_current_block, comparator_->FindShortestSeparator(last_key_in_current_block,
*first_key_in_next_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 { } else {
comparator_->FindShortSuccessor(last_key_in_current_block); comparator_->FindShortSuccessor(last_key_in_current_block);
} }
auto sep = Slice(*last_key_in_current_block);
std::string handle_encoding; std::string handle_encoding;
block_handle.EncodeTo(&handle_encoding); block_handle.EncodeTo(&handle_encoding);
index_block_builder_.Add(*last_key_in_current_block, 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);
}
} }
using IndexBuilder::Finish; using IndexBuilder::Finish;
virtual Status Finish( virtual Status Finish(
IndexBlocks* index_blocks, IndexBlocks* index_blocks,
const BlockHandle& /*last_partition_block_handle*/) override { const BlockHandle& /*last_partition_block_handle*/) override {
index_blocks->index_block_contents = index_block_builder_.Finish(); 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();
}
return Status::OK(); return Status::OK();
} }
virtual size_t EstimatedSize() const override { virtual size_t EstimatedSize() const override {
return index_block_builder_.CurrentSizeEstimate(); 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_;
} }
friend class PartitionedIndexBuilder; friend class PartitionedIndexBuilder;
private: private:
BlockBuilder index_block_builder_; 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 // HashIndexBuilder contains a binary-searchable primary index and the
@@ -183,9 +216,11 @@ class HashIndexBuilder : public IndexBuilder {
public: public:
explicit HashIndexBuilder(const InternalKeyComparator* comparator, explicit HashIndexBuilder(const InternalKeyComparator* comparator,
const SliceTransform* hash_key_extractor, const SliceTransform* hash_key_extractor,
int index_block_restart_interval) int index_block_restart_interval,
int format_version)
: IndexBuilder(comparator), : IndexBuilder(comparator),
primary_index_builder_(comparator, index_block_restart_interval), primary_index_builder_(comparator, index_block_restart_interval,
format_version),
hash_key_extractor_(hash_key_extractor) {} hash_key_extractor_(hash_key_extractor) {}
virtual void AddIndexEntry(std::string* last_key_in_current_block, virtual void AddIndexEntry(std::string* last_key_in_current_block,
@@ -240,6 +275,10 @@ class HashIndexBuilder : public IndexBuilder {
prefix_meta_block_.size(); prefix_meta_block_.size();
} }
virtual bool seperator_is_key_plus_seq() override {
return primary_index_builder_.seperator_is_key_plus_seq();
}
private: private:
void FlushPendingPrefix() { void FlushPendingPrefix() {
prefix_block_.append(pending_entry_prefix_.data(), prefix_block_.append(pending_entry_prefix_.data(),
@@ -316,6 +355,10 @@ class PartitionedIndexBuilder : public IndexBuilder {
// cutting the next partition // cutting the next partition
void RequestPartitionCut(); void RequestPartitionCut();
virtual bool seperator_is_key_plus_seq() override {
return seperator_is_key_plus_seq_;
}
private: private:
void MakeNewSubIndexBuilder(); void MakeNewSubIndexBuilder();
@@ -325,6 +368,7 @@ class PartitionedIndexBuilder : public IndexBuilder {
}; };
std::list<Entry> entries_; // list of partitioned indexes and their keys std::list<Entry> entries_; // list of partitioned indexes and their keys
BlockBuilder index_block_builder_; // top-level index builder BlockBuilder index_block_builder_; // top-level index builder
BlockBuilder index_block_builder_without_seq_; // same for user keys
// the active partition index builder // the active partition index builder
ShortenedIndexBuilder* sub_index_builder_; ShortenedIndexBuilder* sub_index_builder_;
// the last key in the active partition index builder // the last key in the active partition index builder
@@ -333,6 +377,7 @@ class PartitionedIndexBuilder : public IndexBuilder {
// true if Finish is called once but not complete yet. // true if Finish is called once but not complete yet.
bool finishing_indexes = false; bool finishing_indexes = false;
const BlockBasedTableOptions& table_opt_; const BlockBasedTableOptions& table_opt_;
bool seperator_is_key_plus_seq_;
// true if an external entity (such as filter partition builder) request // true if an external entity (such as filter partition builder) request
// cutting the next partition // cutting the next partition
bool partition_cut_requested_ = true; bool partition_cut_requested_ = true;
+5 -21
View File
@@ -228,28 +228,12 @@ class MergingIterator : public InternalIterator {
Slice target = key(); Slice target = key();
for (auto& child : children_) { for (auto& child : children_) {
if (&child != current_) { if (&child != current_) {
if (!prefix_seek_mode_) { child.SeekForPrev(target);
child.Seek(target); TEST_SYNC_POINT_CALLBACK("MergeIterator::Prev:BeforePrev", &child);
if (child.Valid()) { considerStatus(child.status());
// Child is at first entry >= key(). Step back one to be < key() if (child.Valid() && comparator_->Equal(target, child.key())) {
TEST_SYNC_POINT_CALLBACK("MergeIterator::Prev:BeforePrev", child.Prev();
&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()); 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()) { if (child.Valid()) {
+10 -4
View File
@@ -71,6 +71,7 @@ void PropertyBlockBuilder::AddTableProperty(const TableProperties& props) {
Add(TablePropertiesNames::kIndexPartitions, props.index_partitions); Add(TablePropertiesNames::kIndexPartitions, props.index_partitions);
Add(TablePropertiesNames::kTopLevelIndexSize, props.top_level_index_size); 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::kNumEntries, props.num_entries);
Add(TablePropertiesNames::kNumDataBlocks, props.num_data_blocks); Add(TablePropertiesNames::kNumDataBlocks, props.num_data_blocks);
Add(TablePropertiesNames::kFilterSize, props.filter_size); Add(TablePropertiesNames::kFilterSize, props.filter_size);
@@ -192,7 +193,8 @@ Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
Block properties_block(std::move(block_contents), Block properties_block(std::move(block_contents),
kDisableGlobalSequenceNumber); kDisableGlobalSequenceNumber);
BlockIter iter; BlockIter iter;
properties_block.NewIterator(BytewiseComparator(), &iter); properties_block.NewIterator(BytewiseComparator(), BytewiseComparator(),
&iter);
auto new_table_properties = new TableProperties(); auto new_table_properties = new TableProperties();
// All pre-defined properties of type uint64_t // All pre-defined properties of type uint64_t
@@ -203,6 +205,8 @@ Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
&new_table_properties->index_partitions}, &new_table_properties->index_partitions},
{TablePropertiesNames::kTopLevelIndexSize, {TablePropertiesNames::kTopLevelIndexSize,
&new_table_properties->top_level_index_size}, &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::kFilterSize, &new_table_properties->filter_size},
{TablePropertiesNames::kRawKeySize, &new_table_properties->raw_key_size}, {TablePropertiesNames::kRawKeySize, &new_table_properties->raw_key_size},
{TablePropertiesNames::kRawValueSize, {TablePropertiesNames::kRawValueSize,
@@ -312,7 +316,7 @@ Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
Block metaindex_block(std::move(metaindex_contents), Block metaindex_block(std::move(metaindex_contents),
kDisableGlobalSequenceNumber); kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter( std::unique_ptr<InternalIterator> meta_iter(
metaindex_block.NewIterator(BytewiseComparator())); metaindex_block.NewIterator(BytewiseComparator(), BytewiseComparator()));
// -- Read property block // -- Read property block
bool found_properties_block = true; bool found_properties_block = true;
@@ -375,7 +379,8 @@ Status FindMetaBlock(RandomAccessFileReader* file, uint64_t file_size,
kDisableGlobalSequenceNumber); kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter; std::unique_ptr<InternalIterator> meta_iter;
meta_iter.reset(metaindex_block.NewIterator(BytewiseComparator())); meta_iter.reset(
metaindex_block.NewIterator(BytewiseComparator(), BytewiseComparator()));
return FindMetaBlock(meta_iter.get(), meta_block_name, block_handle); return FindMetaBlock(meta_iter.get(), meta_block_name, block_handle);
} }
@@ -416,7 +421,8 @@ Status ReadMetaBlock(RandomAccessFileReader* file,
kDisableGlobalSequenceNumber); kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter; std::unique_ptr<InternalIterator> meta_iter;
meta_iter.reset(metaindex_block.NewIterator(BytewiseComparator())); meta_iter.reset(
metaindex_block.NewIterator(BytewiseComparator(), BytewiseComparator()));
BlockHandle block_handle; BlockHandle block_handle;
status = FindMetaBlock(meta_iter.get(), meta_block_name, &block_handle); status = FindMetaBlock(meta_iter.get(), meta_block_name, &block_handle);
+6 -4
View File
@@ -26,14 +26,16 @@ stl_wrappers::KVMap MakeMockFile(
return stl_wrappers::KVMap(l, stl_wrappers::LessOfComparator(&icmp_)); return stl_wrappers::KVMap(l, stl_wrappers::LessOfComparator(&icmp_));
} }
InternalIterator* MockTableReader::NewIterator(const ReadOptions&, InternalIterator* MockTableReader::NewIterator(
Arena* /*arena*/, const ReadOptions&, const SliceTransform* /* prefix_extractor */,
bool /*skip_filters*/) { Arena* /*arena*/, bool /*skip_filters*/) {
return new MockTableIterator(table_); return new MockTableIterator(table_);
} }
Status MockTableReader::Get(const ReadOptions&, const Slice& key, Status MockTableReader::Get(const ReadOptions&, const Slice& key,
GetContext* get_context, bool /*skip_filters*/) { GetContext* get_context,
const SliceTransform* /*prefix_extractor*/,
bool /*skip_filters*/) {
std::unique_ptr<MockTableIterator> iter(new MockTableIterator(table_)); std::unique_ptr<MockTableIterator> iter(new MockTableIterator(table_));
for (iter->Seek(key); iter->Valid(); iter->Next()) { for (iter->Seek(key); iter->Valid(); iter->Next()) {
ParsedInternalKey parsed_key; ParsedInternalKey parsed_key;
+4 -2
View File
@@ -39,10 +39,12 @@ class MockTableReader : public TableReader {
explicit MockTableReader(const stl_wrappers::KVMap& table) : table_(table) {} explicit MockTableReader(const stl_wrappers::KVMap& table) : table_(table) {}
InternalIterator* NewIterator(const ReadOptions&, InternalIterator* NewIterator(const ReadOptions&,
Arena* arena, const SliceTransform* prefix_extractor,
Arena* arena = nullptr,
bool skip_filters = false) override; bool skip_filters = false) override;
Status Get(const ReadOptions&, const Slice& key, GetContext* get_context, Status Get(const ReadOptions& readOptions, const Slice& key,
GetContext* get_context, const SliceTransform* prefix_extractor,
bool skip_filters = false) override; bool skip_filters = false) override;
uint64_t ApproximateOffsetOf(const Slice& /*key*/) override { return 0; } uint64_t ApproximateOffsetOf(const Slice& /*key*/) override { return 0; }
+58 -23
View File
@@ -5,6 +5,13 @@
#include "table/partitioned_filter_block.h" #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 <utility>
#include "monitoring/perf_context_imp.h" #include "monitoring/perf_context_imp.h"
@@ -24,6 +31,7 @@ PartitionedFilterBlockBuilder::PartitionedFilterBlockBuilder(
: FullFilterBlockBuilder(prefix_extractor, whole_key_filtering, : FullFilterBlockBuilder(prefix_extractor, whole_key_filtering,
filter_bits_builder), filter_bits_builder),
index_on_filter_block_builder_(index_block_restart_interval), 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), p_index_builder_(p_index_builder),
filters_in_partition_(0), filters_in_partition_(0),
num_added_(0) { num_added_(0) {
@@ -48,6 +56,7 @@ void PartitionedFilterBlockBuilder::MaybeCutAFilterBlock() {
std::string& index_key = p_index_builder_->GetPartitionKey(); std::string& index_key = p_index_builder_->GetPartitionKey();
filters.push_back({index_key, filter}); filters.push_back({index_key, filter});
filters_in_partition_ = 0; filters_in_partition_ = 0;
Reset();
} }
void PartitionedFilterBlockBuilder::AddKey(const Slice& key) { void PartitionedFilterBlockBuilder::AddKey(const Slice& key) {
@@ -65,6 +74,10 @@ Slice PartitionedFilterBlockBuilder::Finish(
std::string handle_encoding; std::string handle_encoding;
last_partition_block_handle.EncodeTo(&handle_encoding); last_partition_block_handle.EncodeTo(&handle_encoding);
index_on_filter_block_builder_.Add(last_entry.key, 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(); filters.pop_front();
} else { } else {
MaybeCutAFilterBlock(); MaybeCutAFilterBlock();
@@ -74,7 +87,11 @@ Slice PartitionedFilterBlockBuilder::Finish(
if (UNLIKELY(filters.empty())) { if (UNLIKELY(filters.empty())) {
*status = Status::OK(); *status = Status::OK();
if (finishing_filters) { if (finishing_filters) {
return index_on_filter_block_builder_.Finish(); 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();
}
} else { } else {
// This is the rare case where no key was added to the filter // This is the rare case where no key was added to the filter
return Slice(); return Slice();
@@ -91,12 +108,13 @@ Slice PartitionedFilterBlockBuilder::Finish(
PartitionedFilterBlockReader::PartitionedFilterBlockReader( PartitionedFilterBlockReader::PartitionedFilterBlockReader(
const SliceTransform* prefix_extractor, bool _whole_key_filtering, const SliceTransform* prefix_extractor, bool _whole_key_filtering,
BlockContents&& contents, FilterBitsReader* /*filter_bits_reader*/, BlockContents&& contents, FilterBitsReader* /*filter_bits_reader*/,
Statistics* stats, const Comparator& comparator, Statistics* stats, const InternalKeyComparator comparator,
const BlockBasedTable* table) const BlockBasedTable* table, const bool index_key_includes_seq)
: FilterBlockReader(contents.data.size(), stats, _whole_key_filtering), : FilterBlockReader(contents.data.size(), stats, _whole_key_filtering),
prefix_extractor_(prefix_extractor), prefix_extractor_(prefix_extractor),
comparator_(comparator), comparator_(comparator),
table_(table) { table_(table),
index_key_includes_seq_(index_key_includes_seq) {
idx_on_fltr_blk_.reset(new Block(std::move(contents), idx_on_fltr_blk_.reset(new Block(std::move(contents),
kDisableGlobalSequenceNumber, kDisableGlobalSequenceNumber,
0 /* read_amp_bytes_per_bit */, stats)); 0 /* read_amp_bytes_per_bit */, stats));
@@ -113,7 +131,8 @@ PartitionedFilterBlockReader::~PartitionedFilterBlockReader() {
char cache_key[BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length]; char cache_key[BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length];
BlockIter biter; BlockIter biter;
BlockHandle handle; BlockHandle handle;
idx_on_fltr_blk_->NewIterator(&comparator_, &biter, true); idx_on_fltr_blk_->NewIterator(&comparator_, comparator_.user_comparator(),
&biter, true, nullptr, index_key_includes_seq_);
biter.SeekToFirst(); biter.SeekToFirst();
for (; biter.Valid(); biter.Next()) { for (; biter.Valid(); biter.Next()) {
auto input = biter.value(); auto input = biter.value();
@@ -130,7 +149,8 @@ PartitionedFilterBlockReader::~PartitionedFilterBlockReader() {
} }
bool PartitionedFilterBlockReader::KeyMayMatch( bool PartitionedFilterBlockReader::KeyMayMatch(
const Slice& key, uint64_t block_offset, const bool no_io, const Slice& key, const SliceTransform* prefix_extractor,
uint64_t block_offset, const bool no_io,
const Slice* const const_ikey_ptr) { const Slice* const const_ikey_ptr) {
assert(const_ikey_ptr != nullptr); assert(const_ikey_ptr != nullptr);
assert(block_offset == kNotValid); assert(block_offset == kNotValid);
@@ -145,12 +165,14 @@ bool PartitionedFilterBlockReader::KeyMayMatch(
return false; return false;
} }
bool cached = false; bool cached = false;
auto filter_partition = GetFilterPartition(nullptr /* prefetch_buffer */, auto filter_partition =
&filter_handle, no_io, &cached); GetFilterPartition(nullptr /* prefetch_buffer */, &filter_handle, no_io,
&cached, prefix_extractor);
if (UNLIKELY(!filter_partition.value)) { if (UNLIKELY(!filter_partition.value)) {
return true; return true;
} }
auto res = filter_partition.value->KeyMayMatch(key, block_offset, no_io); auto res = filter_partition.value->KeyMayMatch(key, prefix_extractor,
block_offset, no_io);
if (cached) { if (cached) {
return res; return res;
} }
@@ -163,7 +185,8 @@ bool PartitionedFilterBlockReader::KeyMayMatch(
} }
bool PartitionedFilterBlockReader::PrefixMayMatch( bool PartitionedFilterBlockReader::PrefixMayMatch(
const Slice& prefix, uint64_t block_offset, const bool no_io, const Slice& prefix, const SliceTransform* prefix_extractor,
uint64_t block_offset, const bool no_io,
const Slice* const const_ikey_ptr) { const Slice* const const_ikey_ptr) {
#ifdef NDEBUG #ifdef NDEBUG
(void)block_offset; (void)block_offset;
@@ -181,12 +204,14 @@ bool PartitionedFilterBlockReader::PrefixMayMatch(
return false; return false;
} }
bool cached = false; bool cached = false;
auto filter_partition = GetFilterPartition(nullptr /* prefetch_buffer */, auto filter_partition =
&filter_handle, no_io, &cached); GetFilterPartition(nullptr /* prefetch_buffer */, &filter_handle, no_io,
&cached, prefix_extractor);
if (UNLIKELY(!filter_partition.value)) { if (UNLIKELY(!filter_partition.value)) {
return true; return true;
} }
auto res = filter_partition.value->PrefixMayMatch(prefix, kNotValid, no_io); auto res = filter_partition.value->PrefixMayMatch(prefix, prefix_extractor,
kNotValid, no_io);
if (cached) { if (cached) {
return res; return res;
} }
@@ -201,7 +226,8 @@ bool PartitionedFilterBlockReader::PrefixMayMatch(
Slice PartitionedFilterBlockReader::GetFilterPartitionHandle( Slice PartitionedFilterBlockReader::GetFilterPartitionHandle(
const Slice& entry) { const Slice& entry) {
BlockIter iter; BlockIter iter;
idx_on_fltr_blk_->NewIterator(&comparator_, &iter, true); idx_on_fltr_blk_->NewIterator(&comparator_, comparator_.user_comparator(),
&iter, true, nullptr, index_key_includes_seq_);
iter.Seek(entry); iter.Seek(entry);
if (UNLIKELY(!iter.Valid())) { if (UNLIKELY(!iter.Valid())) {
return Slice(); return Slice();
@@ -214,7 +240,7 @@ Slice PartitionedFilterBlockReader::GetFilterPartitionHandle(
BlockBasedTable::CachableEntry<FilterBlockReader> BlockBasedTable::CachableEntry<FilterBlockReader>
PartitionedFilterBlockReader::GetFilterPartition( PartitionedFilterBlockReader::GetFilterPartition(
FilePrefetchBuffer* prefetch_buffer, Slice* handle_value, const bool no_io, FilePrefetchBuffer* prefetch_buffer, Slice* handle_value, const bool no_io,
bool* cached) { bool* cached, const SliceTransform* prefix_extractor) {
BlockHandle fltr_blk_handle; BlockHandle fltr_blk_handle;
auto s = fltr_blk_handle.DecodeFrom(handle_value); auto s = fltr_blk_handle.DecodeFrom(handle_value);
assert(s.ok()); assert(s.ok());
@@ -237,16 +263,23 @@ PartitionedFilterBlockReader::GetFilterPartition(
} }
return table_->GetFilter(/*prefetch_buffer*/ nullptr, fltr_blk_handle, return table_->GetFilter(/*prefetch_buffer*/ nullptr, fltr_blk_handle,
is_a_filter_partition, no_io, is_a_filter_partition, no_io,
/* get_context */ nullptr); /* get_context */ nullptr, prefix_extractor);
} else { } else {
auto filter = table_->ReadFilter(prefetch_buffer, fltr_blk_handle, auto filter = table_->ReadFilter(prefetch_buffer, fltr_blk_handle,
is_a_filter_partition); is_a_filter_partition, prefix_extractor);
return {filter, nullptr}; return {filter, nullptr};
} }
} }
size_t PartitionedFilterBlockReader::ApproximateMemoryUsage() const { size_t PartitionedFilterBlockReader::ApproximateMemoryUsage() const {
return idx_on_fltr_blk_->size(); 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
} }
// Release the cached entry and decrement its ref count. // Release the cached entry and decrement its ref count.
@@ -257,12 +290,14 @@ void ReleaseFilterCachedEntry(void* arg, void* h) {
} }
// TODO(myabandeh): merge this with the same function in IndexReader // TODO(myabandeh): merge this with the same function in IndexReader
void PartitionedFilterBlockReader::CacheDependencies(bool pin) { void PartitionedFilterBlockReader::CacheDependencies(
bool pin, const SliceTransform* prefix_extractor) {
// Before read partitions, prefetch them to avoid lots of IOs // Before read partitions, prefetch them to avoid lots of IOs
auto rep = table_->rep_; auto rep = table_->rep_;
BlockIter biter; BlockIter biter;
BlockHandle handle; BlockHandle handle;
idx_on_fltr_blk_->NewIterator(&comparator_, &biter, true); idx_on_fltr_blk_->NewIterator(&comparator_, comparator_.user_comparator(),
&biter, true, nullptr, index_key_includes_seq_);
// Index partitions are assumed to be consecuitive. Prefetch them all. // Index partitions are assumed to be consecuitive. Prefetch them all.
// Read the first block offset // Read the first block offset
biter.SeekToFirst(); biter.SeekToFirst();
@@ -308,9 +343,9 @@ void PartitionedFilterBlockReader::CacheDependencies(bool pin) {
const bool no_io = true; const bool no_io = true;
const bool is_a_filter_partition = true; const bool is_a_filter_partition = true;
auto filter = table_->GetFilter(prefetch_buffer.get(), handle, auto filter = table_->GetFilter(
is_a_filter_partition, !no_io, prefetch_buffer.get(), handle, is_a_filter_partition, !no_io,
/* get_context */ nullptr); /* get_context */ nullptr, prefix_extractor);
if (LIKELY(filter.IsSet())) { if (LIKELY(filter.IsSet())) {
if (pin) { if (pin) {
filter_map_[handle.offset()] = std::move(filter); filter_map_[handle.offset()] = std::move(filter);
+16 -14
View File
@@ -41,6 +41,8 @@ class PartitionedFilterBlockBuilder : public FullFilterBlockBuilder {
private: private:
// Filter data // Filter data
BlockBuilder index_on_filter_block_builder_; // top-level index builder BlockBuilder index_on_filter_block_builder_; // top-level index builder
BlockBuilder
index_on_filter_block_builder_without_seq_; // same for user keys
struct FilterEntry { struct FilterEntry {
std::string key; std::string key;
Slice filter; Slice filter;
@@ -68,23 +70,21 @@ class PartitionedFilterBlockBuilder : public FullFilterBlockBuilder {
class PartitionedFilterBlockReader : public FilterBlockReader, class PartitionedFilterBlockReader : public FilterBlockReader,
public Cleanable { public Cleanable {
public: public:
explicit PartitionedFilterBlockReader(const SliceTransform* prefix_extractor, explicit PartitionedFilterBlockReader(
bool whole_key_filtering, const SliceTransform* prefix_extractor, bool whole_key_filtering,
BlockContents&& contents, BlockContents&& contents, FilterBitsReader* filter_bits_reader,
FilterBitsReader* filter_bits_reader, Statistics* stats, const InternalKeyComparator comparator,
Statistics* stats, const BlockBasedTable* table, const bool index_key_includes_seq);
const Comparator& comparator,
const BlockBasedTable* table);
virtual ~PartitionedFilterBlockReader(); virtual ~PartitionedFilterBlockReader();
virtual bool IsBlockBased() override { return false; } virtual bool IsBlockBased() override { return false; }
virtual bool KeyMayMatch( virtual bool KeyMayMatch(
const Slice& key, uint64_t block_offset = kNotValid, const Slice& key, const SliceTransform* prefix_extractor,
const bool no_io = false, uint64_t block_offset = kNotValid, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) override; const Slice* const const_ikey_ptr = nullptr) override;
virtual bool PrefixMayMatch( virtual bool PrefixMayMatch(
const Slice& prefix, uint64_t block_offset = kNotValid, const Slice& prefix, const SliceTransform* prefix_extractor,
const bool no_io = false, uint64_t block_offset = kNotValid, const bool no_io = false,
const Slice* const const_ikey_ptr = nullptr) override; const Slice* const const_ikey_ptr = nullptr) override;
virtual size_t ApproximateMemoryUsage() const override; virtual size_t ApproximateMemoryUsage() const override;
@@ -92,13 +92,15 @@ class PartitionedFilterBlockReader : public FilterBlockReader,
Slice GetFilterPartitionHandle(const Slice& entry); Slice GetFilterPartitionHandle(const Slice& entry);
BlockBasedTable::CachableEntry<FilterBlockReader> GetFilterPartition( BlockBasedTable::CachableEntry<FilterBlockReader> GetFilterPartition(
FilePrefetchBuffer* prefetch_buffer, Slice* handle, const bool no_io, FilePrefetchBuffer* prefetch_buffer, Slice* handle, const bool no_io,
bool* cached); bool* cached, const SliceTransform* prefix_extractor = nullptr);
virtual void CacheDependencies(bool pin) override; virtual void CacheDependencies(
bool bin, const SliceTransform* prefix_extractor) override;
const SliceTransform* prefix_extractor_; const SliceTransform* prefix_extractor_;
std::unique_ptr<Block> idx_on_fltr_blk_; std::unique_ptr<Block> idx_on_fltr_blk_;
const Comparator& comparator_; const InternalKeyComparator comparator_;
const BlockBasedTable* table_; const BlockBasedTable* table_;
const bool index_key_includes_seq_;
std::unordered_map<uint64_t, std::unordered_map<uint64_t,
BlockBasedTable::CachableEntry<FilterBlockReader>> BlockBasedTable::CachableEntry<FilterBlockReader>>
filter_map_; filter_map_;
+20 -14
View File
@@ -29,8 +29,8 @@ class MockedBlockBasedTable : public BlockBasedTable {
virtual CachableEntry<FilterBlockReader> GetFilter( virtual CachableEntry<FilterBlockReader> GetFilter(
FilePrefetchBuffer*, const BlockHandle& filter_blk_handle, FilePrefetchBuffer*, const BlockHandle& filter_blk_handle,
const bool /* unused */, bool /* unused */, const bool /* unused */, bool /* unused */, GetContext* /* unused */,
GetContext* /* unused */) const override { const SliceTransform* /* unused */) const override {
Slice slice = slices[filter_blk_handle.offset()]; Slice slice = slices[filter_blk_handle.offset()];
auto obj = new FullFilterBlockReader( auto obj = new FullFilterBlockReader(
nullptr, true, BlockContents(slice, false, kNoCompression), nullptr, true, BlockContents(slice, false, kNoCompression),
@@ -111,7 +111,7 @@ class PartitionedFilterBlockTest : public testing::Test {
std::unique_ptr<MockedBlockBasedTable> table; std::unique_ptr<MockedBlockBasedTable> table;
PartitionedFilterBlockReader* NewReader( PartitionedFilterBlockReader* NewReader(
PartitionedFilterBlockBuilder* builder) { PartitionedFilterBlockBuilder* builder, PartitionedIndexBuilder* pib) {
BlockHandle bh; BlockHandle bh;
Status status; Status status;
Slice slice; Slice slice;
@@ -121,40 +121,46 @@ class PartitionedFilterBlockTest : public testing::Test {
} while (status.IsIncomplete()); } while (status.IsIncomplete());
const Options options; const Options options;
const ImmutableCFOptions ioptions(options); const ImmutableCFOptions ioptions(options);
const MutableCFOptions moptions(options);
const EnvOptions env_options; const EnvOptions env_options;
table.reset(new MockedBlockBasedTable(new BlockBasedTable::Rep( table.reset(new MockedBlockBasedTable(new BlockBasedTable::Rep(
ioptions, env_options, table_options_, icomp, false))); ioptions, env_options, table_options_, icomp, false)));
auto reader = new PartitionedFilterBlockReader( auto reader = new PartitionedFilterBlockReader(
nullptr, true, BlockContents(slice, false, kNoCompression), nullptr, nullptr, true, BlockContents(slice, false, kNoCompression), nullptr,
nullptr, *icomp.user_comparator(), table.get()); nullptr, icomp, table.get(), pib->seperator_is_key_plus_seq());
return reader; return reader;
} }
void VerifyReader(PartitionedFilterBlockBuilder* builder, void VerifyReader(PartitionedFilterBlockBuilder* builder,
bool empty = false) { PartitionedIndexBuilder* pib, bool empty = false) {
std::unique_ptr<PartitionedFilterBlockReader> reader(NewReader(builder)); std::unique_ptr<PartitionedFilterBlockReader> reader(
NewReader(builder, pib));
// Querying added keys // Querying added keys
const bool no_io = true; const bool no_io = true;
for (auto key : keys) { for (auto key : keys) {
auto ikey = InternalKey(key, 0, ValueType::kTypeValue); auto ikey = InternalKey(key, 0, ValueType::kTypeValue);
const Slice ikey_slice = Slice(*ikey.rep()); const Slice ikey_slice = Slice(*ikey.rep());
ASSERT_TRUE(reader->KeyMayMatch(key, kNotValid, !no_io, &ikey_slice)); ASSERT_TRUE(
reader->KeyMayMatch(key, nullptr, kNotValid, !no_io, &ikey_slice));
} }
{ {
// querying a key twice // querying a key twice
auto ikey = InternalKey(keys[0], 0, ValueType::kTypeValue); auto ikey = InternalKey(keys[0], 0, ValueType::kTypeValue);
const Slice ikey_slice = Slice(*ikey.rep()); const Slice ikey_slice = Slice(*ikey.rep());
ASSERT_TRUE(reader->KeyMayMatch(keys[0], kNotValid, !no_io, &ikey_slice)); ASSERT_TRUE(reader->KeyMayMatch(keys[0], nullptr, kNotValid, !no_io,
&ikey_slice));
} }
// querying missing keys // querying missing keys
for (auto key : missing_keys) { for (auto key : missing_keys) {
auto ikey = InternalKey(key, 0, ValueType::kTypeValue); auto ikey = InternalKey(key, 0, ValueType::kTypeValue);
const Slice ikey_slice = Slice(*ikey.rep()); const Slice ikey_slice = Slice(*ikey.rep());
if (empty) { if (empty) {
ASSERT_TRUE(reader->KeyMayMatch(key, kNotValid, !no_io, &ikey_slice)); ASSERT_TRUE(
reader->KeyMayMatch(key, nullptr, kNotValid, !no_io, &ikey_slice));
} else { } else {
// assuming a good hash function // assuming a good hash function
ASSERT_FALSE(reader->KeyMayMatch(key, kNotValid, !no_io, &ikey_slice)); ASSERT_FALSE(
reader->KeyMayMatch(key, nullptr, kNotValid, !no_io, &ikey_slice));
} }
} }
} }
@@ -177,7 +183,7 @@ class PartitionedFilterBlockTest : public testing::Test {
builder->Add(keys[i]); builder->Add(keys[i]);
CutABlock(pib.get(), keys[i]); CutABlock(pib.get(), keys[i]);
VerifyReader(builder.get()); VerifyReader(builder.get(), pib.get());
return CountNumOfIndexPartitions(pib.get()); return CountNumOfIndexPartitions(pib.get());
} }
@@ -197,7 +203,7 @@ class PartitionedFilterBlockTest : public testing::Test {
builder->Add(keys[i]); builder->Add(keys[i]);
CutABlock(pib.get(), keys[i]); CutABlock(pib.get(), keys[i]);
VerifyReader(builder.get()); VerifyReader(builder.get(), pib.get());
} }
void TestBlockPerAllKeys() { void TestBlockPerAllKeys() {
@@ -215,7 +221,7 @@ class PartitionedFilterBlockTest : public testing::Test {
builder->Add(keys[i]); builder->Add(keys[i]);
CutABlock(pib.get(), keys[i]); CutABlock(pib.get(), keys[i]);
VerifyReader(builder.get()); VerifyReader(builder.get(), pib.get());
} }
void CutABlock(PartitionedIndexBuilder* builder, void CutABlock(PartitionedIndexBuilder* builder,
@@ -256,7 +262,7 @@ TEST_F(PartitionedFilterBlockTest, EmptyBuilder) {
std::unique_ptr<PartitionedIndexBuilder> pib(NewIndexBuilder()); std::unique_ptr<PartitionedIndexBuilder> pib(NewIndexBuilder());
std::unique_ptr<PartitionedFilterBlockBuilder> builder(NewBuilder(pib.get())); std::unique_ptr<PartitionedFilterBlockBuilder> builder(NewBuilder(pib.get()));
const bool empty = true; const bool empty = true;
VerifyReader(builder.get(), empty); VerifyReader(builder.get(), pib.get(), empty);
} }
TEST_F(PartitionedFilterBlockTest, OneBlock) { TEST_F(PartitionedFilterBlockTest, OneBlock) {
+11 -10
View File
@@ -57,7 +57,7 @@ extern const uint64_t kPlainTableMagicNumber = 0x8242229663bf9564ull;
extern const uint64_t kLegacyPlainTableMagicNumber = 0x4f3418eb7a8f13b8ull; extern const uint64_t kLegacyPlainTableMagicNumber = 0x4f3418eb7a8f13b8ull;
PlainTableBuilder::PlainTableBuilder( PlainTableBuilder::PlainTableBuilder(
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions, const MutableCFOptions& moptions,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories, int_tbl_prop_collector_factories,
uint32_t column_family_id, WritableFileWriter* file, uint32_t user_key_len, uint32_t column_family_id, WritableFileWriter* file, uint32_t user_key_len,
@@ -66,20 +66,21 @@ PlainTableBuilder::PlainTableBuilder(
uint32_t num_probes, size_t huge_page_tlb_size, double hash_table_ratio, uint32_t num_probes, size_t huge_page_tlb_size, double hash_table_ratio,
bool store_index_in_file) bool store_index_in_file)
: ioptions_(ioptions), : ioptions_(ioptions),
moptions_(moptions),
bloom_block_(num_probes), bloom_block_(num_probes),
file_(file), file_(file),
bloom_bits_per_key_(bloom_bits_per_key), bloom_bits_per_key_(bloom_bits_per_key),
huge_page_tlb_size_(huge_page_tlb_size), huge_page_tlb_size_(huge_page_tlb_size),
encoder_(encoding_type, user_key_len, ioptions.prefix_extractor, encoder_(encoding_type, user_key_len, moptions.prefix_extractor.get(),
index_sparseness), index_sparseness),
store_index_in_file_(store_index_in_file), store_index_in_file_(store_index_in_file),
prefix_extractor_(ioptions.prefix_extractor) { prefix_extractor_(moptions.prefix_extractor.get()) {
// Build index block and save it in the file if hash_table_ratio > 0 // Build index block and save it in the file if hash_table_ratio > 0
if (store_index_in_file_) { if (store_index_in_file_) {
assert(hash_table_ratio > 0 || IsTotalOrderMode()); assert(hash_table_ratio > 0 || IsTotalOrderMode());
index_builder_.reset( index_builder_.reset(new PlainTableIndexBuilder(
new PlainTableIndexBuilder(&arena_, ioptions, index_sparseness, &arena_, ioptions, moptions.prefix_extractor.get(), index_sparseness,
hash_table_ratio, huge_page_tlb_size_)); hash_table_ratio, huge_page_tlb_size_));
properties_.user_collected_properties properties_.user_collected_properties
[PlainTablePropertyNames::kBloomVersion] = "1"; // For future use [PlainTablePropertyNames::kBloomVersion] = "1"; // For future use
} }
@@ -96,8 +97,8 @@ PlainTableBuilder::PlainTableBuilder(
properties_.format_version = (encoding_type == kPlain) ? 0 : 1; properties_.format_version = (encoding_type == kPlain) ? 0 : 1;
properties_.column_family_id = column_family_id; properties_.column_family_id = column_family_id;
properties_.column_family_name = column_family_name; properties_.column_family_name = column_family_name;
properties_.prefix_extractor_name = ioptions_.prefix_extractor != nullptr properties_.prefix_extractor_name = moptions_.prefix_extractor != nullptr
? ioptions_.prefix_extractor->Name() ? moptions_.prefix_extractor->Name()
: "nullptr"; : "nullptr";
std::string val; std::string val;
@@ -131,11 +132,11 @@ void PlainTableBuilder::Add(const Slice& key, const Slice& value) {
// Store key hash // Store key hash
if (store_index_in_file_) { if (store_index_in_file_) {
if (ioptions_.prefix_extractor == nullptr) { if (moptions_.prefix_extractor == nullptr) {
keys_or_prefixes_hashes_.push_back(GetSliceHash(internal_key.user_key)); keys_or_prefixes_hashes_.push_back(GetSliceHash(internal_key.user_key));
} else { } else {
Slice prefix = Slice prefix =
ioptions_.prefix_extractor->Transform(internal_key.user_key); moptions_.prefix_extractor->Transform(internal_key.user_key);
keys_or_prefixes_hashes_.push_back(GetSliceHash(prefix)); keys_or_prefixes_hashes_.push_back(GetSliceHash(prefix));
} }
} }
+2 -1
View File
@@ -32,7 +32,7 @@ class PlainTableBuilder: public TableBuilder {
// will be part of level specified by 'level'. A value of -1 means // will be part of level specified by 'level'. A value of -1 means
// that the caller does not know which level the output file will reside. // that the caller does not know which level the output file will reside.
PlainTableBuilder( PlainTableBuilder(
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions, const MutableCFOptions& moptions,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories, int_tbl_prop_collector_factories,
uint32_t column_family_id, WritableFileWriter* file, uint32_t column_family_id, WritableFileWriter* file,
@@ -79,6 +79,7 @@ class PlainTableBuilder: public TableBuilder {
private: private:
Arena arena_; Arena arena_;
const ImmutableCFOptions& ioptions_; const ImmutableCFOptions& ioptions_;
const MutableCFOptions& moptions_;
std::vector<std::unique_ptr<IntTblPropCollector>> std::vector<std::unique_ptr<IntTblPropCollector>>
table_properties_collectors_; table_properties_collectors_;
+2 -2
View File
@@ -27,7 +27,7 @@ Status PlainTableFactory::NewTableReader(
table_reader_options.internal_comparator, std::move(file), file_size, table_reader_options.internal_comparator, std::move(file), file_size,
table, table_options_.bloom_bits_per_key, table_options_.hash_table_ratio, table, table_options_.bloom_bits_per_key, table_options_.hash_table_ratio,
table_options_.index_sparseness, table_options_.huge_page_tlb_size, table_options_.index_sparseness, table_options_.huge_page_tlb_size,
table_options_.full_scan_mode); table_options_.full_scan_mode, table_reader_options.prefix_extractor);
} }
TableBuilder* PlainTableFactory::NewTableBuilder( TableBuilder* PlainTableFactory::NewTableBuilder(
@@ -38,7 +38,7 @@ TableBuilder* PlainTableFactory::NewTableBuilder(
// tables // tables
// //
return new PlainTableBuilder( return new PlainTableBuilder(
table_builder_options.ioptions, table_builder_options.ioptions, table_builder_options.moptions,
table_builder_options.int_tbl_prop_collector_factories, column_family_id, table_builder_options.int_tbl_prop_collector_factories, column_family_id,
file, table_options_.user_key_len, table_options_.encoding_type, file, table_options_.user_key_len, table_options_.encoding_type,
table_options_.index_sparseness, table_options_.bloom_bits_per_key, table_options_.index_sparseness, table_options_.bloom_bits_per_key,
+2 -1
View File
@@ -112,6 +112,7 @@ class PlainTableIndex {
class PlainTableIndexBuilder { class PlainTableIndexBuilder {
public: public:
PlainTableIndexBuilder(Arena* arena, const ImmutableCFOptions& ioptions, PlainTableIndexBuilder(Arena* arena, const ImmutableCFOptions& ioptions,
const SliceTransform* prefix_extractor,
size_t index_sparseness, double hash_table_ratio, size_t index_sparseness, double hash_table_ratio,
size_t huge_page_tlb_size) size_t huge_page_tlb_size)
: arena_(arena), : arena_(arena),
@@ -125,7 +126,7 @@ class PlainTableIndexBuilder {
index_sparseness_(index_sparseness), index_sparseness_(index_sparseness),
index_size_(0), index_size_(0),
sub_index_size_(0), sub_index_size_(0),
prefix_extractor_(ioptions.prefix_extractor), prefix_extractor_(prefix_extractor),
hash_table_ratio_(hash_table_ratio), hash_table_ratio_(hash_table_ratio),
huge_page_tlb_size_(huge_page_tlb_size) {} huge_page_tlb_size_(huge_page_tlb_size) {}
+27 -26
View File
@@ -97,12 +97,13 @@ PlainTableReader::PlainTableReader(const ImmutableCFOptions& ioptions,
const InternalKeyComparator& icomparator, const InternalKeyComparator& icomparator,
EncodingType encoding_type, EncodingType encoding_type,
uint64_t file_size, uint64_t file_size,
const TableProperties* table_properties) const TableProperties* table_properties,
const SliceTransform* prefix_extractor)
: internal_comparator_(icomparator), : internal_comparator_(icomparator),
encoding_type_(encoding_type), encoding_type_(encoding_type),
full_scan_mode_(false), full_scan_mode_(false),
user_key_len_(static_cast<uint32_t>(table_properties->fixed_key_len)), user_key_len_(static_cast<uint32_t>(table_properties->fixed_key_len)),
prefix_extractor_(ioptions.prefix_extractor), prefix_extractor_(prefix_extractor),
enable_bloom_(false), enable_bloom_(false),
bloom_(6, nullptr), bloom_(6, nullptr),
file_info_(std::move(file), storage_options, file_info_(std::move(file), storage_options,
@@ -114,15 +115,13 @@ PlainTableReader::PlainTableReader(const ImmutableCFOptions& ioptions,
PlainTableReader::~PlainTableReader() { PlainTableReader::~PlainTableReader() {
} }
Status PlainTableReader::Open(const ImmutableCFOptions& ioptions, Status PlainTableReader::Open(
const EnvOptions& env_options, const ImmutableCFOptions& ioptions, const EnvOptions& env_options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
unique_ptr<RandomAccessFileReader>&& file, unique_ptr<RandomAccessFileReader>&& file, uint64_t file_size,
uint64_t file_size, unique_ptr<TableReader>* table_reader, const int bloom_bits_per_key,
unique_ptr<TableReader>* table_reader, double hash_table_ratio, size_t index_sparseness, size_t huge_page_tlb_size,
const int bloom_bits_per_key, bool full_scan_mode, const SliceTransform* prefix_extractor) {
double hash_table_ratio, size_t index_sparseness,
size_t huge_page_tlb_size, bool full_scan_mode) {
if (file_size > PlainTableIndex::kMaxFileSize) { if (file_size > PlainTableIndex::kMaxFileSize) {
return Status::NotSupported("File is too large for PlainTableReader!"); return Status::NotSupported("File is too large for PlainTableReader!");
} }
@@ -141,12 +140,12 @@ Status PlainTableReader::Open(const ImmutableCFOptions& ioptions,
if (!full_scan_mode && if (!full_scan_mode &&
!prefix_extractor_in_file.empty() /* old version sst file*/ !prefix_extractor_in_file.empty() /* old version sst file*/
&& prefix_extractor_in_file != "nullptr") { && prefix_extractor_in_file != "nullptr") {
if (!ioptions.prefix_extractor) { if (!prefix_extractor) {
return Status::InvalidArgument( return Status::InvalidArgument(
"Prefix extractor is missing when opening a PlainTable built " "Prefix extractor is missing when opening a PlainTable built "
"using a prefix extractor"); "using a prefix extractor");
} else if (prefix_extractor_in_file.compare( } else if (prefix_extractor_in_file.compare(prefix_extractor->Name()) !=
ioptions.prefix_extractor->Name()) != 0) { 0) {
return Status::InvalidArgument( return Status::InvalidArgument(
"Prefix extractor given doesn't match the one used to build " "Prefix extractor given doesn't match the one used to build "
"PlainTable"); "PlainTable");
@@ -163,7 +162,7 @@ Status PlainTableReader::Open(const ImmutableCFOptions& ioptions,
std::unique_ptr<PlainTableReader> new_reader(new PlainTableReader( std::unique_ptr<PlainTableReader> new_reader(new PlainTableReader(
ioptions, std::move(file), env_options, internal_comparator, ioptions, std::move(file), env_options, internal_comparator,
encoding_type, file_size, props)); encoding_type, file_size, props, prefix_extractor));
s = new_reader->MmapDataIfNeeded(); s = new_reader->MmapDataIfNeeded();
if (!s.ok()) { if (!s.ok()) {
@@ -189,9 +188,9 @@ Status PlainTableReader::Open(const ImmutableCFOptions& ioptions,
void PlainTableReader::SetupForCompaction() { void PlainTableReader::SetupForCompaction() {
} }
InternalIterator* PlainTableReader::NewIterator(const ReadOptions& options, InternalIterator* PlainTableReader::NewIterator(
Arena* arena, const ReadOptions& options, const SliceTransform* /* prefix_extractor */,
bool /*skip_filters*/) { Arena* arena, bool /*skip_filters*/) {
bool use_prefix_seek = !IsTotalOrderMode() && !options.total_order_seek; bool use_prefix_seek = !IsTotalOrderMode() && !options.total_order_seek;
if (arena == nullptr) { if (arena == nullptr) {
return new PlainTableIterator(this, use_prefix_seek); return new PlainTableIterator(this, use_prefix_seek);
@@ -210,7 +209,7 @@ Status PlainTableReader::PopulateIndexRecordList(
bool is_first_record = true; bool is_first_record = true;
Slice key_prefix_slice; Slice key_prefix_slice;
PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_, PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_,
ioptions_.prefix_extractor); prefix_extractor_);
while (pos < file_info_.data_end_offset) { while (pos < file_info_.data_end_offset) {
uint32_t key_offset = pos; uint32_t key_offset = pos;
ParsedInternalKey key; ParsedInternalKey key;
@@ -330,9 +329,8 @@ Status PlainTableReader::PopulateIndex(TableProperties* props,
index_block = nullptr; index_block = nullptr;
} }
if ((ioptions_.prefix_extractor == nullptr) && if ((prefix_extractor_ == nullptr) && (hash_table_ratio != 0)) {
(hash_table_ratio != 0)) { // moptions.prefix_extractor is requried for a hash-based look-up.
// ioptions.prefix_extractor is requried for a hash-based look-up.
return Status::NotSupported( return Status::NotSupported(
"PlainTable requires a prefix extractor enable prefix hash mode."); "PlainTable requires a prefix extractor enable prefix hash mode.");
} }
@@ -377,8 +375,9 @@ Status PlainTableReader::PopulateIndex(TableProperties* props,
bloom_bits_per_key = 0; bloom_bits_per_key = 0;
} }
PlainTableIndexBuilder index_builder(&arena_, ioptions_, index_sparseness, PlainTableIndexBuilder index_builder(&arena_, ioptions_, prefix_extractor_,
hash_table_ratio, huge_page_tlb_size); index_sparseness, hash_table_ratio,
huge_page_tlb_size);
std::vector<uint32_t> prefix_hashes; std::vector<uint32_t> prefix_hashes;
if (!index_in_file) { if (!index_in_file) {
@@ -538,7 +537,9 @@ void PlainTableReader::Prepare(const Slice& target) {
} }
Status PlainTableReader::Get(const ReadOptions& /*ro*/, const Slice& target, Status PlainTableReader::Get(const ReadOptions& /*ro*/, const Slice& target,
GetContext* get_context, bool /*skip_filters*/) { GetContext* get_context,
const SliceTransform* /* prefix_extractor */,
bool /*skip_filters*/) {
// Check bloom filter first. // Check bloom filter first.
Slice prefix_slice; Slice prefix_slice;
uint32_t prefix_hash; uint32_t prefix_hash;
@@ -565,7 +566,7 @@ Status PlainTableReader::Get(const ReadOptions& /*ro*/, const Slice& target,
uint32_t offset; uint32_t offset;
bool prefix_match; bool prefix_match;
PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_, PlainTableKeyDecoder decoder(&file_info_, encoding_type_, user_key_len_,
ioptions_.prefix_extractor); prefix_extractor_);
Status s = GetOffset(&decoder, target, prefix_slice, prefix_hash, Status s = GetOffset(&decoder, target, prefix_slice, prefix_hash,
prefix_match, &offset); prefix_match, &offset);
+7 -3
View File
@@ -76,15 +76,18 @@ class PlainTableReader: public TableReader {
uint64_t file_size, unique_ptr<TableReader>* table, uint64_t file_size, unique_ptr<TableReader>* table,
const int bloom_bits_per_key, double hash_table_ratio, const int bloom_bits_per_key, double hash_table_ratio,
size_t index_sparseness, size_t huge_page_tlb_size, size_t index_sparseness, size_t huge_page_tlb_size,
bool full_scan_mode); bool full_scan_mode,
const SliceTransform* prefix_extractor = nullptr);
InternalIterator* NewIterator(const ReadOptions&, InternalIterator* NewIterator(const ReadOptions&,
const SliceTransform* prefix_extractor,
Arena* arena = nullptr, Arena* arena = nullptr,
bool skip_filters = false) override; bool skip_filters = false) override;
void Prepare(const Slice& target) override; void Prepare(const Slice& target) override;
Status Get(const ReadOptions&, const Slice& key, GetContext* get_context, Status Get(const ReadOptions& readOptions, const Slice& key,
GetContext* get_context, const SliceTransform* prefix_extractor,
bool skip_filters = false) override; bool skip_filters = false) override;
uint64_t ApproximateOffsetOf(const Slice& key) override; uint64_t ApproximateOffsetOf(const Slice& key) override;
@@ -105,7 +108,8 @@ class PlainTableReader: public TableReader {
const EnvOptions& env_options, const EnvOptions& env_options,
const InternalKeyComparator& internal_comparator, const InternalKeyComparator& internal_comparator,
EncodingType encoding_type, uint64_t file_size, EncodingType encoding_type, uint64_t file_size,
const TableProperties* table_properties); const TableProperties* table_properties,
const SliceTransform* prefix_extractor);
virtual ~PlainTableReader(); virtual ~PlainTableReader();
protected: protected:
+4 -4
View File
@@ -189,10 +189,10 @@ Status SstFileWriter::Open(const std::string& file_path) {
} }
TableBuilderOptions table_builder_options( TableBuilderOptions table_builder_options(
r->ioptions, r->internal_comparator, &int_tbl_prop_collector_factories, r->ioptions, r->mutable_cf_options, r->internal_comparator,
compression_type, r->ioptions.compression_opts, &int_tbl_prop_collector_factories, compression_type,
nullptr /* compression_dict */, r->skip_filters, r->column_family_name, r->ioptions.compression_opts, nullptr /* compression_dict */,
unknown_level); r->skip_filters, r->column_family_name, unknown_level);
r->file_writer.reset( r->file_writer.reset(
new WritableFileWriter(std::move(sst_file), r->env_options)); new WritableFileWriter(std::move(sst_file), r->env_options));
+6 -1
View File
@@ -27,16 +27,19 @@ class Status;
struct TableReaderOptions { struct TableReaderOptions {
// @param skip_filters Disables loading/accessing the filter block // @param skip_filters Disables loading/accessing the filter block
TableReaderOptions(const ImmutableCFOptions& _ioptions, TableReaderOptions(const ImmutableCFOptions& _ioptions,
const SliceTransform* _prefix_extractor,
const EnvOptions& _env_options, const EnvOptions& _env_options,
const InternalKeyComparator& _internal_comparator, const InternalKeyComparator& _internal_comparator,
bool _skip_filters = false, int _level = -1) bool _skip_filters = false, int _level = -1)
: ioptions(_ioptions), : ioptions(_ioptions),
prefix_extractor(_prefix_extractor),
env_options(_env_options), env_options(_env_options),
internal_comparator(_internal_comparator), internal_comparator(_internal_comparator),
skip_filters(_skip_filters), skip_filters(_skip_filters),
level(_level) {} level(_level) {}
const ImmutableCFOptions& ioptions; const ImmutableCFOptions& ioptions;
const SliceTransform* prefix_extractor;
const EnvOptions& env_options; const EnvOptions& env_options;
const InternalKeyComparator& internal_comparator; const InternalKeyComparator& internal_comparator;
// This is only used for BlockBasedTable (reader) // This is only used for BlockBasedTable (reader)
@@ -47,7 +50,7 @@ struct TableReaderOptions {
struct TableBuilderOptions { struct TableBuilderOptions {
TableBuilderOptions( TableBuilderOptions(
const ImmutableCFOptions& _ioptions, const ImmutableCFOptions& _ioptions, const MutableCFOptions& _moptions,
const InternalKeyComparator& _internal_comparator, const InternalKeyComparator& _internal_comparator,
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
_int_tbl_prop_collector_factories, _int_tbl_prop_collector_factories,
@@ -57,6 +60,7 @@ struct TableBuilderOptions {
const std::string& _column_family_name, int _level, const std::string& _column_family_name, int _level,
const uint64_t _creation_time = 0, const int64_t _oldest_key_time = 0) const uint64_t _creation_time = 0, const int64_t _oldest_key_time = 0)
: ioptions(_ioptions), : ioptions(_ioptions),
moptions(_moptions),
internal_comparator(_internal_comparator), internal_comparator(_internal_comparator),
int_tbl_prop_collector_factories(_int_tbl_prop_collector_factories), int_tbl_prop_collector_factories(_int_tbl_prop_collector_factories),
compression_type(_compression_type), compression_type(_compression_type),
@@ -68,6 +72,7 @@ struct TableBuilderOptions {
creation_time(_creation_time), creation_time(_creation_time),
oldest_key_time(_oldest_key_time) {} oldest_key_time(_oldest_key_time) {}
const ImmutableCFOptions& ioptions; const ImmutableCFOptions& ioptions;
const MutableCFOptions& moptions;
const InternalKeyComparator& internal_comparator; const InternalKeyComparator& internal_comparator;
const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>* const std::vector<std::unique_ptr<IntTblPropCollectorFactory>>*
int_tbl_prop_collector_factories; int_tbl_prop_collector_factories;
+14 -1
View File
@@ -90,7 +90,12 @@ std::string TableProperties::ToString(
prop_delim, kv_delim); prop_delim, kv_delim);
AppendProperty(result, "data block size", data_size, prop_delim, kv_delim); AppendProperty(result, "data block size", data_size, prop_delim, kv_delim);
AppendProperty(result, "index block size", index_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);
if (index_partitions != 0) { if (index_partitions != 0) {
AppendProperty(result, "# index partitions", index_partitions, prop_delim, AppendProperty(result, "# index partitions", index_partitions, prop_delim,
kv_delim); kv_delim);
@@ -107,6 +112,11 @@ std::string TableProperties::ToString(
filter_policy_name.empty() ? std::string("N/A") : filter_policy_name, filter_policy_name.empty() ? std::string("N/A") : filter_policy_name,
prop_delim, kv_delim); prop_delim, kv_delim);
AppendProperty(result, "prefix extractor name",
prefix_extractor_name.empty() ? std::string("N/A")
: prefix_extractor_name,
prop_delim, kv_delim);
AppendProperty(result, "column family ID", AppendProperty(result, "column family ID",
column_family_id == rocksdb::TablePropertiesCollectorFactory:: column_family_id == rocksdb::TablePropertiesCollectorFactory::
Context::kUnknownColumnFamily Context::kUnknownColumnFamily
@@ -150,6 +160,7 @@ void TableProperties::Add(const TableProperties& tp) {
index_size += tp.index_size; index_size += tp.index_size;
index_partitions += tp.index_partitions; index_partitions += tp.index_partitions;
top_level_index_size += tp.top_level_index_size; 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; filter_size += tp.filter_size;
raw_key_size += tp.raw_key_size; raw_key_size += tp.raw_key_size;
raw_value_size += tp.raw_value_size; raw_value_size += tp.raw_value_size;
@@ -165,6 +176,8 @@ const std::string TablePropertiesNames::kIndexPartitions =
"rocksdb.index.partitions"; "rocksdb.index.partitions";
const std::string TablePropertiesNames::kTopLevelIndexSize = const std::string TablePropertiesNames::kTopLevelIndexSize =
"rocksdb.top-level.index.size"; "rocksdb.top-level.index.size";
const std::string TablePropertiesNames::kIndexKeyIsUserKey =
"rocksdb.index.key.is.user.key";
const std::string TablePropertiesNames::kFilterSize = const std::string TablePropertiesNames::kFilterSize =
"rocksdb.filter.size"; "rocksdb.filter.size";
const std::string TablePropertiesNames::kRawKeySize = const std::string TablePropertiesNames::kRawKeySize =
+7 -2
View File
@@ -9,6 +9,7 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include "rocksdb/slice_transform.h"
#include "table/internal_iterator.h" #include "table/internal_iterator.h"
namespace rocksdb { namespace rocksdb {
@@ -39,6 +40,7 @@ class TableReader {
// skip_filters: disables checking the bloom filters even if they exist. This // skip_filters: disables checking the bloom filters even if they exist. This
// option is effective only for block-based table format. // option is effective only for block-based table format.
virtual InternalIterator* NewIterator(const ReadOptions&, virtual InternalIterator* NewIterator(const ReadOptions&,
const SliceTransform* prefix_extractor,
Arena* arena = nullptr, Arena* arena = nullptr,
bool skip_filters = false) = 0; bool skip_filters = false) = 0;
@@ -79,7 +81,9 @@ class TableReader {
// skip_filters: disables checking the bloom filters even if they exist. This // skip_filters: disables checking the bloom filters even if they exist. This
// option is effective only for block-based table format. // option is effective only for block-based table format.
virtual Status Get(const ReadOptions& readOptions, const Slice& key, virtual Status Get(const ReadOptions& readOptions, const Slice& key,
GetContext* get_context, bool skip_filters = false) = 0; GetContext* get_context,
const SliceTransform* prefix_extractor,
bool skip_filters = false) = 0;
// Prefetch data corresponding to a give range of keys // Prefetch data corresponding to a give range of keys
// Typically this functionality is required for table implementations that // Typically this functionality is required for table implementations that
@@ -94,7 +98,8 @@ class TableReader {
} }
// convert db file to a human readable form // convert db file to a human readable form
virtual Status DumpTable(WritableFile* /*out_file*/) { virtual Status DumpTable(WritableFile* /*out_file*/,
const SliceTransform* /*prefix_extractor*/) {
return Status::NotSupported("DumpTable() not supported"); return Status::NotSupported("DumpTable() not supported");
} }
+12 -10
View File
@@ -84,6 +84,8 @@ void TableReaderBenchmark(Options& opts, EnvOptions& env_options,
DB* db = nullptr; DB* db = nullptr;
Status s; Status s;
const ImmutableCFOptions ioptions(opts); const ImmutableCFOptions ioptions(opts);
const ColumnFamilyOptions cfo(opts);
const MutableCFOptions moptions(cfo);
unique_ptr<WritableFileWriter> file_writer; unique_ptr<WritableFileWriter> file_writer;
if (!through_db) { if (!through_db) {
unique_ptr<WritableFile> file; unique_ptr<WritableFile> file;
@@ -95,12 +97,11 @@ void TableReaderBenchmark(Options& opts, EnvOptions& env_options,
file_writer.reset(new WritableFileWriter(std::move(file), env_options)); file_writer.reset(new WritableFileWriter(std::move(file), env_options));
int unknown_level = -1; int unknown_level = -1;
tb = opts.table_factory->NewTableBuilder( tb = opts.table_factory->NewTableBuilder(
TableBuilderOptions(ioptions, ikc, &int_tbl_prop_collector_factories, TableBuilderOptions(
CompressionType::kNoCompression, ioptions, moptions, ikc, &int_tbl_prop_collector_factories,
CompressionOptions(), CompressionType::kNoCompression, CompressionOptions(),
nullptr /* compression_dict */, nullptr /* compression_dict */, false /* skip_filters */,
false /* skip_filters */, kDefaultColumnFamilyName, kDefaultColumnFamilyName, unknown_level),
unknown_level),
0 /* column_family_id */, file_writer.get()); 0 /* column_family_id */, file_writer.get());
} else { } else {
s = DB::Open(opts, dbname, &db); s = DB::Open(opts, dbname, &db);
@@ -138,8 +139,9 @@ void TableReaderBenchmark(Options& opts, EnvOptions& env_options,
unique_ptr<RandomAccessFileReader> file_reader( unique_ptr<RandomAccessFileReader> file_reader(
new RandomAccessFileReader(std::move(raf), file_name)); new RandomAccessFileReader(std::move(raf), file_name));
s = opts.table_factory->NewTableReader( s = opts.table_factory->NewTableReader(
TableReaderOptions(ioptions, env_options, ikc), std::move(file_reader), TableReaderOptions(ioptions, moptions.prefix_extractor.get(),
file_size, &table_reader); env_options, ikc),
std::move(file_reader), file_size, &table_reader);
if (!s.ok()) { if (!s.ok()) {
fprintf(stderr, "Open Table Error: %s\n", s.ToString().c_str()); fprintf(stderr, "Open Table Error: %s\n", s.ToString().c_str());
exit(1); exit(1);
@@ -173,7 +175,7 @@ void TableReaderBenchmark(Options& opts, EnvOptions& env_options,
ioptions.statistics, GetContext::kNotFound, ioptions.statistics, GetContext::kNotFound,
Slice(key), &value, nullptr, &merge_context, Slice(key), &value, nullptr, &merge_context,
&range_del_agg, env); &range_del_agg, env);
s = table_reader->Get(read_options, key, &get_context); s = table_reader->Get(read_options, key, &get_context, nullptr);
} else { } else {
s = db->Get(read_options, key, &result); s = db->Get(read_options, key, &result);
} }
@@ -195,7 +197,7 @@ void TableReaderBenchmark(Options& opts, EnvOptions& env_options,
Iterator* iter = nullptr; Iterator* iter = nullptr;
InternalIterator* iiter = nullptr; InternalIterator* iiter = nullptr;
if (!through_db) { if (!through_db) {
iiter = table_reader->NewIterator(read_options); iiter = table_reader->NewIterator(read_options, nullptr);
} else { } else {
iter = db->NewIterator(read_options); iter = db->NewIterator(read_options);
} }
+284 -189
View File
File diff suppressed because it is too large Load Diff
+13 -1
View File
@@ -430,10 +430,19 @@ DEFINE_int32(ops_between_duration_checks, 1000,
DEFINE_bool(pin_l0_filter_and_index_blocks_in_cache, false, DEFINE_bool(pin_l0_filter_and_index_blocks_in_cache, false,
"Pin index/filter blocks of L0 files in block cache."); "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, DEFINE_int32(block_size,
static_cast<int32_t>(rocksdb::BlockBasedTableOptions().block_size), static_cast<int32_t>(rocksdb::BlockBasedTableOptions().block_size),
"Number of bytes in a block."); "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, DEFINE_int32(block_restart_interval,
rocksdb::BlockBasedTableOptions().block_restart_interval, rocksdb::BlockBasedTableOptions().block_restart_interval,
"Number of keys between restart points " "Number of keys between restart points "
@@ -3132,6 +3141,8 @@ void VerifyDBFromDB(std::string& truth_db_name) {
FLAGS_cache_index_and_filter_blocks; FLAGS_cache_index_and_filter_blocks;
block_based_options.pin_l0_filter_and_index_blocks_in_cache = block_based_options.pin_l0_filter_and_index_blocks_in_cache =
FLAGS_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 if (FLAGS_cache_high_pri_pool_ratio > 1e-6) { // > 0.0 + eps
block_based_options.cache_index_and_filter_blocks_with_high_priority = block_based_options.cache_index_and_filter_blocks_with_high_priority =
true; true;
@@ -3143,7 +3154,8 @@ void VerifyDBFromDB(std::string& truth_db_name) {
block_based_options.index_block_restart_interval = block_based_options.index_block_restart_interval =
FLAGS_index_block_restart_interval; FLAGS_index_block_restart_interval;
block_based_options.filter_policy = filter_policy_; block_based_options.filter_policy = filter_policy_;
block_based_options.format_version = 2; block_based_options.format_version =
static_cast<uint32_t>(FLAGS_format_version);
block_based_options.read_amp_bytes_per_bit = FLAGS_read_amp_bytes_per_bit; block_based_options.read_amp_bytes_per_bit = FLAGS_read_amp_bytes_per_bit;
block_based_options.enable_index_compression = block_based_options.enable_index_compression =
FLAGS_enable_index_compression; FLAGS_enable_index_compression;
+1
View File
@@ -48,6 +48,7 @@ default_params = {
"verify_checksum": 1, "verify_checksum": 1,
"write_buffer_size": 4 * 1024 * 1024, "write_buffer_size": 4 * 1024 * 1024,
"writepercent": 35, "writepercent": 35,
"format_version": lambda: random.randint(2, 3),
} }
+9 -3
View File
@@ -219,10 +219,14 @@ DEFINE_int32(level0_stop_writes_trigger,
rocksdb::Options().level0_stop_writes_trigger, rocksdb::Options().level0_stop_writes_trigger,
"Number of files in level-0 that will trigger put stop."); "Number of files in level-0 that will trigger put stop.");
DEFINE_int32(block_size, DEFINE_int32(block_size, rocksdb::BlockBasedTableOptions().block_size,
static_cast<int32_t>(rocksdb::BlockBasedTableOptions().block_size),
"Number of bytes in a block."); "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, DEFINE_int32(max_background_compactions,
rocksdb::Options().max_background_compactions, rocksdb::Options().max_background_compactions,
"The maximum number of concurrent background compactions " "The maximum number of concurrent background compactions "
@@ -2477,6 +2481,7 @@ class StressTest {
void PrintEnv() const { void PrintEnv() const {
fprintf(stdout, "RocksDB version : %d.%d\n", kMajorVersion, fprintf(stdout, "RocksDB version : %d.%d\n", kMajorVersion,
kMinorVersion); kMinorVersion);
fprintf(stdout, "Format version : %d\n", FLAGS_format_version);
fprintf(stdout, "TransactionDB : %s\n", fprintf(stdout, "TransactionDB : %s\n",
FLAGS_use_txn ? "true" : "false"); FLAGS_use_txn ? "true" : "false");
fprintf(stdout, "Column families : %d\n", FLAGS_column_families); fprintf(stdout, "Column families : %d\n", FLAGS_column_families);
@@ -2560,7 +2565,8 @@ class StressTest {
block_based_options.block_cache_compressed = compressed_cache_; block_based_options.block_cache_compressed = compressed_cache_;
block_based_options.checksum = FLAGS_checksum_type_e; block_based_options.checksum = FLAGS_checksum_type_e;
block_based_options.block_size = FLAGS_block_size; block_based_options.block_size = FLAGS_block_size;
block_based_options.format_version = 2; block_based_options.format_version =
static_cast<uint32_t>(FLAGS_format_version);
block_based_options.filter_policy = filter_policy_; block_based_options.filter_policy = filter_policy_;
options_.table_factory.reset( options_.table_factory.reset(
NewBlockBasedTableFactory(block_based_options)); NewBlockBasedTableFactory(block_based_options));

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