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