Compare commits

...

7 Commits

Author SHA1 Message Date
Andrew Kryczka e876b1b42f Revert "Remove some deprecated/obsolete statistics from the API (#11123)"
This reverts commit 99e559533d.
2023-02-17 16:18:55 -08:00
Andrew Kryczka ca38d391cb Revert "Remove more obsolete statistics (#11131)"
This reverts commit 6da2e20df3.
2023-02-17 16:18:55 -08:00
Andrew Kryczka fb261e5157 Revert "Fix the HISTORY.md entry related to the removed statistics (#11140)"
This reverts commit a6cfdd4eda.
2023-02-17 16:18:55 -08:00
Andrew Kryczka fecd0eeb06 Revert "Remove Stats related to compressed block cache (#11135)"
This reverts commit e808858ae0.
2023-02-17 16:18:55 -08:00
Andrew Kryczka 0771260c5d Revert "Remove compressed block cache (#11117)"
This reverts commit 2800aa069a.
2023-02-17 16:18:55 -08:00
Andrew Kryczka 1518dff897 Revert "Put Cache and CacheWrapper in new public header (#11192)"
This reverts commit 3cacd4b4ec.
2023-02-17 16:18:54 -08:00
Andrew Kryczka 530612ba0a Revert "Remove deprecated util functions in options_util.h (#11126)"
This reverts commit 6943ff6e50.
2023-02-17 16:17:46 -08:00
64 changed files with 2230 additions and 758 deletions
+1 -4
View File
@@ -17,15 +17,12 @@
### Feature Removal
* Remove RocksDB Lite.
* The feature block_cache_compressed is removed. Statistics related to it are removed too.
* Remove deprecated Env::LoadEnv(). Use Env::CreateFromString() instead.
* Remove deprecated FileSystem::Load(). Use FileSystem::CreateFromString() instead.
* Removed the deprecated version of these utility functions and the corresponding Java bindings: `LoadOptionsFromFile`, `LoadLatestOptions`, `CheckOptionsCompatibility`.
* Remove the FactoryFunc from the LoadObject method from the Customizable helper methods.
### Public API Changes
* Moved rarely-needed Cache class definition to new advanced_cache.h, and added a CacheWrapper class to advanced_cache.h. Minor changes to SimCache API definitions.
* Completely removed the following deprecated/obsolete statistics: the tickers `BLOCK_CACHE_INDEX_BYTES_EVICT`, `BLOCK_CACHE_FILTER_BYTES_EVICT`, `BLOOM_FILTER_MICROS`, `NO_FILE_CLOSES`, `STALL_L0_SLOWDOWN_MICROS`, `STALL_MEMTABLE_COMPACTION_MICROS`, `STALL_L0_NUM_FILES_MICROS`, `RATE_LIMIT_DELAY_MILLIS`, `NO_ITERATORS`, `NUMBER_FILTERED_DELETES`, `WRITE_TIMEDOUT`, `BLOB_DB_GC_NUM_KEYS_OVERWRITTEN`, `BLOB_DB_GC_NUM_KEYS_EXPIRED`, `BLOB_DB_GC_BYTES_OVERWRITTEN`, `BLOB_DB_GC_BYTES_EXPIRED`, `BLOCK_CACHE_COMPRESSION_DICT_BYTES_EVICT` as well as the histograms `STALL_L0_SLOWDOWN_COUNT`, `STALL_MEMTABLE_COMPACTION_COUNT`, `STALL_L0_NUM_FILES_COUNT`, `HARD_RATE_LIMIT_DELAY_COUNT`, `SOFT_RATE_LIMIT_DELAY_COUNT`, `BLOB_DB_GC_MICROS`, and `NUM_DATA_BLOCKS_READ_PER_LEVEL`. Note that as a result, the C++ enum values of the still supported statistics have changed. Developers are advised to not rely on the actual numeric values.
* Completely removed the following deprecated/obsolete statistics: `STALL_L0_SLOWDOWN_MICROS`, `STALL_MEMTABLE_COMPACTION_MICROS`, `STALL_L0_NUM_FILES_MICROS`, `NO_ITERATORS`, `BLOB_DB_GC_NUM_KEYS_OVERWRITTEN`, `BLOB_DB_GC_NUM_KEYS_EXPIRED`, `BLOB_DB_GC_BYTES_OVERWRITTEN`, `BLOB_DB_GC_BYTES_EXPIRED`, `BLOB_DB_GC_MICROS`, and `NUM_DATA_BLOCKS_READ_PER_LEVEL`.
* Deprecated IngestExternalFileOptions::write_global_seqno and change default to false. This option only needs to be set to true to generate a DB compatible with RocksDB versions before 5.16.0.
* Remove deprecated APIs `GetColumnFamilyOptionsFrom{Map|String}(const ColumnFamilyOptions&, ..)`, `GetDBOptionsFrom{Map|String}(const DBOptions&, ..)`, `GetBlockBasedTableOptionsFrom{Map|String}(const BlockBasedTableOptions& table_options, ..)` and ` GetPlainTableOptionsFrom{Map|String}(const PlainTableOptions& table_options,..)`.
* Added a subcode of `Status::Corruption`, `Status::SubCode::kMergeOperatorFailed`, for users to identify corruption failures originating in the merge operator, as opposed to RocksDB's internally identified data corruptions
+1 -1
View File
@@ -16,7 +16,7 @@
#include "db/db_impl/db_impl.h"
#include "monitoring/histogram.h"
#include "port/port.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/convenience.h"
#include "rocksdb/db.h"
#include "rocksdb/env.h"
+1 -1
View File
@@ -7,7 +7,7 @@
#include <cassert>
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE {
+1 -1
View File
@@ -8,7 +8,7 @@
#include <algorithm>
#include <atomic>
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "table/unique_id_impl.h"
#include "util/hash.h"
#include "util/math.h"
+1 -1
View File
@@ -8,7 +8,7 @@
#include <string>
#include "port/port.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
namespace ROCKSDB_NAMESPACE {
+37
View File
@@ -1784,6 +1784,43 @@ TEST_F(DBSecondaryCacheTest, SecondaryCacheFailureTest) {
Destroy(options);
}
TEST_F(DBSecondaryCacheTest, TestSecondaryWithCompressedCache) {
if (!Snappy_Supported()) {
ROCKSDB_GTEST_SKIP("Compressed cache test requires snappy support");
return;
}
LRUCacheOptions opts(2000 /* capacity */, 0 /* num_shard_bits */,
false /* strict_capacity_limit */,
0.5 /* high_pri_pool_ratio */,
nullptr /* memory_allocator */, kDefaultToAdaptiveMutex,
kDontChargeCacheMetadata);
std::shared_ptr<TestSecondaryCache> secondary_cache(
new TestSecondaryCache(2048 * 1024));
opts.secondary_cache = secondary_cache;
std::shared_ptr<Cache> cache = NewLRUCache(opts);
BlockBasedTableOptions table_options;
table_options.block_cache_compressed = cache;
table_options.no_block_cache = true;
table_options.block_size = 1234;
Options options = GetDefaultOptions();
options.compression = kSnappyCompression;
options.create_if_missing = true;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
DestroyAndReopen(options);
Random rnd(301);
const int N = 6;
for (int i = 0; i < N; i++) {
// Partly compressible
std::string p_v = rnd.RandomString(507) + std::string(500, ' ');
ASSERT_OK(Put(Key(i), p_v));
}
ASSERT_OK(Flush());
for (int i = 0; i < 2 * N; i++) {
std::string v = Get(Key(i % N));
ASSERT_EQ(1007, v.size());
}
}
TEST_F(LRUCacheSecondaryCacheTest, BasicWaitAllTest) {
LRUCacheOptions opts(1024 /* capacity */, 2 /* num_shard_bits */,
false /* strict_capacity_limit */,
+1 -1
View File
@@ -15,7 +15,7 @@
#include "port/lang.h"
#include "port/port.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "util/hash.h"
#include "util/mutexlock.h"
+1 -1
View File
@@ -29,8 +29,8 @@
#include <type_traits>
#include "cache/cache_helpers.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/advanced_options.h"
#include "rocksdb/cache.h"
namespace ROCKSDB_NAMESPACE {
+1 -1
View File
@@ -8,7 +8,7 @@
#include <memory>
#include "memory/memory_allocator.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/rocksdb_namespace.h"
#include "rocksdb/slice.h"
#include "rocksdb/status.h"
+12 -8
View File
@@ -16,7 +16,7 @@
#include <vector>
#include "port/port.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/compaction_filter.h"
#include "rocksdb/comparator.h"
#include "rocksdb/convenience.h"
@@ -68,7 +68,6 @@ using ROCKSDB_NAMESPACE::CompactionOptionsFIFO;
using ROCKSDB_NAMESPACE::CompactRangeOptions;
using ROCKSDB_NAMESPACE::Comparator;
using ROCKSDB_NAMESPACE::CompressionType;
using ROCKSDB_NAMESPACE::ConfigOptions;
using ROCKSDB_NAMESPACE::CuckooTableOptions;
using ROCKSDB_NAMESPACE::DB;
using ROCKSDB_NAMESPACE::DBOptions;
@@ -2498,12 +2497,8 @@ void rocksdb_load_latest_options(
rocksdb_options_t*** list_column_family_options, char** errptr) {
DBOptions db_opt;
std::vector<ColumnFamilyDescriptor> cf_descs;
ConfigOptions config_opts;
config_opts.ignore_unknown_options = ignore_unknown_options;
config_opts.input_strings_escaped = true;
config_opts.env = env->rep;
Status s = LoadLatestOptions(config_opts, std::string(db_path), &db_opt,
&cf_descs, &cache->rep);
Status s = LoadLatestOptions(std::string(db_path), env->rep, &db_opt,
&cf_descs, ignore_unknown_options, &cache->rep);
if (s.ok()) {
char** cf_names = (char**)malloc(cf_descs.size() * sizeof(char*));
rocksdb_options_t** cf_options = (rocksdb_options_t**)malloc(
@@ -2624,6 +2619,14 @@ void rocksdb_block_based_options_set_block_cache(
}
}
void rocksdb_block_based_options_set_block_cache_compressed(
rocksdb_block_based_table_options_t* options,
rocksdb_cache_t* block_cache_compressed) {
if (block_cache_compressed) {
options->rep.block_cache_compressed = block_cache_compressed->rep;
}
}
void rocksdb_block_based_options_set_whole_key_filtering(
rocksdb_block_based_table_options_t* options, unsigned char v) {
options->rep.whole_key_filtering = v;
@@ -6397,3 +6400,4 @@ void rocksdb_enable_manual_compaction(rocksdb_t* db) {
}
} // end extern "C"
+21 -12
View File
@@ -3434,13 +3434,17 @@ INSTANTIATE_TEST_CASE_P(DBBasicTestTrackWal, DBBasicTestTrackWal,
class DBBasicTestMultiGet : public DBTestBase {
public:
DBBasicTestMultiGet(std::string test_dir, int num_cfs,
DBBasicTestMultiGet(std::string test_dir, int num_cfs, bool compressed_cache,
bool uncompressed_cache, bool _compression_enabled,
bool _fill_cache, uint32_t compression_parallel_threads)
: DBTestBase(test_dir, /*env_do_fsync=*/false) {
compression_enabled_ = _compression_enabled;
fill_cache_ = _fill_cache;
if (compressed_cache) {
std::shared_ptr<Cache> cache = NewLRUCache(1048576);
compressed_cache_ = std::make_shared<MyBlockCache>(cache);
}
if (uncompressed_cache) {
std::shared_ptr<Cache> cache = NewLRUCache(1048576);
uncompressed_cache_ = std::make_shared<MyBlockCache>(cache);
@@ -3477,6 +3481,7 @@ class DBBasicTestMultiGet : public DBTestBase {
} else {
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
}
table_options.block_cache_compressed = compressed_cache_;
table_options.flush_block_policy_factory.reset(
new MyFlushBlockPolicyFactory());
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -3659,14 +3664,16 @@ class DBBasicTestMultiGet : public DBTestBase {
std::vector<std::string> cf_names_;
};
class DBBasicTestWithParallelIO : public DBBasicTestMultiGet,
public testing::WithParamInterface<
std::tuple<bool, bool, bool, uint32_t>> {
class DBBasicTestWithParallelIO
: public DBBasicTestMultiGet,
public testing::WithParamInterface<
std::tuple<bool, bool, bool, bool, uint32_t>> {
public:
DBBasicTestWithParallelIO()
: DBBasicTestMultiGet("/db_basic_test_with_parallel_io", 1,
std::get<0>(GetParam()), std::get<1>(GetParam()),
std::get<2>(GetParam()), std::get<3>(GetParam())) {}
std::get<2>(GetParam()), std::get<3>(GetParam()),
std::get<4>(GetParam())) {}
};
TEST_P(DBBasicTestWithParallelIO, MultiGet) {
@@ -3995,12 +4002,13 @@ TEST_P(DBBasicTestWithParallelIO, MultiGetWithMissingFile) {
INSTANTIATE_TEST_CASE_P(ParallelIO, DBBasicTestWithParallelIO,
// Params are as follows -
// Param 0 - Uncompressed cache enabled
// Param 1 - Data compression enabled
// Param 2 - ReadOptions::fill_cache
// Param 3 - CompressionOptions::parallel_threads
// Param 0 - Compressed cache enabled
// Param 1 - Uncompressed cache enabled
// Param 2 - Data compression enabled
// Param 3 - ReadOptions::fill_cache
// Param 4 - CompressionOptions::parallel_threads
::testing::Combine(::testing::Bool(), ::testing::Bool(),
::testing::Bool(),
::testing::Bool(), ::testing::Bool(),
::testing::Values(1, 4)));
// Forward declaration
@@ -4211,8 +4219,9 @@ class DBBasicTestMultiGetDeadline : public DBBasicTestMultiGet,
DBBasicTestMultiGetDeadline()
: DBBasicTestMultiGet(
"db_basic_test_multiget_deadline" /*Test dir*/,
10 /*# of column families*/, true /*uncompressed cache enabled*/,
true /*compression enabled*/, true /*ReadOptions.fill_cache*/,
10 /*# of column families*/, false /*compressed cache enabled*/,
true /*uncompressed cache enabled*/, true /*compression enabled*/,
true /*ReadOptions.fill_cache*/,
1 /*# of parallel compression threads*/) {}
inline void CheckStatus(std::vector<Status>& statuses, size_t num_ok) {
+351 -15
View File
@@ -44,6 +44,10 @@ class DBBlockCacheTest : public DBTestBase {
size_t compression_dict_miss_count_ = 0;
size_t compression_dict_hit_count_ = 0;
size_t compression_dict_insert_count_ = 0;
size_t compressed_miss_count_ = 0;
size_t compressed_hit_count_ = 0;
size_t compressed_insert_count_ = 0;
size_t compressed_failure_count_ = 0;
public:
const size_t kNumBlocks = 10;
@@ -81,6 +85,14 @@ class DBBlockCacheTest : public DBTestBase {
hit_count_ = TestGetTickerCount(options, BLOCK_CACHE_HIT);
insert_count_ = TestGetTickerCount(options, BLOCK_CACHE_ADD);
failure_count_ = TestGetTickerCount(options, BLOCK_CACHE_ADD_FAILURES);
compressed_miss_count_ =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS);
compressed_hit_count_ =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT);
compressed_insert_count_ =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD);
compressed_failure_count_ =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD_FAILURES);
}
void RecordCacheCountersForCompressionDict(const Options& options) {
@@ -132,6 +144,29 @@ class DBBlockCacheTest : public DBTestBase {
compression_dict_insert_count_ = new_compression_dict_insert_count;
}
void CheckCompressedCacheCounters(const Options& options,
size_t expected_misses,
size_t expected_hits,
size_t expected_inserts,
size_t expected_failures) {
size_t new_miss_count =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS);
size_t new_hit_count =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT);
size_t new_insert_count =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD);
size_t new_failure_count =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_ADD_FAILURES);
ASSERT_EQ(compressed_miss_count_ + expected_misses, new_miss_count);
ASSERT_EQ(compressed_hit_count_ + expected_hits, new_hit_count);
ASSERT_EQ(compressed_insert_count_ + expected_inserts, new_insert_count);
ASSERT_EQ(compressed_failure_count_ + expected_failures, new_failure_count);
compressed_miss_count_ = new_miss_count;
compressed_hit_count_ = new_hit_count;
compressed_insert_count_ = new_insert_count;
compressed_failure_count_ = new_failure_count;
}
const std::array<size_t, kNumCacheEntryRoles> GetCacheEntryRoleCountsBg() {
// Verify in cache entry role stats
std::array<size_t, kNumCacheEntryRoles> cache_entry_role_counts;
@@ -237,6 +272,84 @@ TEST_F(DBBlockCacheTest, TestWithoutCompressedBlockCache) {
}
#ifdef SNAPPY
TEST_F(DBBlockCacheTest, TestWithCompressedBlockCache) {
Options options = CurrentOptions();
options.create_if_missing = true;
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
table_options.block_cache_compressed = nullptr;
table_options.block_size = 1;
table_options.filter_policy.reset(NewBloomFilterPolicy(20));
table_options.cache_index_and_filter_blocks = false;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
options.compression = CompressionType::kSnappyCompression;
DestroyAndReopen(options);
std::string value(kValueSize, 'a');
for (size_t i = 0; i < kNumBlocks; i++) {
ASSERT_OK(Put(std::to_string(i), value));
ASSERT_OK(Flush());
}
ReadOptions read_options;
std::shared_ptr<Cache> compressed_cache = NewLRUCache(1 << 25, 0, false);
LRUCacheOptions co;
co.capacity = 0;
co.num_shard_bits = 0;
co.strict_capacity_limit = false;
// Needed not to count entry stats collector
co.metadata_charge_policy = kDontChargeCacheMetadata;
std::shared_ptr<Cache> cache = NewLRUCache(co);
table_options.block_cache = cache;
table_options.no_block_cache = false;
table_options.block_cache_compressed = compressed_cache;
table_options.max_auto_readahead_size = 0;
table_options.cache_index_and_filter_blocks = false;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
Reopen(options);
RecordCacheCounters(options);
// Load blocks into cache.
for (size_t i = 0; i < kNumBlocks - 1; i++) {
ASSERT_EQ(value, Get(std::to_string(i)));
CheckCacheCounters(options, 1, 0, 1, 0);
CheckCompressedCacheCounters(options, 1, 0, 1, 0);
}
size_t usage = cache->GetUsage();
ASSERT_EQ(0, usage);
ASSERT_EQ(usage, cache->GetPinnedUsage());
size_t compressed_usage = compressed_cache->GetUsage();
ASSERT_LT(0, compressed_usage);
// Compressed block cache cannot be pinned.
ASSERT_EQ(0, compressed_cache->GetPinnedUsage());
// Set strict capacity limit flag. Now block will only load into compressed
// block cache.
cache->SetCapacity(usage);
cache->SetStrictCapacityLimit(true);
ASSERT_EQ(usage, cache->GetPinnedUsage());
// Load last key block.
ASSERT_EQ(
"Operation aborted: Memory limit reached: Insert failed due to LRU cache "
"being full.",
Get(std::to_string(kNumBlocks - 1)));
// Failure will also record the miss counter.
CheckCacheCounters(options, 1, 0, 0, 1);
CheckCompressedCacheCounters(options, 1, 0, 1, 0);
// Clear strict capacity limit flag. This time we shall hit compressed block
// cache and load into block cache.
cache->SetStrictCapacityLimit(false);
// Load last key block.
ASSERT_EQ(value, Get(std::to_string(kNumBlocks - 1)));
CheckCacheCounters(options, 1, 0, 1, 0);
CheckCompressedCacheCounters(options, 0, 1, 0, 0);
}
namespace {
class PersistentCacheFromCache : public PersistentCache {
@@ -287,11 +400,9 @@ class PersistentCacheFromCache : public PersistentCache {
};
class ReadOnlyCacheWrapper : public CacheWrapper {
public:
using CacheWrapper::CacheWrapper;
const char* Name() const override { return "ReadOnlyCacheWrapper"; }
using Cache::Insert;
Status Insert(const Slice& /*key*/, Cache::ObjectPtr /*value*/,
const CacheItemHelper* /*helper*/, size_t /*charge*/,
Handle** /*handle*/, Priority /*priority*/) override {
@@ -300,6 +411,80 @@ class ReadOnlyCacheWrapper : public CacheWrapper {
};
} // anonymous namespace
TEST_F(DBBlockCacheTest, TestWithSameCompressed) {
auto table_options = GetTableOptions();
auto options = GetOptions(table_options);
InitTable(options);
std::shared_ptr<Cache> rw_cache{NewLRUCache(1000000)};
std::shared_ptr<PersistentCacheFromCache> rw_pcache{
new PersistentCacheFromCache(rw_cache, /*read_only*/ false)};
// Exercise some obscure behavior with read-only wrappers
std::shared_ptr<Cache> ro_cache{new ReadOnlyCacheWrapper(rw_cache)};
std::shared_ptr<PersistentCacheFromCache> ro_pcache{
new PersistentCacheFromCache(rw_cache, /*read_only*/ true)};
// Simple same pointer
table_options.block_cache = rw_cache;
table_options.block_cache_compressed = rw_cache;
table_options.persistent_cache.reset();
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: block_cache same as block_cache_compressed not "
"currently supported, and would be bad for performance anyway");
// Other cases
table_options.block_cache = ro_cache;
table_options.block_cache_compressed = rw_cache;
table_options.persistent_cache.reset();
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: block_cache and block_cache_compressed share "
"the same key space, which is not supported");
table_options.block_cache = rw_cache;
table_options.block_cache_compressed = ro_cache;
table_options.persistent_cache.reset();
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: block_cache_compressed and block_cache share "
"the same key space, which is not supported");
table_options.block_cache = ro_cache;
table_options.block_cache_compressed.reset();
table_options.persistent_cache = rw_pcache;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: block_cache and persistent_cache share the same "
"key space, which is not supported");
table_options.block_cache = rw_cache;
table_options.block_cache_compressed.reset();
table_options.persistent_cache = ro_pcache;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: persistent_cache and block_cache share the same "
"key space, which is not supported");
table_options.block_cache.reset();
table_options.no_block_cache = true;
table_options.block_cache_compressed = ro_cache;
table_options.persistent_cache = rw_pcache;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: block_cache_compressed and persistent_cache "
"share the same key space, which is not supported");
table_options.block_cache.reset();
table_options.no_block_cache = true;
table_options.block_cache_compressed = rw_cache;
table_options.persistent_cache = ro_pcache;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ASSERT_EQ(TryReopen(options).ToString(),
"Invalid argument: persistent_cache and block_cache_compressed "
"share the same key space, which is not supported");
}
#endif // SNAPPY
@@ -421,6 +606,11 @@ TEST_F(DBBlockCacheTest, IndexAndFilterBlocksStats) {
ASSERT_EQ(cache->GetUsage(), index_bytes_insert + filter_bytes_insert);
// set the cache capacity to the current usage
cache->SetCapacity(index_bytes_insert + filter_bytes_insert);
// The index and filter eviction statistics were broken by the refactoring
// that moved the readers out of the block cache. Disabling these until we can
// bring the stats back.
// ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_INDEX_BYTES_EVICT), 0);
// ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_FILTER_BYTES_EVICT), 0);
// Note that the second key needs to be no longer than the first one.
// Otherwise the second index block may not fit in cache.
ASSERT_OK(Put(1, "key", "val"));
@@ -431,6 +621,13 @@ TEST_F(DBBlockCacheTest, IndexAndFilterBlocksStats) {
index_bytes_insert);
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_FILTER_BYTES_INSERT),
filter_bytes_insert);
// The index and filter eviction statistics were broken by the refactoring
// that moved the readers out of the block cache. Disabling these until we can
// bring the stats back.
// ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_INDEX_BYTES_EVICT),
// index_bytes_insert);
// ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_FILTER_BYTES_EVICT),
// filter_bytes_insert);
}
#if (defined OS_LINUX || defined OS_WIN)
@@ -713,8 +910,7 @@ class LookupLiarCache : public CacheWrapper {
explicit LookupLiarCache(std::shared_ptr<Cache> target)
: CacheWrapper(std::move(target)) {}
const char* Name() const override { return "LookupLiarCache"; }
using Cache::Lookup;
Handle* Lookup(const Slice& key, const CacheItemHelper* helper = nullptr,
CreateContext* create_context = nullptr,
Priority priority = Priority::LOW, bool wait = true,
@@ -887,6 +1083,124 @@ TEST_F(DBBlockCacheTest, ParanoidFileChecks) {
TestGetTickerCount(options, BLOCK_CACHE_ADD));
}
TEST_F(DBBlockCacheTest, CompressedCache) {
if (!Snappy_Supported()) {
return;
}
int num_iter = 80;
// Run this test three iterations.
// Iteration 1: only a uncompressed block cache
// Iteration 2: only a compressed block cache
// Iteration 3: both block cache and compressed cache
// Iteration 4: both block cache and compressed cache, but DB is not
// compressed
for (int iter = 0; iter < 4; iter++) {
Options options = CurrentOptions();
options.write_buffer_size = 64 * 1024; // small write buffer
options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
BlockBasedTableOptions table_options;
switch (iter) {
case 0:
// only uncompressed block cache
table_options.block_cache = NewLRUCache(8 * 1024);
table_options.block_cache_compressed = nullptr;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
case 1:
// no block cache, only compressed cache
table_options.no_block_cache = true;
table_options.block_cache = nullptr;
table_options.block_cache_compressed = NewLRUCache(8 * 1024);
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
case 2:
// both compressed and uncompressed block cache
table_options.block_cache = NewLRUCache(1024);
table_options.block_cache_compressed = NewLRUCache(8 * 1024);
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
case 3:
// both block cache and compressed cache, but DB is not compressed
// also, make block cache sizes bigger, to trigger block cache hits
table_options.block_cache = NewLRUCache(1024 * 1024);
table_options.block_cache_compressed = NewLRUCache(8 * 1024 * 1024);
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
options.compression = kNoCompression;
break;
default:
FAIL();
}
CreateAndReopenWithCF({"pikachu"}, options);
// default column family doesn't have block cache
Options no_block_cache_opts;
no_block_cache_opts.statistics = options.statistics;
no_block_cache_opts = CurrentOptions(no_block_cache_opts);
BlockBasedTableOptions table_options_no_bc;
table_options_no_bc.no_block_cache = true;
no_block_cache_opts.table_factory.reset(
NewBlockBasedTableFactory(table_options_no_bc));
ReopenWithColumnFamilies(
{"default", "pikachu"},
std::vector<Options>({no_block_cache_opts, options}));
Random rnd(301);
// Write 8MB (80 values, each 100K)
ASSERT_EQ(NumTableFilesAtLevel(0, 1), 0);
std::vector<std::string> values;
std::string str;
for (int i = 0; i < num_iter; i++) {
if (i % 4 == 0) { // high compression ratio
str = rnd.RandomString(1000);
}
values.push_back(str);
ASSERT_OK(Put(1, Key(i), values[i]));
}
// flush all data from memtable so that reads are from block cache
ASSERT_OK(Flush(1));
for (int i = 0; i < num_iter; i++) {
ASSERT_EQ(Get(1, Key(i)), values[i]);
}
// check that we triggered the appropriate code paths in the cache
switch (iter) {
case 0:
// only uncompressed block cache
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_MISS), 0);
ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS), 0);
break;
case 1:
// no block cache, only compressed cache
ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_MISS), 0);
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS), 0);
break;
case 2:
// both compressed and uncompressed block cache
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_MISS), 0);
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS), 0);
break;
case 3:
// both compressed and uncompressed block cache
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_MISS), 0);
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_HIT), 0);
ASSERT_GT(TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS), 0);
// compressed doesn't have any hits since blocks are not compressed on
// storage
ASSERT_EQ(TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT), 0);
break;
default:
FAIL();
}
options.create_if_missing = true;
DestroyAndReopen(options);
}
}
TEST_F(DBBlockCacheTest, CacheCompressionDict) {
const int kNumFiles = 4;
const int kNumEntriesPerFile = 128;
@@ -1390,16 +1704,31 @@ TEST_P(DBBlockCacheKeyTest, StableCacheKeys) {
uint64_t expected_stat = 0;
std::function<void()> verify_stats;
table_options.cache_index_and_filter_blocks = true;
table_options.block_cache = NewLRUCache(1 << 25, 0, false);
verify_stats = [&options, &expected_stat] {
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_DATA_ADD));
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_INDEX_ADD));
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_FILTER_ADD));
};
if (use_compressed_cache_) {
if (!Snappy_Supported()) {
ROCKSDB_GTEST_SKIP("Compressed cache test requires snappy support");
return;
}
options.compression = CompressionType::kSnappyCompression;
table_options.no_block_cache = true;
table_options.block_cache_compressed = NewLRUCache(1 << 25, 0, false);
verify_stats = [&options, &expected_stat] {
// One for ordinary SST file and one for external SST file
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_COMPRESSED_ADD));
};
} else {
table_options.cache_index_and_filter_blocks = true;
table_options.block_cache = NewLRUCache(1 << 25, 0, false);
verify_stats = [&options, &expected_stat] {
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_DATA_ADD));
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_INDEX_ADD));
ASSERT_EQ(expected_stat,
options.statistics->getTickerCount(BLOCK_CACHE_FILTER_ADD));
};
}
table_options.filter_policy.reset(NewBloomFilterPolicy(10, false));
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
@@ -1469,6 +1798,13 @@ TEST_P(DBBlockCacheKeyTest, StableCacheKeys) {
ASSERT_OK(db_->IngestExternalFile(handles_[1], {f}, ingest_opts));
}
if (exclude_file_numbers_) {
// FIXME(peterd): figure out where these extra ADDs are coming from
options.statistics->recordTick(BLOCK_CACHE_COMPRESSED_ADD,
uint64_t{0} - uint64_t{2});
}
#endif
perform_gets();
verify_stats();
+4
View File
@@ -2223,6 +2223,7 @@ TEST_P(DBIteratorTest, ReadAhead) {
size_t bytes_read = env_->random_read_bytes_counter_;
delete iter;
int64_t num_file_closes = TestGetTickerCount(options, NO_FILE_CLOSES);
env_->random_read_bytes_counter_ = 0;
options.statistics->setTickerCount(NO_FILE_OPENS, 0);
read_options.readahead_size = 1024 * 10;
@@ -2231,7 +2232,10 @@ TEST_P(DBIteratorTest, ReadAhead) {
int64_t num_file_opens_readahead = TestGetTickerCount(options, NO_FILE_OPENS);
size_t bytes_read_readahead = env_->random_read_bytes_counter_;
delete iter;
int64_t num_file_closes_readahead =
TestGetTickerCount(options, NO_FILE_CLOSES);
ASSERT_EQ(num_file_opens, num_file_opens_readahead);
ASSERT_EQ(num_file_closes, num_file_closes_readahead);
ASSERT_GT(bytes_read_readahead, bytes_read);
ASSERT_GT(bytes_read_readahead, read_options.readahead_size * 3);
+1
View File
@@ -240,6 +240,7 @@ TEST_P(DBTestTailingIterator, TailingIteratorTrimSeekToNext) {
iterh = nullptr;
BlockBasedTableOptions table_options;
table_options.no_block_cache = true;
table_options.block_cache_compressed = nullptr;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
ReopenWithColumnFamilies({"default", "pikachu"}, options);
read_options.read_tier = kBlockCacheTier;
+61
View File
@@ -105,6 +105,66 @@ TEST_F(DBTest2, OpenForReadOnlyWithColumnFamilies) {
ASSERT_NOK(env_->FileExists(dbname));
}
class TestReadOnlyWithCompressedCache
: public DBTestBase,
public testing::WithParamInterface<std::tuple<int, bool>> {
public:
TestReadOnlyWithCompressedCache()
: DBTestBase("test_readonly_with_compressed_cache",
/*env_do_fsync=*/true) {
max_open_files_ = std::get<0>(GetParam());
use_mmap_ = std::get<1>(GetParam());
}
int max_open_files_;
bool use_mmap_;
};
TEST_P(TestReadOnlyWithCompressedCache, ReadOnlyWithCompressedCache) {
if (use_mmap_ && !IsMemoryMappedAccessSupported()) {
ROCKSDB_GTEST_SKIP("Test requires MMAP support");
return;
}
ASSERT_OK(Put("foo", "bar"));
ASSERT_OK(Put("foo2", "barbarbarbarbarbarbarbar"));
ASSERT_OK(Flush());
DB* db_ptr = nullptr;
Options options = CurrentOptions();
options.allow_mmap_reads = use_mmap_;
options.max_open_files = max_open_files_;
options.compression = kSnappyCompression;
BlockBasedTableOptions table_options;
table_options.block_cache_compressed = NewLRUCache(8 * 1024 * 1024);
table_options.no_block_cache = true;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
options.statistics = CreateDBStatistics();
ASSERT_OK(DB::OpenForReadOnly(options, dbname_, &db_ptr));
std::string v;
ASSERT_OK(db_ptr->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("bar", v);
ASSERT_EQ(0, options.statistics->getTickerCount(BLOCK_CACHE_COMPRESSED_HIT));
ASSERT_OK(db_ptr->Get(ReadOptions(), "foo", &v));
ASSERT_EQ("bar", v);
if (Snappy_Supported()) {
if (use_mmap_) {
ASSERT_EQ(0,
options.statistics->getTickerCount(BLOCK_CACHE_COMPRESSED_HIT));
} else {
ASSERT_EQ(1,
options.statistics->getTickerCount(BLOCK_CACHE_COMPRESSED_HIT));
}
}
delete db_ptr;
}
INSTANTIATE_TEST_CASE_P(TestReadOnlyWithCompressedCache,
TestReadOnlyWithCompressedCache,
::testing::Combine(::testing::Values(-1, 100),
::testing::Bool()));
class PartitionedIndexTestListener : public EventListener {
public:
void OnFlushCompleted(DB* /*db*/, const FlushJobInfo& info) override {
@@ -2550,6 +2610,7 @@ TEST_F(DBTest2, PersistentCache) {
new MockPersistentCache(type, 10 * 1024));
table_options.no_block_cache = true;
table_options.block_cache = bsize ? NewLRUCache(bsize) : nullptr;
table_options.block_cache_compressed = nullptr;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
DestroyAndReopen(options);
+4
View File
@@ -460,6 +460,10 @@ Options DBTestBase::GetOptions(
options.compaction_style = kCompactionStyleUniversal;
options.num_levels = 8;
break;
case kCompressedBlockCache:
options.allow_mmap_writes = can_allow_mmap;
table_options.block_cache_compressed = NewLRUCache(8 * 1024 * 1024);
break;
case kInfiniteMaxOpenFiles:
options.max_open_files = -1;
break;
+86 -11
View File
@@ -909,6 +909,82 @@ class TestPutOperator : public MergeOperator {
virtual const char* Name() const override { return "TestPutOperator"; }
};
// A wrapper around Cache that can easily be extended with instrumentation,
// etc.
class CacheWrapper : public Cache {
public:
explicit CacheWrapper(std::shared_ptr<Cache> target)
: target_(std::move(target)) {}
const char* Name() const override { return target_->Name(); }
Status Insert(const Slice& key, ObjectPtr value,
const CacheItemHelper* helper, size_t charge,
Handle** handle = nullptr,
Priority priority = Priority::LOW) override {
return target_->Insert(key, value, helper, charge, handle, priority);
}
Handle* Lookup(const Slice& key, const CacheItemHelper* helper,
CreateContext* create_context,
Priority priority = Priority::LOW, bool wait = true,
Statistics* stats = nullptr) override {
return target_->Lookup(key, helper, create_context, priority, wait, stats);
}
bool Ref(Handle* handle) override { return target_->Ref(handle); }
using Cache::Release;
bool Release(Handle* handle, bool erase_if_last_ref = false) override {
return target_->Release(handle, erase_if_last_ref);
}
ObjectPtr Value(Handle* handle) override { return target_->Value(handle); }
void Erase(const Slice& key) override { target_->Erase(key); }
uint64_t NewId() override { return target_->NewId(); }
void SetCapacity(size_t capacity) override { target_->SetCapacity(capacity); }
void SetStrictCapacityLimit(bool strict_capacity_limit) override {
target_->SetStrictCapacityLimit(strict_capacity_limit);
}
bool HasStrictCapacityLimit() const override {
return target_->HasStrictCapacityLimit();
}
size_t GetCapacity() const override { return target_->GetCapacity(); }
size_t GetUsage() const override { return target_->GetUsage(); }
size_t GetUsage(Handle* handle) const override {
return target_->GetUsage(handle);
}
size_t GetPinnedUsage() const override { return target_->GetPinnedUsage(); }
size_t GetCharge(Handle* handle) const override {
return target_->GetCharge(handle);
}
const CacheItemHelper* GetCacheItemHelper(Handle* handle) const override {
return target_->GetCacheItemHelper(handle);
}
void ApplyToAllEntries(
const std::function<void(const Slice& key, ObjectPtr value, size_t charge,
const CacheItemHelper* helper)>& callback,
const ApplyToAllEntriesOptions& opts) override {
target_->ApplyToAllEntries(callback, opts);
}
void EraseUnRefEntries() override { target_->EraseUnRefEntries(); }
protected:
std::shared_ptr<Cache> target_;
};
/*
* A cache wrapper that tracks certain CacheEntryRole's cache charge, its
* peaks and increments
@@ -926,8 +1002,6 @@ class TargetCacheChargeTrackingCache : public CacheWrapper {
public:
explicit TargetCacheChargeTrackingCache(std::shared_ptr<Cache> target);
const char* Name() const override { return "TargetCacheChargeTrackingCache"; }
Status Insert(const Slice& key, ObjectPtr value,
const CacheItemHelper* helper, size_t charge,
Handle** handle = nullptr,
@@ -980,15 +1054,16 @@ class DBTestBase : public testing::Test {
kHashSkipList = 18,
kUniversalCompaction = 19,
kUniversalCompactionMultiLevel = 20,
kInfiniteMaxOpenFiles = 21,
kCRC32cChecksum = 22,
kFIFOCompaction = 23,
kOptimizeFiltersForHits = 24,
kRowCache = 25,
kRecycleLogFiles = 26,
kConcurrentSkipList = 27,
kPipelinedWrite = 28,
kConcurrentWALWrites = 29,
kCompressedBlockCache = 21,
kInfiniteMaxOpenFiles = 22,
kCRC32cChecksum = 23,
kFIFOCompaction = 24,
kOptimizeFiltersForHits = 25,
kRowCache = 26,
kRecycleLogFiles = 27,
kConcurrentSkipList = 28,
kPipelinedWrite = 29,
kConcurrentWALWrites = 30,
kDirectIO,
kLevelSubcompactions,
kBlockBasedTableWithIndexRestartInterval,
+1 -1
View File
@@ -20,8 +20,8 @@
#include "db/wal_edit.h"
#include "memory/arena.h"
#include "port/malloc.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/advanced_options.h"
#include "rocksdb/cache.h"
#include "table/table_reader.h"
#include "table/unique_id_impl.h"
#include "util/autovector.h"
+13 -7
View File
@@ -53,6 +53,8 @@ std::shared_ptr<const FilterPolicy> CreateFilterPolicy() {
StressTest::StressTest()
: cache_(NewCache(FLAGS_cache_size, FLAGS_cache_numshardbits)),
compressed_cache_(NewLRUCache(FLAGS_compressed_cache_size,
FLAGS_compressed_cache_numshardbits)),
filter_policy_(CreateFilterPolicy()),
db_(nullptr),
txn_db_(nullptr),
@@ -2484,9 +2486,10 @@ void StressTest::Open(SharedState* shared) {
assert(db_ == nullptr);
assert(txn_db_ == nullptr);
if (!InitializeOptionsFromFile(options_)) {
InitializeOptionsFromFlags(cache_, filter_policy_, options_);
InitializeOptionsFromFlags(cache_, compressed_cache_, filter_policy_,
options_);
}
InitializeOptionsGeneral(cache_, filter_policy_, options_);
InitializeOptionsGeneral(cache_, compressed_cache_, filter_policy_, options_);
if (FLAGS_prefix_size == 0 && FLAGS_rep_factory == kHashSkipList) {
fprintf(stderr,
@@ -2943,13 +2946,9 @@ void CheckAndSetOptionsForUserTimestamp(Options& options) {
bool InitializeOptionsFromFile(Options& options) {
DBOptions db_options;
ConfigOptions config_options;
config_options.ignore_unknown_options = false;
config_options.input_strings_escaped = true;
config_options.env = db_stress_env;
std::vector<ColumnFamilyDescriptor> cf_descriptors;
if (!FLAGS_options_file.empty()) {
Status s = LoadOptionsFromFile(config_options, FLAGS_options_file,
Status s = LoadOptionsFromFile(FLAGS_options_file, db_stress_env,
&db_options, &cf_descriptors);
if (!s.ok()) {
fprintf(stderr, "Unable to load options file %s --- %s\n",
@@ -2965,6 +2964,7 @@ bool InitializeOptionsFromFile(Options& options) {
void InitializeOptionsFromFlags(
const std::shared_ptr<Cache>& cache,
const std::shared_ptr<Cache>& block_cache_compressed,
const std::shared_ptr<const FilterPolicy>& filter_policy,
Options& options) {
BlockBasedTableOptions block_based_options;
@@ -2977,6 +2977,7 @@ void InitializeOptionsFromFlags(
static_cast<PinningTier>(FLAGS_partition_pinning);
block_based_options.metadata_cache_options.unpartitioned_pinning =
static_cast<PinningTier>(FLAGS_unpartitioned_pinning);
block_based_options.block_cache_compressed = block_cache_compressed;
block_based_options.checksum = checksum_type_e;
block_based_options.block_size = FLAGS_block_size;
block_based_options.cache_usage_options.options_overrides.insert(
@@ -3219,6 +3220,7 @@ void InitializeOptionsFromFlags(
void InitializeOptionsGeneral(
const std::shared_ptr<Cache>& cache,
const std::shared_ptr<Cache>& block_cache_compressed,
const std::shared_ptr<const FilterPolicy>& filter_policy,
Options& options) {
options.create_missing_column_families = true;
@@ -3239,6 +3241,10 @@ void InitializeOptionsGeneral(
if (FLAGS_cache_size > 0) {
table_options->block_cache = cache;
}
if (!table_options->block_cache_compressed &&
FLAGS_compressed_cache_size > 0) {
table_options->block_cache_compressed = block_cache_compressed;
}
if (!table_options->filter_policy) {
table_options->filter_policy = filter_policy;
}
+4 -2
View File
@@ -282,6 +282,7 @@ extern bool InitializeOptionsFromFile(Options& options);
// input arguments.
extern void InitializeOptionsFromFlags(
const std::shared_ptr<Cache>& cache,
const std::shared_ptr<Cache>& block_cache_compressed,
const std::shared_ptr<const FilterPolicy>& filter_policy, Options& options);
// Initialize `options` on which `InitializeOptionsFromFile()` and
@@ -289,7 +290,7 @@ extern void InitializeOptionsFromFlags(
// There are two cases.
// Case 1: OPTIONS file is not specified. Command line arguments have been used
// to initialize `options`. InitializeOptionsGeneral() will use
// `cache` and `filter_policy` to initialize
// `cache`, `block_cache_compressed` and `filter_policy` to initialize
// corresponding fields of `options`. InitializeOptionsGeneral() will
// also set up other fields of `options` so that stress test can run.
// Examples include `create_if_missing` and
@@ -300,13 +301,14 @@ extern void InitializeOptionsFromFlags(
// case, if command line arguments indicate that the user wants to set
// up such shared objects, e.g. block cache, compressed block cache,
// row cache, filter policy, then InitializeOptionsGeneral() will honor
// the user's choice, thus passing `cache`,
// the user's choice, thus passing `cache`, `block_cache_compressed`,
// `filter_policy` as input arguments.
//
// InitializeOptionsGeneral() must not overwrite fields of `options` loaded
// from OPTIONS file.
extern void InitializeOptionsGeneral(
const std::shared_ptr<Cache>& cache,
const std::shared_ptr<Cache>& block_cache_compressed,
const std::shared_ptr<const FilterPolicy>& filter_policy, Options& options);
// If no OPTIONS file is specified, set up `options` so that we can test
-527
View File
@@ -1,527 +0,0 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
//
// APIs for customizing read caches in RocksDB.
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include "rocksdb/cache.h"
#include "rocksdb/memory_allocator.h"
#include "rocksdb/slice.h"
#include "rocksdb/status.h"
namespace ROCKSDB_NAMESPACE {
class Logger;
class Statistics;
// A Cache maps keys to objects resident in memory, tracks reference counts
// on those key-object entries, and is able to remove unreferenced entries
// whenever it wants. All operations are fully thread safe except as noted.
// Inserted entries have a specified "charge" which is some quantity in
// unspecified units, typically bytes of memory used. A Cache will typically
// have a finite capacity in units of charge, and evict entries as needed
// to stay at or below that capacity.
//
// NOTE: This API is for expert use only and is intended more for customizing
// cache behavior than for calling into outside of RocksDB. It is subject to
// change as RocksDB evolves, especially the RocksDB block cache. Overriding
// CacheWrapper is the preferred way of customizing some operations on an
// existing implementation.
//
// INTERNAL: See typed_cache.h for convenient wrappers on top of this API.
// New virtual functions must also be added to CacheWrapper below.
class Cache {
public: // types hidden from API client
// Opaque handle to an entry stored in the cache.
struct Handle {};
public: // types hidden from Cache implementation
// Pointer to cached object of unspecified type. (This type alias is
// provided for clarity, not really for type checking.)
using ObjectPtr = void*;
// Opaque object providing context (settings, etc.) to create objects
// for primary cache from saved (serialized) secondary cache entries.
struct CreateContext {};
public: // type defs
// Depending on implementation, cache entries with higher priority levels
// could be less likely to get evicted than entries with lower priority
// levels. The "high" priority level applies to certain SST metablocks (e.g.
// index and filter blocks) if the option
// cache_index_and_filter_blocks_with_high_priority is set. The "low" priority
// level is used for other kinds of SST blocks (most importantly, data
// blocks), as well as the above metablocks in case
// cache_index_and_filter_blocks_with_high_priority is
// not set. The "bottom" priority level is for BlobDB's blob values.
enum class Priority { HIGH, LOW, BOTTOM };
// A set of callbacks to allow objects in the primary block cache to be
// be persisted in a secondary cache. The purpose of the secondary cache
// is to support other ways of caching the object, such as persistent or
// compressed data, that may require the object to be parsed and transformed
// in some way. Since the primary cache holds C++ objects and the secondary
// cache may only hold flat data that doesn't need relocation, these
// callbacks need to be provided by the user of the block
// cache to do the conversion.
// The CacheItemHelper is passed to Insert() and Lookup(). It has pointers
// to callback functions for size, saving and deletion of the
// object. The callbacks are defined in C-style in order to make them
// stateless and not add to the cache metadata size.
// Saving multiple std::function objects will take up 32 bytes per
// function, even if its not bound to an object and does no capture.
//
// All the callbacks are C-style function pointers in order to simplify
// lifecycle management. Objects in the cache can outlive the parent DB,
// so anything required for these operations should be contained in the
// object itself.
//
// The SizeCallback takes a pointer to the object and returns the size
// of the persistable data. It can be used by the secondary cache to allocate
// memory if needed.
//
// RocksDB callbacks are NOT exception-safe. A callback completing with an
// exception can lead to undefined behavior in RocksDB, including data loss,
// unreported corruption, deadlocks, and more.
using SizeCallback = size_t (*)(ObjectPtr obj);
// The SaveToCallback takes an object pointer and saves the persistable
// data into a buffer. The secondary cache may decide to not store it in a
// contiguous buffer, in which case this callback will be called multiple
// times with increasing offset
using SaveToCallback = Status (*)(ObjectPtr from_obj, size_t from_offset,
size_t length, char* out_buf);
// A function pointer type for destruction of a cache object. This will
// typically call the destructor for the appropriate type of the object.
// The Cache is responsible for copying and reclaiming space for the key,
// but objects are managed in part using this callback. Generally a DeleterFn
// can be nullptr if the ObjectPtr does not need destruction (e.g. nullptr or
// pointer into static data).
using DeleterFn = void (*)(ObjectPtr obj, MemoryAllocator* allocator);
// The CreateCallback is takes in a buffer from the NVM cache and constructs
// an object using it. The callback doesn't have ownership of the buffer and
// should copy the contents into its own buffer. The CreateContext* is
// provided by Lookup and may be used to follow DB- or CF-specific settings.
// In case of some error, non-OK is returned and the caller should ignore
// any result in out_obj. (The implementation must clean up after itself.)
using CreateCallback = Status (*)(const Slice& data, CreateContext* context,
MemoryAllocator* allocator,
ObjectPtr* out_obj, size_t* out_charge);
// A struct with pointers to helper functions for spilling items from the
// cache into the secondary cache. May be extended in the future. An
// instance of this struct is expected to outlive the cache.
struct CacheItemHelper {
// Function for deleting an object on its removal from the Cache.
// nullptr is only for entries that require no destruction, such as
// "placeholder" cache entries with nullptr object.
DeleterFn del_cb; // (<- Most performance critical)
// Next three are used for persisting values as described above.
// If any is nullptr, then all three should be nullptr and persisting the
// entry to/from secondary cache is not supported.
SizeCallback size_cb;
SaveToCallback saveto_cb;
CreateCallback create_cb;
// Classification of the entry for monitoring purposes in block cache.
CacheEntryRole role;
constexpr CacheItemHelper()
: del_cb(nullptr),
size_cb(nullptr),
saveto_cb(nullptr),
create_cb(nullptr),
role(CacheEntryRole::kMisc) {}
explicit constexpr CacheItemHelper(CacheEntryRole _role,
DeleterFn _del_cb = nullptr,
SizeCallback _size_cb = nullptr,
SaveToCallback _saveto_cb = nullptr,
CreateCallback _create_cb = nullptr)
: del_cb(_del_cb),
size_cb(_size_cb),
saveto_cb(_saveto_cb),
create_cb(_create_cb),
role(_role) {
// Either all three secondary cache callbacks are non-nullptr or
// all three are nullptr
assert((size_cb != nullptr) == (saveto_cb != nullptr));
assert((size_cb != nullptr) == (create_cb != nullptr));
}
inline bool IsSecondaryCacheCompatible() const {
return size_cb != nullptr;
}
};
public: // ctor/dtor/create
Cache(std::shared_ptr<MemoryAllocator> allocator = nullptr)
: memory_allocator_(std::move(allocator)) {}
// No copying allowed
Cache(const Cache&) = delete;
Cache& operator=(const Cache&) = delete;
// Destroys all remaining entries by calling the associated "deleter"
virtual ~Cache() {}
// Creates a new Cache based on the input value string and returns the result.
// Currently, this method can be used to create LRUCaches only
// @param config_options
// @param value The value might be:
// - an old-style cache ("1M") -- equivalent to NewLRUCache(1024*102(
// - Name-value option pairs -- "capacity=1M; num_shard_bits=4;
// For the LRUCache, the values are defined in LRUCacheOptions.
// @param result The new Cache object
// @return OK if the cache was successfully created
// @return NotFound if an invalid name was specified in the value
// @return InvalidArgument if either the options were not valid
static Status CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<Cache>* result);
public: // functions
// The type of the Cache
virtual const char* Name() const = 0;
// The Insert and Lookup APIs below are intended to allow cached objects
// to be demoted/promoted between the primary block cache and a secondary
// cache. The secondary cache could be a non-volatile cache, and will
// likely store the object in a different representation. They rely on a
// per object CacheItemHelper to do the conversions.
// The secondary cache may persist across process and system restarts,
// and may even be moved between hosts. Therefore, the cache key must
// be repeatable across restarts/reboots, and globally unique if
// multiple DBs share the same cache and the set of DBs can change
// over time.
// Insert a mapping from key->object into the cache and assign it
// the specified charge against the total cache capacity. If
// strict_capacity_limit is true and cache reaches its full capacity,
// return Status::MemoryLimit. `obj` must be non-nullptr if compatible
// with secondary cache (helper->size_cb != nullptr), because Value() ==
// nullptr is reserved for indicating some secondary cache failure cases.
// On success, returns OK and takes ownership of `obj`, eventually deleting
// it with helper->del_cb. On non-OK return, the caller maintains ownership
// of `obj` so will often need to delete it in such cases.
//
// The helper argument is saved by the cache and will be used when the
// inserted object is evicted or considered for promotion to the secondary
// cache. Promotion to secondary cache is only enabled if helper->size_cb
// != nullptr. The helper must outlive the cache. Callers may use
// &kNoopCacheItemHelper as a trivial helper (no deleter for the object,
// no secondary cache). `helper` must not be nullptr (efficiency).
//
// If `handle` is not nullptr and return status is OK, `handle` is set
// to a Handle* for the entry. The caller must call this->Release(handle)
// when the returned entry is no longer needed. If `handle` is nullptr, it is
// as if Release is called immediately after Insert.
//
// Regardless of whether the item was inserted into the cache,
// it will attempt to insert it into the secondary cache if one is
// configured, and the helper supports it.
// The cache implementation must support a secondary cache, otherwise
// the item is only inserted into the primary cache. It may
// defer the insertion to the secondary cache as it sees fit.
//
// When the inserted entry is no longer needed, it will be destroyed using
// helper->del_cb (if non-nullptr).
virtual Status Insert(const Slice& key, ObjectPtr obj,
const CacheItemHelper* helper, size_t charge,
Handle** handle = nullptr,
Priority priority = Priority::LOW) = 0;
// Lookup the key, returning nullptr if not found. If found, returns
// a handle to the mapping that must eventually be passed to Release().
//
// If a non-nullptr helper argument is provided with a non-nullptr
// create_cb, and a secondary cache is configured, then the secondary
// cache is also queried if lookup in the primary cache fails. If found
// in secondary cache, the provided create_db and create_context are
// used to promote the entry to an object in the primary cache.
// In that case, the helper may be saved and used later when the object
// is evicted, so as usual, the pointed-to helper must outlive the cache.
//
// ======================== Async Lookup (wait=false) ======================
// When wait=false, the handle returned might be in any of three states:
// * Present - If Value() != nullptr, then the result is present and
// the handle can be used just as if wait=true.
// * Pending, not ready (IsReady() == false) - secondary cache is still
// working to retrieve the value. Might become ready any time.
// * Pending, ready (IsReady() == true) - secondary cache has the value
// but it has not been loaded as an object into primary cache. Call to
// Wait()/WaitAll() will not block.
//
// IMPORTANT: Pending handles are not thread-safe, and only these functions
// are allowed on them: Value(), IsReady(), Wait(), WaitAll(). Even Release()
// can only come after Wait() or WaitAll() even though a reference is held.
//
// Only Wait()/WaitAll() gets a Handle out of a Pending state. (Waiting is
// safe and has no effect on other handle states.) After waiting on a Handle,
// it is in one of two states:
// * Present - if Value() != nullptr
// * Failed - if Value() == nullptr, such as if the secondary cache
// initially thought it had the value but actually did not.
//
// Note that given an arbitrary Handle, the only way to distinguish the
// Pending+ready state from the Failed state is to Wait() on it. A cache
// entry not compatible with secondary cache can also have Value()==nullptr
// like the Failed state, but this is not generally a concern.
virtual Handle* Lookup(const Slice& key,
const CacheItemHelper* helper = nullptr,
CreateContext* create_context = nullptr,
Priority priority = Priority::LOW, bool wait = true,
Statistics* stats = nullptr) = 0;
// Convenience wrapper when secondary cache not supported
inline Handle* BasicLookup(const Slice& key, Statistics* stats) {
return Lookup(key, nullptr, nullptr, Priority::LOW, true, stats);
}
// Increments the reference count for the handle if it refers to an entry in
// the cache. Returns true if refcount was incremented; otherwise, returns
// false.
// REQUIRES: handle must have been returned by a method on *this.
virtual bool Ref(Handle* handle) = 0;
/**
* Release a mapping returned by a previous Lookup(). A released entry might
* still remain in cache in case it is later looked up by others. If
* erase_if_last_ref is set then it also erases it from the cache if there is
* no other reference to it. Erasing it should call the deleter function that
* was provided when the entry was inserted.
*
* Returns true if the entry was also erased.
*/
// REQUIRES: handle must not have been released yet.
// REQUIRES: handle must have been returned by a method on *this.
virtual bool Release(Handle* handle, bool erase_if_last_ref = false) = 0;
// Return the object assiciated with a handle returned by a successful
// Lookup(). For historical reasons, this is also known at the "value"
// associated with the key.
// REQUIRES: handle must not have been released yet.
// REQUIRES: handle must have been returned by a method on *this.
virtual ObjectPtr Value(Handle* handle) = 0;
// If the cache contains the entry for the key, erase it. Note that the
// underlying entry will be kept around until all existing handles
// to it have been released.
virtual void Erase(const Slice& key) = 0;
// Return a new numeric id. May be used by multiple clients who are
// sharding the same cache to partition the key space. Typically the
// client will allocate a new id at startup and prepend the id to
// its cache keys.
virtual uint64_t NewId() = 0;
// sets the maximum configured capacity of the cache. When the new
// capacity is less than the old capacity and the existing usage is
// greater than new capacity, the implementation will do its best job to
// purge the released entries from the cache in order to lower the usage
virtual void SetCapacity(size_t capacity) = 0;
// Set whether to return error on insertion when cache reaches its full
// capacity.
virtual void SetStrictCapacityLimit(bool strict_capacity_limit) = 0;
// Get the flag whether to return error on insertion when cache reaches its
// full capacity.
virtual bool HasStrictCapacityLimit() const = 0;
// Returns the maximum configured capacity of the cache
virtual size_t GetCapacity() const = 0;
// Returns the memory size for the entries residing in the cache.
virtual size_t GetUsage() const = 0;
// Returns the number of entries currently tracked in the table. SIZE_MAX
// means "not supported." This is used for inspecting the load factor, along
// with GetTableAddressCount().
virtual size_t GetOccupancyCount() const { return SIZE_MAX; }
// Returns the number of ways the hash function is divided for addressing
// entries. Zero means "not supported." This is used for inspecting the load
// factor, along with GetOccupancyCount().
virtual size_t GetTableAddressCount() const { return 0; }
// Returns the memory size for a specific entry in the cache.
virtual size_t GetUsage(Handle* handle) const = 0;
// Returns the memory size for the entries in use by the system
virtual size_t GetPinnedUsage() const = 0;
// Returns the charge for the specific entry in the cache.
virtual size_t GetCharge(Handle* handle) const = 0;
// Returns the helper for the specified entry.
virtual const CacheItemHelper* GetCacheItemHelper(Handle* handle) const = 0;
// Call this on shutdown if you want to speed it up. Cache will disown
// any underlying data and will not free it on delete. This call will leak
// memory - call this only if you're shutting down the process.
// Any attempts of using cache after this call will fail terribly.
// Always delete the DB object before calling this method!
virtual void DisownData() {
// default implementation is noop
}
struct ApplyToAllEntriesOptions {
// If the Cache uses locks, setting `average_entries_per_lock` to
// a higher value suggests iterating over more entries each time a lock
// is acquired, likely reducing the time for ApplyToAllEntries but
// increasing latency for concurrent users of the Cache. Setting
// `average_entries_per_lock` to a smaller value could be helpful if
// callback is relatively expensive, such as using large data structures.
size_t average_entries_per_lock = 256;
};
// Apply a callback to all entries in the cache. The Cache must ensure
// thread safety but does not guarantee that a consistent snapshot of all
// entries is iterated over if other threads are operating on the Cache
// also.
virtual void ApplyToAllEntries(
const std::function<void(const Slice& key, ObjectPtr obj, size_t charge,
const CacheItemHelper* helper)>& callback,
const ApplyToAllEntriesOptions& opts) = 0;
// Remove all entries.
// Prerequisite: no entry is referenced.
virtual void EraseUnRefEntries() = 0;
virtual std::string GetPrintableOptions() const { return ""; }
// Check for any warnings or errors in the operation of the cache and
// report them to the logger. This is intended only to be called
// periodically so does not need to be very efficient. (Obscure calling
// conventions for Logger inherited from env.h)
virtual void ReportProblems(
const std::shared_ptr<Logger>& /*info_log*/) const {}
MemoryAllocator* memory_allocator() const { return memory_allocator_.get(); }
// EXPERIMENTAL
// The following APIs are experimental and might change in the future.
// Release a mapping returned by a previous Lookup(). The "useful"
// parameter specifies whether the data was actually used or not,
// which may be used by the cache implementation to decide whether
// to consider it as a hit for retention purposes. As noted elsewhere,
// "pending" handles require Wait()/WaitAll() before Release().
virtual bool Release(Handle* handle, bool /*useful*/,
bool erase_if_last_ref) {
return Release(handle, erase_if_last_ref);
}
// Determines if the handle returned by Lookup() can give a value without
// blocking, though Wait()/WaitAll() might be required to publish it to
// Value(). See secondary cache compatible Lookup() above for details.
// This call is not thread safe on "pending" handles.
virtual bool IsReady(Handle* /*handle*/) { return true; }
// Convert a "pending" handle into a full thread-shareable handle by
// * If necessary, wait until secondary cache finishes loading the value.
// * Construct the object for primary cache and set it in the handle.
// Even after Wait() on a pending handle, the caller must check for
// Value() == nullptr in case of failure. This call is not thread-safe
// on pending handles. This call has no effect on non-pending handles.
// See secondary cache compatible Lookup() above for details.
virtual void Wait(Handle* /*handle*/) {}
// Wait for a vector of handles to become ready. As with Wait(), the user
// should check the Value() of each handle for nullptr. This call is not
// thread-safe on pending handles.
virtual void WaitAll(std::vector<Handle*>& /*handles*/) {}
private:
std::shared_ptr<MemoryAllocator> memory_allocator_;
};
// A wrapper around Cache that can easily be extended with instrumentation,
// etc.
class CacheWrapper : public Cache {
public:
explicit CacheWrapper(std::shared_ptr<Cache> target)
: target_(std::move(target)) {}
// Only function that derived class must provide
// const char* Name() const override { ... }
Status Insert(const Slice& key, ObjectPtr value,
const CacheItemHelper* helper, size_t charge,
Handle** handle = nullptr,
Priority priority = Priority::LOW) override {
return target_->Insert(key, value, helper, charge, handle, priority);
}
Handle* Lookup(const Slice& key, const CacheItemHelper* helper,
CreateContext* create_context,
Priority priority = Priority::LOW, bool wait = true,
Statistics* stats = nullptr) override {
return target_->Lookup(key, helper, create_context, priority, wait, stats);
}
bool Ref(Handle* handle) override { return target_->Ref(handle); }
using Cache::Release;
bool Release(Handle* handle, bool erase_if_last_ref = false) override {
return target_->Release(handle, erase_if_last_ref);
}
ObjectPtr Value(Handle* handle) override { return target_->Value(handle); }
void Erase(const Slice& key) override { target_->Erase(key); }
uint64_t NewId() override { return target_->NewId(); }
void SetCapacity(size_t capacity) override { target_->SetCapacity(capacity); }
void SetStrictCapacityLimit(bool strict_capacity_limit) override {
target_->SetStrictCapacityLimit(strict_capacity_limit);
}
bool HasStrictCapacityLimit() const override {
return target_->HasStrictCapacityLimit();
}
size_t GetCapacity() const override { return target_->GetCapacity(); }
size_t GetUsage() const override { return target_->GetUsage(); }
size_t GetUsage(Handle* handle) const override {
return target_->GetUsage(handle);
}
size_t GetPinnedUsage() const override { return target_->GetPinnedUsage(); }
size_t GetCharge(Handle* handle) const override {
return target_->GetCharge(handle);
}
const CacheItemHelper* GetCacheItemHelper(Handle* handle) const override {
return target_->GetCacheItemHelper(handle);
}
void ApplyToAllEntries(
const std::function<void(const Slice& key, ObjectPtr value, size_t charge,
const CacheItemHelper* helper)>& callback,
const ApplyToAllEntriesOptions& opts) override {
target_->ApplyToAllEntries(callback, opts);
}
void EraseUnRefEntries() override { target_->EraseUnRefEntries(); }
protected:
std::shared_ptr<Cache> target_;
};
// Useful for cache entries requiring no clean-up, such as for cache
// reservations
inline constexpr Cache::CacheItemHelper kNoopCacheItemHelper{};
} // namespace ROCKSDB_NAMESPACE
+4
View File
@@ -1001,6 +1001,10 @@ extern ROCKSDB_LIBRARY_API void rocksdb_block_based_options_set_no_block_cache(
extern ROCKSDB_LIBRARY_API void rocksdb_block_based_options_set_block_cache(
rocksdb_block_based_table_options_t* options, rocksdb_cache_t* block_cache);
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_block_cache_compressed(
rocksdb_block_based_table_options_t* options,
rocksdb_cache_t* block_cache_compressed);
extern ROCKSDB_LIBRARY_API void
rocksdb_block_based_options_set_whole_key_filtering(
rocksdb_block_based_table_options_t*, unsigned char);
extern ROCKSDB_LIBRARY_API void rocksdb_block_based_options_set_format_version(
+429 -3
View File
@@ -7,22 +7,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
//
// Various APIs for configuring, creating, and monitoring read caches.
// Various APIs for creating and customizing read caches in RocksDB.
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include "rocksdb/compression_type.h"
#include "rocksdb/data_structure.h"
#include "rocksdb/memory_allocator.h"
#include "rocksdb/slice.h"
#include "rocksdb/statistics.h"
#include "rocksdb/status.h"
namespace ROCKSDB_NAMESPACE {
class Cache; // defined in advanced_cache.h
class Cache;
struct ConfigOptions;
class Logger;
class SecondaryCache;
// Classifications of block cache entries.
@@ -360,4 +364,426 @@ extern std::shared_ptr<Cache> NewClockCache(
CacheMetadataChargePolicy metadata_charge_policy =
kDefaultCacheMetadataChargePolicy);
// A Cache maps keys to objects resident in memory, tracks reference counts
// on those key-object entries, and is able to remove unreferenced entries
// whenever it wants. All operations are fully thread safe except as noted.
// Inserted entries have a specified "charge" which is some quantity in
// unspecified units, typically bytes of memory used. A Cache will typically
// have a finite capacity in units of charge, and evict entries as needed
// to stay at or below that capacity.
//
// NOTE: This API is for expert use only and is more intended for providing
// custom implementations than for calling into. It is subject to change
// as RocksDB evolves, especially the RocksDB block cache.
//
// INTERNAL: See typed_cache.h for convenient wrappers on top of this API.
class Cache {
public: // types hidden from API client
// Opaque handle to an entry stored in the cache.
struct Handle {};
public: // types hidden from Cache implementation
// Pointer to cached object of unspecified type. (This type alias is
// provided for clarity, not really for type checking.)
using ObjectPtr = void*;
// Opaque object providing context (settings, etc.) to create objects
// for primary cache from saved (serialized) secondary cache entries.
struct CreateContext {};
public: // type defs
// Depending on implementation, cache entries with higher priority levels
// could be less likely to get evicted than entries with lower priority
// levels. The "high" priority level applies to certain SST metablocks (e.g.
// index and filter blocks) if the option
// cache_index_and_filter_blocks_with_high_priority is set. The "low" priority
// level is used for other kinds of SST blocks (most importantly, data
// blocks), as well as the above metablocks in case
// cache_index_and_filter_blocks_with_high_priority is
// not set. The "bottom" priority level is for BlobDB's blob values.
enum class Priority { HIGH, LOW, BOTTOM };
// A set of callbacks to allow objects in the primary block cache to be
// be persisted in a secondary cache. The purpose of the secondary cache
// is to support other ways of caching the object, such as persistent or
// compressed data, that may require the object to be parsed and transformed
// in some way. Since the primary cache holds C++ objects and the secondary
// cache may only hold flat data that doesn't need relocation, these
// callbacks need to be provided by the user of the block
// cache to do the conversion.
// The CacheItemHelper is passed to Insert() and Lookup(). It has pointers
// to callback functions for size, saving and deletion of the
// object. The callbacks are defined in C-style in order to make them
// stateless and not add to the cache metadata size.
// Saving multiple std::function objects will take up 32 bytes per
// function, even if its not bound to an object and does no capture.
//
// All the callbacks are C-style function pointers in order to simplify
// lifecycle management. Objects in the cache can outlive the parent DB,
// so anything required for these operations should be contained in the
// object itself.
//
// The SizeCallback takes a pointer to the object and returns the size
// of the persistable data. It can be used by the secondary cache to allocate
// memory if needed.
//
// RocksDB callbacks are NOT exception-safe. A callback completing with an
// exception can lead to undefined behavior in RocksDB, including data loss,
// unreported corruption, deadlocks, and more.
using SizeCallback = size_t (*)(ObjectPtr obj);
// The SaveToCallback takes an object pointer and saves the persistable
// data into a buffer. The secondary cache may decide to not store it in a
// contiguous buffer, in which case this callback will be called multiple
// times with increasing offset
using SaveToCallback = Status (*)(ObjectPtr from_obj, size_t from_offset,
size_t length, char* out_buf);
// A function pointer type for destruction of a cache object. This will
// typically call the destructor for the appropriate type of the object.
// The Cache is responsible for copying and reclaiming space for the key,
// but objects are managed in part using this callback. Generally a DeleterFn
// can be nullptr if the ObjectPtr does not need destruction (e.g. nullptr or
// pointer into static data).
using DeleterFn = void (*)(ObjectPtr obj, MemoryAllocator* allocator);
// The CreateCallback is takes in a buffer from the NVM cache and constructs
// an object using it. The callback doesn't have ownership of the buffer and
// should copy the contents into its own buffer. The CreateContext* is
// provided by Lookup and may be used to follow DB- or CF-specific settings.
// In case of some error, non-OK is returned and the caller should ignore
// any result in out_obj. (The implementation must clean up after itself.)
using CreateCallback = Status (*)(const Slice& data, CreateContext* context,
MemoryAllocator* allocator,
ObjectPtr* out_obj, size_t* out_charge);
// A struct with pointers to helper functions for spilling items from the
// cache into the secondary cache. May be extended in the future. An
// instance of this struct is expected to outlive the cache.
struct CacheItemHelper {
// Function for deleting an object on its removal from the Cache.
// nullptr is only for entries that require no destruction, such as
// "placeholder" cache entries with nullptr object.
DeleterFn del_cb; // (<- Most performance critical)
// Next three are used for persisting values as described above.
// If any is nullptr, then all three should be nullptr and persisting the
// entry to/from secondary cache is not supported.
SizeCallback size_cb;
SaveToCallback saveto_cb;
CreateCallback create_cb;
// Classification of the entry for monitoring purposes in block cache.
CacheEntryRole role;
constexpr CacheItemHelper()
: del_cb(nullptr),
size_cb(nullptr),
saveto_cb(nullptr),
create_cb(nullptr),
role(CacheEntryRole::kMisc) {}
explicit constexpr CacheItemHelper(CacheEntryRole _role,
DeleterFn _del_cb = nullptr,
SizeCallback _size_cb = nullptr,
SaveToCallback _saveto_cb = nullptr,
CreateCallback _create_cb = nullptr)
: del_cb(_del_cb),
size_cb(_size_cb),
saveto_cb(_saveto_cb),
create_cb(_create_cb),
role(_role) {
// Either all three secondary cache callbacks are non-nullptr or
// all three are nullptr
assert((size_cb != nullptr) == (saveto_cb != nullptr));
assert((size_cb != nullptr) == (create_cb != nullptr));
}
inline bool IsSecondaryCacheCompatible() const {
return size_cb != nullptr;
}
};
public: // ctor/dtor/create
Cache(std::shared_ptr<MemoryAllocator> allocator = nullptr)
: memory_allocator_(std::move(allocator)) {}
// No copying allowed
Cache(const Cache&) = delete;
Cache& operator=(const Cache&) = delete;
// Destroys all remaining entries by calling the associated "deleter"
virtual ~Cache() {}
// Creates a new Cache based on the input value string and returns the result.
// Currently, this method can be used to create LRUCaches only
// @param config_options
// @param value The value might be:
// - an old-style cache ("1M") -- equivalent to NewLRUCache(1024*102(
// - Name-value option pairs -- "capacity=1M; num_shard_bits=4;
// For the LRUCache, the values are defined in LRUCacheOptions.
// @param result The new Cache object
// @return OK if the cache was successfully created
// @return NotFound if an invalid name was specified in the value
// @return InvalidArgument if either the options were not valid
static Status CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<Cache>* result);
public: // functions
// The type of the Cache
virtual const char* Name() const = 0;
// The Insert and Lookup APIs below are intended to allow cached objects
// to be demoted/promoted between the primary block cache and a secondary
// cache. The secondary cache could be a non-volatile cache, and will
// likely store the object in a different representation. They rely on a
// per object CacheItemHelper to do the conversions.
// The secondary cache may persist across process and system restarts,
// and may even be moved between hosts. Therefore, the cache key must
// be repeatable across restarts/reboots, and globally unique if
// multiple DBs share the same cache and the set of DBs can change
// over time.
// Insert a mapping from key->object into the cache and assign it
// the specified charge against the total cache capacity. If
// strict_capacity_limit is true and cache reaches its full capacity,
// return Status::MemoryLimit. `obj` must be non-nullptr if compatible
// with secondary cache (helper->size_cb != nullptr), because Value() ==
// nullptr is reserved for indicating some secondary cache failure cases.
// On success, returns OK and takes ownership of `obj`, eventually deleting
// it with helper->del_cb. On non-OK return, the caller maintains ownership
// of `obj` so will often need to delete it in such cases.
//
// The helper argument is saved by the cache and will be used when the
// inserted object is evicted or considered for promotion to the secondary
// cache. Promotion to secondary cache is only enabled if helper->size_cb
// != nullptr. The helper must outlive the cache. Callers may use
// &kNoopCacheItemHelper as a trivial helper (no deleter for the object,
// no secondary cache). `helper` must not be nullptr (efficiency).
//
// If `handle` is not nullptr and return status is OK, `handle` is set
// to a Handle* for the entry. The caller must call this->Release(handle)
// when the returned entry is no longer needed. If `handle` is nullptr, it is
// as if Release is called immediately after Insert.
//
// Regardless of whether the item was inserted into the cache,
// it will attempt to insert it into the secondary cache if one is
// configured, and the helper supports it.
// The cache implementation must support a secondary cache, otherwise
// the item is only inserted into the primary cache. It may
// defer the insertion to the secondary cache as it sees fit.
//
// When the inserted entry is no longer needed, it will be destroyed using
// helper->del_cb (if non-nullptr).
virtual Status Insert(const Slice& key, ObjectPtr obj,
const CacheItemHelper* helper, size_t charge,
Handle** handle = nullptr,
Priority priority = Priority::LOW) = 0;
// Lookup the key, returning nullptr if not found. If found, returns
// a handle to the mapping that must eventually be passed to Release().
//
// If a non-nullptr helper argument is provided with a non-nullptr
// create_cb, and a secondary cache is configured, then the secondary
// cache is also queried if lookup in the primary cache fails. If found
// in secondary cache, the provided create_db and create_context are
// used to promote the entry to an object in the primary cache.
// In that case, the helper may be saved and used later when the object
// is evicted, so as usual, the pointed-to helper must outlive the cache.
//
// ======================== Async Lookup (wait=false) ======================
// When wait=false, the handle returned might be in any of three states:
// * Present - If Value() != nullptr, then the result is present and
// the handle can be used just as if wait=true.
// * Pending, not ready (IsReady() == false) - secondary cache is still
// working to retrieve the value. Might become ready any time.
// * Pending, ready (IsReady() == true) - secondary cache has the value
// but it has not been loaded as an object into primary cache. Call to
// Wait()/WaitAll() will not block.
//
// IMPORTANT: Pending handles are not thread-safe, and only these functions
// are allowed on them: Value(), IsReady(), Wait(), WaitAll(). Even Release()
// can only come after Wait() or WaitAll() even though a reference is held.
//
// Only Wait()/WaitAll() gets a Handle out of a Pending state. (Waiting is
// safe and has no effect on other handle states.) After waiting on a Handle,
// it is in one of two states:
// * Present - if Value() != nullptr
// * Failed - if Value() == nullptr, such as if the secondary cache
// initially thought it had the value but actually did not.
//
// Note that given an arbitrary Handle, the only way to distinguish the
// Pending+ready state from the Failed state is to Wait() on it. A cache
// entry not compatible with secondary cache can also have Value()==nullptr
// like the Failed state, but this is not generally a concern.
virtual Handle* Lookup(const Slice& key,
const CacheItemHelper* helper = nullptr,
CreateContext* create_context = nullptr,
Priority priority = Priority::LOW, bool wait = true,
Statistics* stats = nullptr) = 0;
// Convenience wrapper when secondary cache not supported
inline Handle* BasicLookup(const Slice& key, Statistics* stats) {
return Lookup(key, nullptr, nullptr, Priority::LOW, true, stats);
}
// Increments the reference count for the handle if it refers to an entry in
// the cache. Returns true if refcount was incremented; otherwise, returns
// false.
// REQUIRES: handle must have been returned by a method on *this.
virtual bool Ref(Handle* handle) = 0;
/**
* Release a mapping returned by a previous Lookup(). A released entry might
* still remain in cache in case it is later looked up by others. If
* erase_if_last_ref is set then it also erases it from the cache if there is
* no other reference to it. Erasing it should call the deleter function that
* was provided when the entry was inserted.
*
* Returns true if the entry was also erased.
*/
// REQUIRES: handle must not have been released yet.
// REQUIRES: handle must have been returned by a method on *this.
virtual bool Release(Handle* handle, bool erase_if_last_ref = false) = 0;
// Return the object assiciated with a handle returned by a successful
// Lookup(). For historical reasons, this is also known at the "value"
// associated with the key.
// REQUIRES: handle must not have been released yet.
// REQUIRES: handle must have been returned by a method on *this.
virtual ObjectPtr Value(Handle* handle) = 0;
// If the cache contains the entry for the key, erase it. Note that the
// underlying entry will be kept around until all existing handles
// to it have been released.
virtual void Erase(const Slice& key) = 0;
// Return a new numeric id. May be used by multiple clients who are
// sharding the same cache to partition the key space. Typically the
// client will allocate a new id at startup and prepend the id to
// its cache keys.
virtual uint64_t NewId() = 0;
// sets the maximum configured capacity of the cache. When the new
// capacity is less than the old capacity and the existing usage is
// greater than new capacity, the implementation will do its best job to
// purge the released entries from the cache in order to lower the usage
virtual void SetCapacity(size_t capacity) = 0;
// Set whether to return error on insertion when cache reaches its full
// capacity.
virtual void SetStrictCapacityLimit(bool strict_capacity_limit) = 0;
// Get the flag whether to return error on insertion when cache reaches its
// full capacity.
virtual bool HasStrictCapacityLimit() const = 0;
// Returns the maximum configured capacity of the cache
virtual size_t GetCapacity() const = 0;
// Returns the memory size for the entries residing in the cache.
virtual size_t GetUsage() const = 0;
// Returns the number of entries currently tracked in the table. SIZE_MAX
// means "not supported." This is used for inspecting the load factor, along
// with GetTableAddressCount().
virtual size_t GetOccupancyCount() const { return SIZE_MAX; }
// Returns the number of ways the hash function is divided for addressing
// entries. Zero means "not supported." This is used for inspecting the load
// factor, along with GetOccupancyCount().
virtual size_t GetTableAddressCount() const { return 0; }
// Returns the memory size for a specific entry in the cache.
virtual size_t GetUsage(Handle* handle) const = 0;
// Returns the memory size for the entries in use by the system
virtual size_t GetPinnedUsage() const = 0;
// Returns the charge for the specific entry in the cache.
virtual size_t GetCharge(Handle* handle) const = 0;
// Returns the helper for the specified entry.
virtual const CacheItemHelper* GetCacheItemHelper(Handle* handle) const = 0;
// Call this on shutdown if you want to speed it up. Cache will disown
// any underlying data and will not free it on delete. This call will leak
// memory - call this only if you're shutting down the process.
// Any attempts of using cache after this call will fail terribly.
// Always delete the DB object before calling this method!
virtual void DisownData() {
// default implementation is noop
}
struct ApplyToAllEntriesOptions {
// If the Cache uses locks, setting `average_entries_per_lock` to
// a higher value suggests iterating over more entries each time a lock
// is acquired, likely reducing the time for ApplyToAllEntries but
// increasing latency for concurrent users of the Cache. Setting
// `average_entries_per_lock` to a smaller value could be helpful if
// callback is relatively expensive, such as using large data structures.
size_t average_entries_per_lock = 256;
};
// Apply a callback to all entries in the cache. The Cache must ensure
// thread safety but does not guarantee that a consistent snapshot of all
// entries is iterated over if other threads are operating on the Cache
// also.
virtual void ApplyToAllEntries(
const std::function<void(const Slice& key, ObjectPtr obj, size_t charge,
const CacheItemHelper* helper)>& callback,
const ApplyToAllEntriesOptions& opts) = 0;
// Remove all entries.
// Prerequisite: no entry is referenced.
virtual void EraseUnRefEntries() = 0;
virtual std::string GetPrintableOptions() const { return ""; }
// Check for any warnings or errors in the operation of the cache and
// report them to the logger. This is intended only to be called
// periodically so does not need to be very efficient. (Obscure calling
// conventions for Logger inherited from env.h)
virtual void ReportProblems(
const std::shared_ptr<Logger>& /*info_log*/) const {}
MemoryAllocator* memory_allocator() const { return memory_allocator_.get(); }
// EXPERIMENTAL
// The following APIs are experimental and might change in the future.
// Release a mapping returned by a previous Lookup(). The "useful"
// parameter specifies whether the data was actually used or not,
// which may be used by the cache implementation to decide whether
// to consider it as a hit for retention purposes. As noted elsewhere,
// "pending" handles require Wait()/WaitAll() before Release().
virtual bool Release(Handle* handle, bool /*useful*/,
bool erase_if_last_ref) {
return Release(handle, erase_if_last_ref);
}
// Determines if the handle returned by Lookup() can give a value without
// blocking, though Wait()/WaitAll() might be required to publish it to
// Value(). See secondary cache compatible Lookup() above for details.
// This call is not thread safe on "pending" handles.
virtual bool IsReady(Handle* /*handle*/) { return true; }
// Convert a "pending" handle into a full thread-shareable handle by
// * If necessary, wait until secondary cache finishes loading the value.
// * Construct the object for primary cache and set it in the handle.
// Even after Wait() on a pending handle, the caller must check for
// Value() == nullptr in case of failure. This call is not thread-safe
// on pending handles. This call has no effect on non-pending handles.
// See secondary cache compatible Lookup() above for details.
virtual void Wait(Handle* /*handle*/) {}
// Wait for a vector of handles to become ready. As with Wait(), the user
// should check the Value() of each handle for nullptr. This call is not
// thread-safe on pending handles.
virtual void WaitAll(std::vector<Handle*>& /*handles*/) {}
private:
std::shared_ptr<MemoryAllocator> memory_allocator_;
};
// Useful for cache entries requiring no clean-up, such as for cache
// reservations
inline constexpr Cache::CacheItemHelper kNoopCacheItemHelper{};
} // namespace ROCKSDB_NAMESPACE
+1 -1
View File
@@ -9,7 +9,7 @@
#include <memory>
#include <string>
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/customizable.h"
#include "rocksdb/slice.h"
#include "rocksdb/statistics.h"
+62 -17
View File
@@ -19,14 +19,13 @@
namespace ROCKSDB_NAMESPACE {
/**
* Keep adding tickers here. Note that the C++ enum values, unlike the values in
* the Java bindings, are not guaranteed to be stable; also, the C++ and Java
* values for any given ticker are not guaranteed to match.
* 1. Add the new ticker before TICKER_ENUM_MAX.
* Keep adding tickers here.
* 1. Any ticker should be added immediately before TICKER_ENUM_MAX, taking
* over its old value.
* 2. Add a readable string in TickersNameMap below for the newly added ticker.
* 3. Add a corresponding enum value to TickerType.java in the Java API.
* 4. Add the enum conversions from/to Java/C++ to portal.h's toJavaTickerType
* and toCppTickers.
* 3. Add a corresponding enum value to TickerType.java in the java API
* 4. Add the enum conversions from Java and C++ to portal.h's toJavaTickerType
* and toCppTickers
*/
enum Tickers : uint32_t {
// total block cache misses
@@ -51,6 +50,8 @@ enum Tickers : uint32_t {
BLOCK_CACHE_INDEX_ADD,
// # of bytes of index blocks inserted into cache
BLOCK_CACHE_INDEX_BYTES_INSERT,
// # of bytes of index block erased from cache
BLOCK_CACHE_INDEX_BYTES_EVICT,
// # of times cache miss when accessing filter block from block cache.
BLOCK_CACHE_FILTER_MISS,
// # of times cache hit when accessing filter block from block cache.
@@ -59,6 +60,8 @@ enum Tickers : uint32_t {
BLOCK_CACHE_FILTER_ADD,
// # of bytes of bloom filter blocks inserted into cache
BLOCK_CACHE_FILTER_BYTES_INSERT,
// # of bytes of bloom filter block erased from cache
BLOCK_CACHE_FILTER_BYTES_EVICT,
// # of times cache miss when accessing data block from block cache.
BLOCK_CACHE_DATA_MISS,
// # of times cache hit when accessing data block from block cache.
@@ -80,6 +83,8 @@ enum Tickers : uint32_t {
// exist.
BLOOM_FILTER_FULL_TRUE_POSITIVE,
BLOOM_FILTER_MICROS,
// # persistent cache hit
PERSISTENT_CACHE_HIT,
// # persistent cache miss
@@ -142,19 +147,32 @@ enum Tickers : uint32_t {
// The number of uncompressed bytes read from an iterator.
// Includes size of key and value.
ITER_BYTES_READ,
NO_FILE_CLOSES,
NO_FILE_OPENS,
NO_FILE_ERRORS,
// DEPRECATED Time system had to wait to do LO-L1 compactions
STALL_L0_SLOWDOWN_MICROS,
// DEPRECATED Time system had to wait to move memtable to L1.
STALL_MEMTABLE_COMPACTION_MICROS,
// DEPRECATED write throttle because of too many files in L0
STALL_L0_NUM_FILES_MICROS,
// Writer has to wait for compaction or flush to finish.
STALL_MICROS,
// The wait time for db mutex.
// Disabled by default. To enable it set stats level to kAll
DB_MUTEX_WAIT_MICROS,
RATE_LIMIT_DELAY_MILLIS,
// DEPRECATED number of iterators currently open
NO_ITERATORS,
// Number of MultiGet calls, keys read, and bytes read
NUMBER_MULTIGET_CALLS,
NUMBER_MULTIGET_KEYS_READ,
NUMBER_MULTIGET_BYTES_READ,
// Number of deletes records that were not required to be
// written to storage because key does not exist
NUMBER_FILTERED_DELETES,
NUMBER_MERGE_FAILURES,
// number of times bloom was checked before creating iterator on a
@@ -170,6 +188,12 @@ enum Tickers : uint32_t {
// Record the number of calls to GetUpdatesSince. Useful to keep track of
// transaction log iterator refreshes
GET_UPDATES_SINCE_CALLS,
BLOCK_CACHE_COMPRESSED_MISS, // miss in the compressed block cache
BLOCK_CACHE_COMPRESSED_HIT, // hit in the compressed block cache
// Number of blocks added to compressed block cache
BLOCK_CACHE_COMPRESSED_ADD,
// Number of failures when adding blocks to compressed block cache
BLOCK_CACHE_COMPRESSED_ADD_FAILURES,
WAL_FILE_SYNCED, // Number of times WAL sync is done
WAL_FILE_BYTES, // Number of bytes written to WAL
@@ -177,6 +201,7 @@ enum Tickers : uint32_t {
// head of the writers queue.
WRITE_DONE_BY_SELF,
WRITE_DONE_BY_OTHER, // Equivalent to writes done for others
WRITE_TIMEDOUT, // Number of writes ending up with timed-out.
WRITE_WITH_WAL, // Number of Write calls that request WAL
COMPACT_READ_BYTES, // Bytes read during compaction
COMPACT_WRITE_BYTES, // Bytes written during compaction
@@ -287,8 +312,20 @@ enum Tickers : uint32_t {
BLOB_DB_GC_NUM_NEW_FILES,
// # of BlobDB garbage collection failures. Only applicable to legacy BlobDB.
BLOB_DB_GC_FAILURES,
// # of keys dropped by BlobDB garbage collection because they had been
// overwritten. DEPRECATED.
BLOB_DB_GC_NUM_KEYS_OVERWRITTEN,
// # of keys dropped by BlobDB garbage collection because of expiration.
// DEPRECATED.
BLOB_DB_GC_NUM_KEYS_EXPIRED,
// # of keys relocated to new blob file by garbage collection.
BLOB_DB_GC_NUM_KEYS_RELOCATED,
// # of bytes dropped by BlobDB garbage collection because they had been
// overwritten. DEPRECATED.
BLOB_DB_GC_BYTES_OVERWRITTEN,
// # of bytes dropped by BlobDB garbage collection because of expiration.
// DEPRECATED.
BLOB_DB_GC_BYTES_EXPIRED,
// # of bytes relocated to new blob file by garbage collection.
BLOB_DB_GC_BYTES_RELOCATED,
// # of blob files evicted because of BlobDB is full. Only applicable to
@@ -326,6 +363,7 @@ enum Tickers : uint32_t {
BLOCK_CACHE_COMPRESSION_DICT_HIT,
BLOCK_CACHE_COMPRESSION_DICT_ADD,
BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT,
BLOCK_CACHE_COMPRESSION_DICT_BYTES_EVICT,
// # of blocks redundantly inserted into block cache.
// REQUIRES: BLOCK_CACHE_ADD_REDUNDANT <= BLOCK_CACHE_ADD
@@ -423,15 +461,12 @@ enum Tickers : uint32_t {
extern const std::vector<std::pair<Tickers, std::string>> TickersNameMap;
/**
* Keep adding histograms here. Note that the C++ enum values, unlike the values
* in the Java bindings, are not guaranteed to be stable; also, the C++ and Java
* values for any given histogram are not guaranteed to match.
* 1. Add the new histogram before HISTOGRAM_ENUM_MAX.
* 2. Add a readable string in HistogramsNameMap below for the newly added
* histogram.
* 3. Add a corresponding enum value to HistogramType.java in the Java API.
* 4. Add the enum conversions from/to Java/C++ to portal.h's
* toJavaHistogramsType and toCppHistograms.
* Keep adding histogram's here.
* Any histogram should have value less than HISTOGRAM_ENUM_MAX
* Add a new Histogram by assigning it the current value of HISTOGRAM_ENUM_MAX
* Add a string representation in HistogramsNameMap below
* And increment HISTOGRAM_ENUM_MAX
* Add a corresponding enum value to HistogramType.java in the java API
*/
enum Histograms : uint32_t {
DB_GET = 0,
@@ -449,6 +484,11 @@ enum Histograms : uint32_t {
READ_BLOCK_COMPACTION_MICROS,
READ_BLOCK_GET_MICROS,
WRITE_RAW_BLOCK_MICROS,
STALL_L0_SLOWDOWN_COUNT,
STALL_MEMTABLE_COMPACTION_COUNT,
STALL_L0_NUM_FILES_COUNT,
HARD_RATE_LIMIT_DELAY_COUNT,
SOFT_RATE_LIMIT_DELAY_COUNT,
NUM_FILES_IN_SINGLE_COMPACTION,
DB_SEEK,
WRITE_STALL,
@@ -495,6 +535,8 @@ enum Histograms : uint32_t {
BLOB_DB_BLOB_FILE_READ_MICROS,
// Blob file sync latency.
BLOB_DB_BLOB_FILE_SYNC_MICROS,
// BlobDB garbage collection time. DEPRECATED.
BLOB_DB_GC_MICROS,
// BlobDB compression time.
BLOB_DB_COMPRESSION_MICROS,
// BlobDB decompression time.
@@ -506,6 +548,9 @@ enum Histograms : uint32_t {
// MultiGet stats logged per level
// Num of index and filter blocks read from file system per level.
NUM_INDEX_AND_FILTER_BLOCKS_READ_PER_LEVEL,
// Num of data blocks read from file system per level.
// Obsolete
NUM_DATA_BLOCKS_READ_PER_LEVEL,
// Num of sst files read from file system per level.
NUM_SST_READ_PER_LEVEL,
@@ -528,7 +573,7 @@ enum Histograms : uint32_t {
// Wait time for aborting async read in FilePrefetchBuffer destructor
ASYNC_PREFETCH_ABORT_MICROS,
HISTOGRAM_ENUM_MAX
HISTOGRAM_ENUM_MAX,
};
extern const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap;
+9
View File
@@ -266,6 +266,15 @@ struct BlockBasedTableOptions {
// IF NULL, no page cache is used
std::shared_ptr<PersistentCache> persistent_cache = nullptr;
// DEPRECATED: This feature is planned for removal in a future release.
// Use SecondaryCache instead.
//
// If non-NULL use the specified cache for compressed blocks.
// If NULL, rocksdb will not use a compressed block cache.
// Note: though it looks similar to `block_cache`, RocksDB doesn't put the
// same type of object there.
std::shared_ptr<Cache> block_cache_compressed = nullptr;
// Approximate size of user data packed per block. Note that the
// block size specified here corresponds to uncompressed data. The
// actual size of the unit read from disk may be smaller if
+27 -5
View File
@@ -49,12 +49,15 @@ struct ConfigOptions;
// casting the return value of TableFactory::GetOptions() to
// BlockBasedTableOptions and making necessary changes.
//
// config_options contains a set of options that controls the processing
// of the options.
// ignore_unknown_options can be set to true if you want to ignore options
// that are from a newer version of the db, essentially for forward
// compatibility.
//
// config_options.ignore_unknown_options can be set to true if you want to
// ignore options that are from a newer version of the db, essentially for
// forward compatibility.
// config_options contains a set of options that controls the processing
// of the options. The LoadLatestOptions(ConfigOptions...) should be preferred;
// the alternative signature may be deprecated in a future release. The
// equivalent functionality can be achieved by setting the corresponding options
// in the ConfigOptions parameter.
//
// examples/options_file_example.cc demonstrates how to use this function
// to open a RocksDB instance.
@@ -66,6 +69,11 @@ struct ConfigOptions;
// to the options file itself.
//
// @see LoadOptionsFromFile
Status LoadLatestOptions(const std::string& dbpath, Env* env,
DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
bool ignore_unknown_options = false,
std::shared_ptr<Cache>* cache = {});
Status LoadLatestOptions(const ConfigOptions& config_options,
const std::string& dbpath, DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
@@ -74,7 +82,17 @@ Status LoadLatestOptions(const ConfigOptions& config_options,
// Similar to LoadLatestOptions, this function constructs the DBOptions
// and ColumnFamilyDescriptors based on the specified RocksDB Options file.
//
// The LoadOptionsFile(ConfigOptions...) should be preferred;
// the alternative signature may be deprecated in a future release. The
// equivalent functionality can be achieved by setting the corresponding
// options in the ConfigOptions parameter.
//
// @see LoadLatestOptions
Status LoadOptionsFromFile(const std::string& options_file_name, Env* env,
DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
bool ignore_unknown_options = false,
std::shared_ptr<Cache>* cache = {});
Status LoadOptionsFromFile(const ConfigOptions& config_options,
const std::string& options_file_name,
DBOptions* db_options,
@@ -96,6 +114,10 @@ Status GetLatestOptionsFileName(const std::string& dbpath, Env* env,
// * prefix_extractor
// * table_factory
// * merge_operator
Status CheckOptionsCompatibility(
const std::string& dbpath, Env* env, const DBOptions& db_options,
const std::vector<ColumnFamilyDescriptor>& cf_descs,
bool ignore_unknown_options = false);
Status CheckOptionsCompatibility(
const ConfigOptions& config_options, const std::string& dbpath,
const DBOptions& db_options,
+7 -4
View File
@@ -10,7 +10,7 @@
#include <memory>
#include <string>
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/env.h"
#include "rocksdb/slice.h"
#include "rocksdb/statistics.h"
@@ -42,10 +42,13 @@ extern std::shared_ptr<SimCache> NewSimCache(std::shared_ptr<Cache> sim_cache,
std::shared_ptr<Cache> cache,
int num_shard_bits);
// An abstract base class (public interface) to the SimCache implementation
class SimCache : public CacheWrapper {
class SimCache : public Cache {
public:
using CacheWrapper::CacheWrapper;
SimCache() {}
~SimCache() override {}
const char* Name() const override { return "SimCache"; }
// returns the maximum configured capacity of the simcache for simulation
virtual size_t GetSimCapacity() const = 0;
+2 -1
View File
@@ -6,10 +6,11 @@
// This file implements the "bridge" between Java and C++ for
// ROCKSDB_NAMESPACE::Cache.
#include "rocksdb/cache.h"
#include <jni.h>
#include "include/org_rocksdb_Cache.h"
#include "rocksdb/advanced_cache.h"
/*
* Class: org_rocksdb_Cache
-13
View File
@@ -36,19 +36,6 @@ jlong Java_org_rocksdb_ConfigOptions_newConfigOptions(JNIEnv *, jclass) {
return GET_CPLUSPLUS_POINTER(cfg_opt);
}
/*
* Class: org_rocksdb_ConfigOptions
* Method: setEnv
* Signature: (JJ;)V
*/
void Java_org_rocksdb_ConfigOptions_setEnv(JNIEnv *, jclass, jlong handle,
jlong rocksdb_env_handle) {
auto *cfg_opt = reinterpret_cast<ROCKSDB_NAMESPACE::ConfigOptions *>(handle);
auto *rocksdb_env =
reinterpret_cast<ROCKSDB_NAMESPACE::Env *>(rocksdb_env_handle);
cfg_opt->env = rocksdb_env;
}
/*
* Class: org_rocksdb_ConfigOptions
* Method: setDelimiter
+58 -2
View File
@@ -54,9 +54,37 @@ void build_column_family_descriptor_list(
/*
* Class: org_rocksdb_OptionsUtil
* Method: loadLatestOptions
* Signature: (Ljava/lang/String;JLjava/util/List;Z)V
*/
void Java_org_rocksdb_OptionsUtil_loadLatestOptions__Ljava_lang_String_2JJLjava_util_List_2Z(
JNIEnv* env, jclass /*jcls*/, jstring jdbpath, jlong jenv_handle,
jlong jdb_opts_handle, jobject jcfds, jboolean ignore_unknown_options) {
jboolean has_exception = JNI_FALSE;
auto db_path =
ROCKSDB_NAMESPACE::JniUtil::copyStdString(env, jdbpath, &has_exception);
if (has_exception == JNI_TRUE) {
// exception occurred
return;
}
std::vector<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor> cf_descs;
ROCKSDB_NAMESPACE::Status s = ROCKSDB_NAMESPACE::LoadLatestOptions(
db_path, reinterpret_cast<ROCKSDB_NAMESPACE::Env*>(jenv_handle),
reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions*>(jdb_opts_handle),
&cf_descs, ignore_unknown_options);
if (!s.ok()) {
// error, raise an exception
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
} else {
build_column_family_descriptor_list(env, jcfds, cf_descs);
}
}
/*
* Class: org_rocksdb_OptionsUtil
* Method: loadLatestOptions_1
* Signature: (JLjava/lang/String;JLjava/util/List;)V
*/
void Java_org_rocksdb_OptionsUtil_loadLatestOptions(
void Java_org_rocksdb_OptionsUtil_loadLatestOptions__JLjava_lang_String_2JLjava_util_List_2(
JNIEnv* env, jclass /*jcls*/, jlong cfg_handle, jstring jdbpath,
jlong jdb_opts_handle, jobject jcfds) {
jboolean has_exception = JNI_FALSE;
@@ -81,12 +109,40 @@ void Java_org_rocksdb_OptionsUtil_loadLatestOptions(
}
}
/*
* Class: org_rocksdb_OptionsUtil
* Method: loadOptionsFromFile
* Signature: (Ljava/lang/String;JJLjava/util/List;Z)V
*/
void Java_org_rocksdb_OptionsUtil_loadOptionsFromFile__Ljava_lang_String_2JJLjava_util_List_2Z(
JNIEnv* env, jclass /*jcls*/, jstring jopts_file_name, jlong jenv_handle,
jlong jdb_opts_handle, jobject jcfds, jboolean ignore_unknown_options) {
jboolean has_exception = JNI_FALSE;
auto opts_file_name = ROCKSDB_NAMESPACE::JniUtil::copyStdString(
env, jopts_file_name, &has_exception);
if (has_exception == JNI_TRUE) {
// exception occurred
return;
}
std::vector<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor> cf_descs;
ROCKSDB_NAMESPACE::Status s = ROCKSDB_NAMESPACE::LoadOptionsFromFile(
opts_file_name, reinterpret_cast<ROCKSDB_NAMESPACE::Env*>(jenv_handle),
reinterpret_cast<ROCKSDB_NAMESPACE::DBOptions*>(jdb_opts_handle),
&cf_descs, ignore_unknown_options);
if (!s.ok()) {
// error, raise an exception
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s);
} else {
build_column_family_descriptor_list(env, jcfds, cf_descs);
}
}
/*
* Class: org_rocksdb_OptionsUtil
* Method: loadOptionsFromFile
* Signature: (JLjava/lang/String;JLjava/util/List;)V
*/
void Java_org_rocksdb_OptionsUtil_loadOptionsFromFile(
void Java_org_rocksdb_OptionsUtil_loadOptionsFromFile__JLjava_lang_String_2JLjava_util_List_2(
JNIEnv* env, jclass /*jcls*/, jlong cfg_handle, jstring jopts_file_name,
jlong jdb_opts_handle, jobject jcfds) {
jboolean has_exception = JNI_FALSE;
+100
View File
@@ -4806,6 +4806,8 @@ class TickerTypeJni {
return 0x6;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_INDEX_BYTES_INSERT:
return 0x7;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_INDEX_BYTES_EVICT:
return 0x8;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_MISS:
return 0x9;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_HIT:
@@ -4814,6 +4816,8 @@ class TickerTypeJni {
return 0xB;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_BYTES_INSERT:
return 0xC;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_BYTES_EVICT:
return 0xD;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_DATA_MISS:
return 0xE;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_DATA_HIT:
@@ -4880,20 +4884,34 @@ class TickerTypeJni {
return 0x2D;
case ROCKSDB_NAMESPACE::Tickers::ITER_BYTES_READ:
return 0x2E;
case ROCKSDB_NAMESPACE::Tickers::NO_FILE_CLOSES:
return 0x2F;
case ROCKSDB_NAMESPACE::Tickers::NO_FILE_OPENS:
return 0x30;
case ROCKSDB_NAMESPACE::Tickers::NO_FILE_ERRORS:
return 0x31;
case ROCKSDB_NAMESPACE::Tickers::STALL_L0_SLOWDOWN_MICROS:
return 0x32;
case ROCKSDB_NAMESPACE::Tickers::STALL_MEMTABLE_COMPACTION_MICROS:
return 0x33;
case ROCKSDB_NAMESPACE::Tickers::STALL_L0_NUM_FILES_MICROS:
return 0x34;
case ROCKSDB_NAMESPACE::Tickers::STALL_MICROS:
return 0x35;
case ROCKSDB_NAMESPACE::Tickers::DB_MUTEX_WAIT_MICROS:
return 0x36;
case ROCKSDB_NAMESPACE::Tickers::RATE_LIMIT_DELAY_MILLIS:
return 0x37;
case ROCKSDB_NAMESPACE::Tickers::NO_ITERATORS:
return 0x38;
case ROCKSDB_NAMESPACE::Tickers::NUMBER_MULTIGET_CALLS:
return 0x39;
case ROCKSDB_NAMESPACE::Tickers::NUMBER_MULTIGET_KEYS_READ:
return 0x3A;
case ROCKSDB_NAMESPACE::Tickers::NUMBER_MULTIGET_BYTES_READ:
return 0x3B;
case ROCKSDB_NAMESPACE::Tickers::NUMBER_FILTERED_DELETES:
return 0x3C;
case ROCKSDB_NAMESPACE::Tickers::NUMBER_MERGE_FAILURES:
return 0x3D;
case ROCKSDB_NAMESPACE::Tickers::BLOOM_FILTER_PREFIX_CHECKED:
@@ -4904,6 +4922,14 @@ class TickerTypeJni {
return 0x40;
case ROCKSDB_NAMESPACE::Tickers::GET_UPDATES_SINCE_CALLS:
return 0x41;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_MISS:
return 0x42;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_HIT:
return 0x43;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_ADD:
return 0x44;
case ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_ADD_FAILURES:
return 0x45;
case ROCKSDB_NAMESPACE::Tickers::WAL_FILE_SYNCED:
return 0x46;
case ROCKSDB_NAMESPACE::Tickers::WAL_FILE_BYTES:
@@ -4912,6 +4938,8 @@ class TickerTypeJni {
return 0x48;
case ROCKSDB_NAMESPACE::Tickers::WRITE_DONE_BY_OTHER:
return 0x49;
case ROCKSDB_NAMESPACE::Tickers::WRITE_TIMEDOUT:
return 0x4A;
case ROCKSDB_NAMESPACE::Tickers::WRITE_WITH_WAL:
return 0x4B;
case ROCKSDB_NAMESPACE::Tickers::COMPACT_READ_BYTES:
@@ -5015,8 +5043,16 @@ class TickerTypeJni {
return 0x7C;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_FAILURES:
return 0x7D;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_KEYS_OVERWRITTEN:
return 0x7E;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_KEYS_EXPIRED:
return 0x7F;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_KEYS_RELOCATED:
return -0x02;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_BYTES_OVERWRITTEN:
return -0x03;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_BYTES_EXPIRED:
return -0x04;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_BYTES_RELOCATED:
return -0x05;
case ROCKSDB_NAMESPACE::Tickers::BLOB_DB_FIFO_NUM_FILES_EVICTED:
@@ -5155,6 +5191,8 @@ class TickerTypeJni {
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_INDEX_ADD;
case 0x7:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_INDEX_BYTES_INSERT;
case 0x8:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_INDEX_BYTES_EVICT;
case 0x9:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_MISS;
case 0xA:
@@ -5163,6 +5201,8 @@ class TickerTypeJni {
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_ADD;
case 0xC:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_BYTES_INSERT;
case 0xD:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_FILTER_BYTES_EVICT;
case 0xE:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_DATA_MISS;
case 0xF:
@@ -5229,20 +5269,34 @@ class TickerTypeJni {
return ROCKSDB_NAMESPACE::Tickers::NUMBER_DB_PREV_FOUND;
case 0x2E:
return ROCKSDB_NAMESPACE::Tickers::ITER_BYTES_READ;
case 0x2F:
return ROCKSDB_NAMESPACE::Tickers::NO_FILE_CLOSES;
case 0x30:
return ROCKSDB_NAMESPACE::Tickers::NO_FILE_OPENS;
case 0x31:
return ROCKSDB_NAMESPACE::Tickers::NO_FILE_ERRORS;
case 0x32:
return ROCKSDB_NAMESPACE::Tickers::STALL_L0_SLOWDOWN_MICROS;
case 0x33:
return ROCKSDB_NAMESPACE::Tickers::STALL_MEMTABLE_COMPACTION_MICROS;
case 0x34:
return ROCKSDB_NAMESPACE::Tickers::STALL_L0_NUM_FILES_MICROS;
case 0x35:
return ROCKSDB_NAMESPACE::Tickers::STALL_MICROS;
case 0x36:
return ROCKSDB_NAMESPACE::Tickers::DB_MUTEX_WAIT_MICROS;
case 0x37:
return ROCKSDB_NAMESPACE::Tickers::RATE_LIMIT_DELAY_MILLIS;
case 0x38:
return ROCKSDB_NAMESPACE::Tickers::NO_ITERATORS;
case 0x39:
return ROCKSDB_NAMESPACE::Tickers::NUMBER_MULTIGET_CALLS;
case 0x3A:
return ROCKSDB_NAMESPACE::Tickers::NUMBER_MULTIGET_KEYS_READ;
case 0x3B:
return ROCKSDB_NAMESPACE::Tickers::NUMBER_MULTIGET_BYTES_READ;
case 0x3C:
return ROCKSDB_NAMESPACE::Tickers::NUMBER_FILTERED_DELETES;
case 0x3D:
return ROCKSDB_NAMESPACE::Tickers::NUMBER_MERGE_FAILURES;
case 0x3E:
@@ -5253,6 +5307,14 @@ class TickerTypeJni {
return ROCKSDB_NAMESPACE::Tickers::NUMBER_OF_RESEEKS_IN_ITERATION;
case 0x41:
return ROCKSDB_NAMESPACE::Tickers::GET_UPDATES_SINCE_CALLS;
case 0x42:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_MISS;
case 0x43:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_HIT;
case 0x44:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_ADD;
case 0x45:
return ROCKSDB_NAMESPACE::Tickers::BLOCK_CACHE_COMPRESSED_ADD_FAILURES;
case 0x46:
return ROCKSDB_NAMESPACE::Tickers::WAL_FILE_SYNCED;
case 0x47:
@@ -5261,6 +5323,8 @@ class TickerTypeJni {
return ROCKSDB_NAMESPACE::Tickers::WRITE_DONE_BY_SELF;
case 0x49:
return ROCKSDB_NAMESPACE::Tickers::WRITE_DONE_BY_OTHER;
case 0x4A:
return ROCKSDB_NAMESPACE::Tickers::WRITE_TIMEDOUT;
case 0x4B:
return ROCKSDB_NAMESPACE::Tickers::WRITE_WITH_WAL;
case 0x4C:
@@ -5365,8 +5429,16 @@ class TickerTypeJni {
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_NEW_FILES;
case 0x7D:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_FAILURES;
case 0x7E:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_KEYS_OVERWRITTEN;
case 0x7F:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_KEYS_EXPIRED;
case -0x02:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_NUM_KEYS_RELOCATED;
case -0x03:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_BYTES_OVERWRITTEN;
case -0x04:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_BYTES_EXPIRED;
case -0x05:
return ROCKSDB_NAMESPACE::Tickers::BLOB_DB_GC_BYTES_RELOCATED;
case -0x06:
@@ -5522,6 +5594,16 @@ class HistogramTypeJni {
return 0xB;
case ROCKSDB_NAMESPACE::Histograms::WRITE_RAW_BLOCK_MICROS:
return 0xC;
case ROCKSDB_NAMESPACE::Histograms::STALL_L0_SLOWDOWN_COUNT:
return 0xD;
case ROCKSDB_NAMESPACE::Histograms::STALL_MEMTABLE_COMPACTION_COUNT:
return 0xE;
case ROCKSDB_NAMESPACE::Histograms::STALL_L0_NUM_FILES_COUNT:
return 0xF;
case ROCKSDB_NAMESPACE::Histograms::HARD_RATE_LIMIT_DELAY_COUNT:
return 0x10;
case ROCKSDB_NAMESPACE::Histograms::SOFT_RATE_LIMIT_DELAY_COUNT:
return 0x11;
case ROCKSDB_NAMESPACE::Histograms::NUM_FILES_IN_SINGLE_COMPACTION:
return 0x12;
case ROCKSDB_NAMESPACE::Histograms::DB_SEEK:
@@ -5574,6 +5656,8 @@ class HistogramTypeJni {
return 0x2A;
case ROCKSDB_NAMESPACE::Histograms::BLOB_DB_BLOB_FILE_SYNC_MICROS:
return 0x2B;
case ROCKSDB_NAMESPACE::Histograms::BLOB_DB_GC_MICROS:
return 0x2C;
case ROCKSDB_NAMESPACE::Histograms::BLOB_DB_COMPRESSION_MICROS:
return 0x2D;
case ROCKSDB_NAMESPACE::Histograms::BLOB_DB_DECOMPRESSION_MICROS:
@@ -5581,6 +5665,8 @@ class HistogramTypeJni {
case ROCKSDB_NAMESPACE::Histograms::
NUM_INDEX_AND_FILTER_BLOCKS_READ_PER_LEVEL:
return 0x2F;
case ROCKSDB_NAMESPACE::Histograms::NUM_DATA_BLOCKS_READ_PER_LEVEL:
return 0x30;
case ROCKSDB_NAMESPACE::Histograms::NUM_SST_READ_PER_LEVEL:
return 0x31;
case ROCKSDB_NAMESPACE::Histograms::ERROR_HANDLER_AUTORESUME_RETRY_COUNT:
@@ -5637,6 +5723,16 @@ class HistogramTypeJni {
return ROCKSDB_NAMESPACE::Histograms::READ_BLOCK_GET_MICROS;
case 0xC:
return ROCKSDB_NAMESPACE::Histograms::WRITE_RAW_BLOCK_MICROS;
case 0xD:
return ROCKSDB_NAMESPACE::Histograms::STALL_L0_SLOWDOWN_COUNT;
case 0xE:
return ROCKSDB_NAMESPACE::Histograms::STALL_MEMTABLE_COMPACTION_COUNT;
case 0xF:
return ROCKSDB_NAMESPACE::Histograms::STALL_L0_NUM_FILES_COUNT;
case 0x10:
return ROCKSDB_NAMESPACE::Histograms::HARD_RATE_LIMIT_DELAY_COUNT;
case 0x11:
return ROCKSDB_NAMESPACE::Histograms::SOFT_RATE_LIMIT_DELAY_COUNT;
case 0x12:
return ROCKSDB_NAMESPACE::Histograms::NUM_FILES_IN_SINGLE_COMPACTION;
case 0x13:
@@ -5689,6 +5785,8 @@ class HistogramTypeJni {
return ROCKSDB_NAMESPACE::Histograms::BLOB_DB_BLOB_FILE_READ_MICROS;
case 0x2B:
return ROCKSDB_NAMESPACE::Histograms::BLOB_DB_BLOB_FILE_SYNC_MICROS;
case 0x2C:
return ROCKSDB_NAMESPACE::Histograms::BLOB_DB_GC_MICROS;
case 0x2D:
return ROCKSDB_NAMESPACE::Histograms::BLOB_DB_COMPRESSION_MICROS;
case 0x2E:
@@ -5696,6 +5794,8 @@ class HistogramTypeJni {
case 0x2F:
return ROCKSDB_NAMESPACE::Histograms::
NUM_INDEX_AND_FILTER_BLOCKS_READ_PER_LEVEL;
case 0x30:
return ROCKSDB_NAMESPACE::Histograms::NUM_DATA_BLOCKS_READ_PER_LEVEL;
case 0x31:
return ROCKSDB_NAMESPACE::Histograms::NUM_SST_READ_PER_LEVEL;
case 0x32:
+19 -3
View File
@@ -55,8 +55,8 @@ jlong Java_org_rocksdb_BlockBasedTableConfig_newTableFactoryHandle(
jbyte jdata_block_index_type_value,
jdouble jdata_block_hash_table_util_ratio, jbyte jchecksum_type_value,
jboolean jno_block_cache, jlong jblock_cache_handle,
jlong jpersistent_cache_handle, jlong jblock_size,
jint jblock_size_deviation, jint jblock_restart_interval,
jlong jpersistent_cache_handle, jlong jblock_cache_compressed_handle,
jlong jblock_size, jint jblock_size_deviation, jint jblock_restart_interval,
jint jindex_block_restart_interval, jlong jmetadata_block_size,
jboolean jpartition_filters, jboolean joptimize_filters_for_memory,
jboolean juse_delta_encoding, jlong jfilter_policy_handle,
@@ -64,7 +64,8 @@ jlong Java_org_rocksdb_BlockBasedTableConfig_newTableFactoryHandle(
jint jread_amp_bytes_per_bit, jint jformat_version,
jboolean jenable_index_compression, jboolean jblock_align,
jbyte jindex_shortening, jlong jblock_cache_size,
jint jblock_cache_num_shard_bits) {
jint jblock_cache_num_shard_bits, jlong jblock_cache_compressed_size,
jint jblock_cache_compressed_num_shard_bits) {
ROCKSDB_NAMESPACE::BlockBasedTableOptions options;
options.cache_index_and_filter_blocks =
static_cast<bool>(jcache_index_and_filter_blocks);
@@ -112,6 +113,21 @@ jlong Java_org_rocksdb_BlockBasedTableConfig_newTableFactoryHandle(
jpersistent_cache_handle);
options.persistent_cache = *pCache;
}
if (jblock_cache_compressed_handle > 0) {
std::shared_ptr<ROCKSDB_NAMESPACE::Cache> *pCache =
reinterpret_cast<std::shared_ptr<ROCKSDB_NAMESPACE::Cache> *>(
jblock_cache_compressed_handle);
options.block_cache_compressed = *pCache;
} else if (jblock_cache_compressed_size > 0) {
if (jblock_cache_compressed_num_shard_bits > 0) {
options.block_cache_compressed = ROCKSDB_NAMESPACE::NewLRUCache(
static_cast<size_t>(jblock_cache_compressed_size),
static_cast<int>(jblock_cache_compressed_num_shard_bits));
} else {
options.block_cache_compressed = ROCKSDB_NAMESPACE::NewLRUCache(
static_cast<size_t>(jblock_cache_compressed_size));
}
}
options.block_size = static_cast<size_t>(jblock_size);
options.block_size_deviation = static_cast<int>(jblock_size_deviation);
options.block_restart_interval = static_cast<int>(jblock_restart_interval);
-2
View File
@@ -7,8 +7,6 @@
#include <jni.h>
#include <cassert>
#include "include/org_rocksdb_WriteBufferManager.h"
#include "rocksdb/cache.h"
#include "rocksjni/cplusplus_to_java_convert.h"
@@ -92,7 +92,8 @@ public class RocksDBSample {
.setFilterPolicy(bloomFilter)
.setBlockSizeDeviation(5)
.setBlockRestartInterval(10)
.setCacheIndexAndFilterBlocks(true);
.setCacheIndexAndFilterBlocks(true)
.setBlockCacheCompressed(new LRUCache(64 * 1000, 10));
assert (table_options.blockSizeDeviation() == 5);
assert (table_options.blockRestartInterval() == 10);
@@ -25,6 +25,7 @@ public class BlockBasedTableConfig extends TableFormatConfig {
noBlockCache = false;
blockCache = null;
persistentCache = null;
blockCacheCompressed = null;
blockSize = 4 * 1024;
blockSizeDeviation = 10;
blockRestartInterval = 16;
@@ -45,6 +46,10 @@ public class BlockBasedTableConfig extends TableFormatConfig {
// NOTE: ONLY used if blockCache == null
blockCacheSize = 8 * 1024 * 1024;
blockCacheNumShardBits = 0;
// NOTE: ONLY used if blockCacheCompressed == null
blockCacheCompressedSize = 0;
blockCacheCompressedNumShardBits = 0;
}
/**
@@ -290,6 +295,31 @@ public class BlockBasedTableConfig extends TableFormatConfig {
return this;
}
/**
* Use the specified cache for compressed blocks.
*
* If {@code null}, RocksDB will not use a compressed block cache.
*
* Note: though it looks similar to {@link #setBlockCache(Cache)}, RocksDB
* doesn't put the same type of object there.
*
* {@link org.rocksdb.Cache} should not be disposed before options instances
* using this cache is disposed.
*
* {@link org.rocksdb.Cache} instance can be re-used in multiple options
* instances.
*
* @param blockCacheCompressed {@link org.rocksdb.Cache} Cache java instance
* (e.g. LRUCache).
*
* @return the reference to the current config.
*/
public BlockBasedTableConfig setBlockCacheCompressed(
final Cache blockCacheCompressed) {
this.blockCacheCompressed = blockCacheCompressed;
return this;
}
/**
* Get the approximate size of user data packed per block.
*
@@ -829,6 +859,64 @@ public class BlockBasedTableConfig extends TableFormatConfig {
return this;
}
/**
* Size of compressed block cache. If 0, then block_cache_compressed is set
* to null.
*
* @return size of compressed block cache.
*/
@Deprecated
public long blockCacheCompressedSize() {
return blockCacheCompressedSize;
}
/**
* Size of compressed block cache. If 0, then block_cache_compressed is set
* to null.
*
* @param blockCacheCompressedSize of compressed block cache.
* @return the reference to the current config.
*
* @deprecated Use {@link #setBlockCacheCompressed(Cache)}.
*/
@Deprecated
public BlockBasedTableConfig setBlockCacheCompressedSize(
final long blockCacheCompressedSize) {
this.blockCacheCompressedSize = blockCacheCompressedSize;
return this;
}
/**
* Controls the number of shards for the block compressed cache.
* This is applied only if blockCompressedCacheSize is set to non-negative.
*
* @return numShardBits the number of shard bits. The resulting
* number of shards would be 2 ^ numShardBits. Any negative
* number means use default settings.
*/
@Deprecated
public int blockCacheCompressedNumShardBits() {
return blockCacheCompressedNumShardBits;
}
/**
* Controls the number of shards for the block compressed cache.
* This is applied only if blockCompressedCacheSize is set to non-negative.
*
* @param blockCacheCompressedNumShardBits the number of shard bits. The resulting
* number of shards would be 2 ^ numShardBits. Any negative
* number means use default settings."
* @return the reference to the current option.
*
* @deprecated Use {@link #setBlockCacheCompressed(Cache)}.
*/
@Deprecated
public BlockBasedTableConfig setBlockCacheCompressedNumShardBits(
final int blockCacheCompressedNumShardBits) {
this.blockCacheCompressedNumShardBits = blockCacheCompressedNumShardBits;
return this;
}
/**
* Influence the behavior when kHashSearch is used.
* if false, stores a precise prefix to block range mapping
@@ -889,15 +977,23 @@ public class BlockBasedTableConfig extends TableFormatConfig {
persistentCacheHandle = 0;
}
final long blockCacheCompressedHandle;
if (blockCacheCompressed != null) {
blockCacheCompressedHandle = blockCacheCompressed.nativeHandle_;
} else {
blockCacheCompressedHandle = 0;
}
return newTableFactoryHandle(cacheIndexAndFilterBlocks,
cacheIndexAndFilterBlocksWithHighPriority, pinL0FilterAndIndexBlocksInCache,
pinTopLevelIndexAndFilter, indexType.getValue(), dataBlockIndexType.getValue(),
dataBlockHashTableUtilRatio, checksumType.getValue(), noBlockCache, blockCacheHandle,
persistentCacheHandle, blockSize, blockSizeDeviation, blockRestartInterval,
indexBlockRestartInterval, metadataBlockSize, partitionFilters, optimizeFiltersForMemory,
useDeltaEncoding, filterPolicyHandle, wholeKeyFiltering, verifyCompression,
readAmpBytesPerBit, formatVersion, enableIndexCompression, blockAlign,
indexShortening.getValue(), blockCacheSize, blockCacheNumShardBits);
persistentCacheHandle, blockCacheCompressedHandle, blockSize, blockSizeDeviation,
blockRestartInterval, indexBlockRestartInterval, metadataBlockSize, partitionFilters,
optimizeFiltersForMemory, useDeltaEncoding, filterPolicyHandle, wholeKeyFiltering,
verifyCompression, readAmpBytesPerBit, formatVersion, enableIndexCompression, blockAlign,
indexShortening.getValue(), blockCacheSize, blockCacheNumShardBits,
blockCacheCompressedSize, blockCacheCompressedNumShardBits);
}
private native long newTableFactoryHandle(final boolean cacheIndexAndFilterBlocks,
@@ -906,15 +1002,18 @@ public class BlockBasedTableConfig extends TableFormatConfig {
final byte indexTypeValue, final byte dataBlockIndexTypeValue,
final double dataBlockHashTableUtilRatio, final byte checksumTypeValue,
final boolean noBlockCache, final long blockCacheHandle, final long persistentCacheHandle,
final long blockSize, final int blockSizeDeviation, final int blockRestartInterval,
final int indexBlockRestartInterval, final long metadataBlockSize,
final boolean partitionFilters, final boolean optimizeFiltersForMemory,
final boolean useDeltaEncoding, final long filterPolicyHandle,
final boolean wholeKeyFiltering, final boolean verifyCompression,
final int readAmpBytesPerBit, final int formatVersion, final boolean enableIndexCompression,
final boolean blockAlign, final byte indexShortening,
final long blockCacheCompressedHandle, final long blockSize, final int blockSizeDeviation,
final int blockRestartInterval, final int indexBlockRestartInterval,
final long metadataBlockSize, final boolean partitionFilters,
final boolean optimizeFiltersForMemory, final boolean useDeltaEncoding,
final long filterPolicyHandle, final boolean wholeKeyFiltering,
final boolean verifyCompression, final int readAmpBytesPerBit, final int formatVersion,
final boolean enableIndexCompression, final boolean blockAlign, final byte indexShortening,
@Deprecated final long blockCacheSize, @Deprecated final int blockCacheNumShardBits);
@Deprecated final long blockCacheSize, @Deprecated final int blockCacheNumShardBits,
@Deprecated final long blockCacheCompressedSize,
@Deprecated final int blockCacheCompressedNumShardBits);
//TODO(AR) flushBlockPolicyFactory
private boolean cacheIndexAndFilterBlocks;
@@ -928,6 +1027,7 @@ public class BlockBasedTableConfig extends TableFormatConfig {
private boolean noBlockCache;
private Cache blockCache;
private PersistentCache persistentCache;
private Cache blockCacheCompressed;
private long blockSize;
private int blockSizeDeviation;
private int blockRestartInterval;
@@ -948,4 +1048,8 @@ public class BlockBasedTableConfig extends TableFormatConfig {
// NOTE: ONLY used if blockCache == null
@Deprecated private long blockCacheSize;
@Deprecated private int blockCacheNumShardBits;
// NOTE: ONLY used if blockCacheCompressed == null
@Deprecated private long blockCacheCompressedSize;
@Deprecated private int blockCacheCompressedNumShardBits;
}
@@ -36,6 +36,16 @@ public enum HistogramType {
WRITE_RAW_BLOCK_MICROS((byte) 0xC),
STALL_L0_SLOWDOWN_COUNT((byte) 0xD),
STALL_MEMTABLE_COMPACTION_COUNT((byte) 0xE),
STALL_L0_NUM_FILES_COUNT((byte) 0xF),
HARD_RATE_LIMIT_DELAY_COUNT((byte) 0x10),
SOFT_RATE_LIMIT_DELAY_COUNT((byte) 0x11),
NUM_FILES_IN_SINGLE_COMPACTION((byte) 0x12),
DB_SEEK((byte) 0x13),
@@ -134,6 +144,11 @@ public enum HistogramType {
*/
BLOB_DB_BLOB_FILE_SYNC_MICROS((byte) 0x2B),
/**
* BlobDB garbage collection time.
*/
BLOB_DB_GC_MICROS((byte) 0x2C),
/**
* BlobDB compression time.
*/
@@ -150,6 +165,11 @@ public enum HistogramType {
*/
NUM_INDEX_AND_FILTER_BLOCKS_READ_PER_LEVEL((byte) 0x2F),
/**
* Num of Data blocks read from file system per level in MultiGet request.
*/
NUM_DATA_BLOCKS_READ_PER_LEVEL((byte) 0x30),
/**
* Num of SST files read from file system per level in MultiGet request.
*/
@@ -29,12 +29,53 @@ public class OptionsUtil {
* For table_factory, this function further supports deserializing
* BlockBasedTableFactory and its BlockBasedTableOptions except the
* pointer options of BlockBasedTableOptions (flush_block_policy_factory,
* and block_cache), which will be initialized with
* block_cache, and block_cache_compressed), which will be initialized with
* default values. Developers can further specify these three options by
* casting the return value of TableFactoroy::GetOptions() to
* BlockBasedTableOptions and making necessary changes.
*
* @param dbPath the path to the RocksDB.
* @param env {@link org.rocksdb.Env} instance.
* @param dbOptions {@link org.rocksdb.DBOptions} instance. This will be
* filled and returned.
* @param cfDescs A list of {@link org.rocksdb.ColumnFamilyDescriptor}'s be
* returned.
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public static void loadLatestOptions(String dbPath, Env env, DBOptions dbOptions,
List<ColumnFamilyDescriptor> cfDescs) throws RocksDBException {
loadLatestOptions(dbPath, env, dbOptions, cfDescs, false);
}
/**
* @param dbPath the path to the RocksDB.
* @param env {@link org.rocksdb.Env} instance.
* @param dbOptions {@link org.rocksdb.DBOptions} instance. This will be
* filled and returned.
* @param cfDescs A list of {@link org.rocksdb.ColumnFamilyDescriptor}'s be
* returned.
* @param ignoreUnknownOptions this flag can be set to true if you want to
* ignore options that are from a newer version of the db, essentially for
* forward compatibility.
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public static void loadLatestOptions(String dbPath, Env env, DBOptions dbOptions,
List<ColumnFamilyDescriptor> cfDescs, boolean ignoreUnknownOptions) throws RocksDBException {
loadLatestOptions(
dbPath, env.nativeHandle_, dbOptions.nativeHandle_, cfDescs, ignoreUnknownOptions);
}
/**
* Similar to LoadLatestOptions, this function constructs the DBOptions
* and ColumnFamilyDescriptors based on the specified RocksDB Options file.
* See LoadLatestOptions above.
*
* @param dbPath the path to the RocksDB.
* @param configOptions {@link org.rocksdb.ConfigOptions} instance.
* @param dbOptions {@link org.rocksdb.DBOptions} instance. This will be
* filled and returned.
@@ -48,6 +89,46 @@ public class OptionsUtil {
loadLatestOptions(configOptions.nativeHandle_, dbPath, dbOptions.nativeHandle_, cfDescs);
}
/**
* Similar to LoadLatestOptions, this function constructs the DBOptions
* and ColumnFamilyDescriptors based on the specified RocksDB Options file.
* See LoadLatestOptions above.
*
* @param optionsFileName the RocksDB options file path.
* @param env {@link org.rocksdb.Env} instance.
* @param dbOptions {@link org.rocksdb.DBOptions} instance. This will be
* filled and returned.
* @param cfDescs A list of {@link org.rocksdb.ColumnFamilyDescriptor}'s be
* returned.
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public static void loadOptionsFromFile(String optionsFileName, Env env, DBOptions dbOptions,
List<ColumnFamilyDescriptor> cfDescs) throws RocksDBException {
loadOptionsFromFile(optionsFileName, env, dbOptions, cfDescs, false);
}
/**
* @param optionsFileName the RocksDB options file path.
* @param env {@link org.rocksdb.Env} instance.
* @param dbOptions {@link org.rocksdb.DBOptions} instance. This will be
* filled and returned.
* @param cfDescs A list of {@link org.rocksdb.ColumnFamilyDescriptor}'s be
* returned.
* @param ignoreUnknownOptions this flag can be set to true if you want to
* ignore options that are from a newer version of the db, esentially for
* forward compatibility.
*
* @throws RocksDBException thrown if error happens in underlying
* native library.
*/
public static void loadOptionsFromFile(String optionsFileName, Env env, DBOptions dbOptions,
List<ColumnFamilyDescriptor> cfDescs, boolean ignoreUnknownOptions) throws RocksDBException {
loadOptionsFromFile(
optionsFileName, env.nativeHandle_, dbOptions.nativeHandle_, cfDescs, ignoreUnknownOptions);
}
/**
* Similar to LoadLatestOptions, this function constructs the DBOptions
* and ColumnFamilyDescriptors based on the specified RocksDB Options file.
@@ -89,8 +170,13 @@ public class OptionsUtil {
private OptionsUtil() {}
// native methods
private native static void loadLatestOptions(String dbPath, long envHandle, long dbOptionsHandle,
List<ColumnFamilyDescriptor> cfDescs, boolean ignoreUnknownOptions) throws RocksDBException;
private native static void loadLatestOptions(long cfgHandle, String dbPath, long dbOptionsHandle,
List<ColumnFamilyDescriptor> cfDescs) throws RocksDBException;
private native static void loadOptionsFromFile(String optionsFileName, long envHandle,
long dbOptionsHandle, List<ColumnFamilyDescriptor> cfDescs, boolean ignoreUnknownOptions)
throws RocksDBException;
private native static void loadOptionsFromFile(long cfgHandle, String optionsFileName,
long dbOptionsHandle, List<ColumnFamilyDescriptor> cfDescs) throws RocksDBException;
private native static String getLatestOptionsFileName(String dbPath, long envHandle)
@@ -62,6 +62,11 @@ public enum TickerType {
*/
BLOCK_CACHE_INDEX_BYTES_INSERT((byte) 0x7),
/**
* # of bytes of index block erased from cache
*/
BLOCK_CACHE_INDEX_BYTES_EVICT((byte) 0x8),
/**
* # of times cache miss when accessing filter block from block cache.
*/
@@ -82,6 +87,11 @@ public enum TickerType {
*/
BLOCK_CACHE_FILTER_BYTES_INSERT((byte) 0xC),
/**
* # of bytes of bloom filter block erased from cache
*/
BLOCK_CACHE_FILTER_BYTES_EVICT((byte) 0xD),
/**
* # of times cache miss when accessing data block from block cache.
*/
@@ -259,10 +269,36 @@ public enum TickerType {
*/
ITER_BYTES_READ((byte) 0x2E),
NO_FILE_CLOSES((byte) 0x2F),
NO_FILE_OPENS((byte) 0x30),
NO_FILE_ERRORS((byte) 0x31),
/**
* Time system had to wait to do LO-L1 compactions.
*
* @deprecated
*/
@Deprecated
STALL_L0_SLOWDOWN_MICROS((byte) 0x32),
/**
* Time system had to wait to move memtable to L1.
*
* @deprecated
*/
@Deprecated
STALL_MEMTABLE_COMPACTION_MICROS((byte) 0x33),
/**
* write throttle because of too many files in L0.
*
* @deprecated
*/
@Deprecated
STALL_L0_NUM_FILES_MICROS((byte) 0x34),
/**
* Writer has to wait for compaction or flush to finish.
*/
@@ -275,6 +311,14 @@ public enum TickerType {
*/
DB_MUTEX_WAIT_MICROS((byte) 0x36),
RATE_LIMIT_DELAY_MILLIS((byte) 0x37),
/**
* Number of iterators created.
*
*/
NO_ITERATORS((byte) 0x38),
/**
* Number of MultiGet calls.
*/
@@ -290,6 +334,11 @@ public enum TickerType {
*/
NUMBER_MULTIGET_BYTES_READ((byte) 0x3B),
/**
* Number of deletes records that were not required to be
* written to storage because key does not exist.
*/
NUMBER_FILTERED_DELETES((byte) 0x3C),
NUMBER_MERGE_FAILURES((byte) 0x3D),
/**
@@ -312,6 +361,26 @@ public enum TickerType {
*/
GET_UPDATES_SINCE_CALLS((byte) 0x41),
/**
* Miss in the compressed block cache.
*/
BLOCK_CACHE_COMPRESSED_MISS((byte) 0x42),
/**
* Hit in the compressed block cache.
*/
BLOCK_CACHE_COMPRESSED_HIT((byte) 0x43),
/**
* Number of blocks added to compressed block cache.
*/
BLOCK_CACHE_COMPRESSED_ADD((byte) 0x44),
/**
* Number of failures when adding blocks to compressed block cache.
*/
BLOCK_CACHE_COMPRESSED_ADD_FAILURES((byte) 0x45),
/**
* Number of times WAL sync is done.
*/
@@ -333,6 +402,11 @@ public enum TickerType {
*/
WRITE_DONE_BY_OTHER((byte) 0x49),
/**
* Number of writes ending up with timed-out.
*/
WRITE_TIMEDOUT((byte) 0x4A),
/**
* Number of Write calls that request WAL.
*/
@@ -574,11 +648,33 @@ public enum TickerType {
*/
BLOB_DB_GC_FAILURES((byte) 0x7D),
/**
* # of keys drop by BlobDB garbage collection because they had been
* overwritten.
*/
BLOB_DB_GC_NUM_KEYS_OVERWRITTEN((byte) 0x7E),
/**
* # of keys drop by BlobDB garbage collection because of expiration.
*/
BLOB_DB_GC_NUM_KEYS_EXPIRED((byte) 0x7F),
/**
* # of keys relocated to new blob file by garbage collection.
*/
BLOB_DB_GC_NUM_KEYS_RELOCATED((byte) -0x02),
/**
* # of bytes drop by BlobDB garbage collection because they had been
* overwritten.
*/
BLOB_DB_GC_BYTES_OVERWRITTEN((byte) -0x03),
/**
* # of bytes drop by BlobDB garbage collection because of expiration.
*/
BLOB_DB_GC_BYTES_EXPIRED((byte) -0x04),
/**
* # of bytes relocated to new blob file by garbage collection.
*/
@@ -230,6 +230,63 @@ public class BlockBasedTableConfigTest {
}
}
@Test
public void blockCacheCompressed() {
try (final Cache cache = new LRUCache(17 * 1024 * 1024);
final Options options = new Options().setTableFormatConfig(
new BlockBasedTableConfig().setBlockCacheCompressed(cache))) {
assertThat(options.tableFactoryName()).isEqualTo("BlockBasedTable");
}
}
@Ignore("See issue: https://github.com/facebook/rocksdb/issues/4822")
@Test
public void blockCacheCompressedIntegration() throws RocksDBException {
final byte[] key1 = "some-key1".getBytes(StandardCharsets.UTF_8);
final byte[] key2 = "some-key1".getBytes(StandardCharsets.UTF_8);
final byte[] key3 = "some-key1".getBytes(StandardCharsets.UTF_8);
final byte[] key4 = "some-key1".getBytes(StandardCharsets.UTF_8);
final byte[] value = "some-value".getBytes(StandardCharsets.UTF_8);
try (final Cache compressedCache = new LRUCache(8 * 1024 * 1024);
final Statistics statistics = new Statistics()) {
final BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig()
.setNoBlockCache(true)
.setBlockCache(null)
.setBlockCacheCompressed(compressedCache)
.setFormatVersion(4);
try (final Options options = new Options()
.setCreateIfMissing(true)
.setStatistics(statistics)
.setTableFormatConfig(blockBasedTableConfig)) {
for (int shard = 0; shard < 8; shard++) {
try (final FlushOptions flushOptions = new FlushOptions();
final WriteOptions writeOptions = new WriteOptions();
final ReadOptions readOptions = new ReadOptions();
final RocksDB db =
RocksDB.open(options, dbFolder.getRoot().getAbsolutePath() + "/" + shard)) {
db.put(writeOptions, key1, value);
db.put(writeOptions, key2, value);
db.put(writeOptions, key3, value);
db.put(writeOptions, key4, value);
db.flush(flushOptions);
db.get(readOptions, key1);
db.get(readOptions, key2);
db.get(readOptions, key3);
db.get(readOptions, key4);
assertThat(statistics.getTickerCount(TickerType.BLOCK_CACHE_COMPRESSED_ADD)).isEqualTo(shard + 1);
}
}
}
}
}
@Test
public void blockSize() {
final BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
@@ -413,4 +470,21 @@ public class BlockBasedTableConfigTest {
isEqualTo(5);
}
@Deprecated
@Test
public void blockCacheCompressedSize() {
final BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockCacheCompressedSize(40);
assertThat(blockBasedTableConfig.blockCacheCompressedSize()).
isEqualTo(40);
}
@Deprecated
@Test
public void blockCacheCompressedNumShardBits() {
final BlockBasedTableConfig blockBasedTableConfig = new BlockBasedTableConfig();
blockBasedTableConfig.setBlockCacheCompressedNumShardBits(4);
assertThat(blockBasedTableConfig.blockCacheCompressedNumShardBits()).
isEqualTo(4);
}
}
@@ -77,16 +77,13 @@ public class OptionsUtilTest {
// Read the options back and verify
DBOptions dbOptions = new DBOptions();
ConfigOptions configOptions =
new ConfigOptions().setIgnoreUnknownOptions(false).setInputStringsEscaped(true).setEnv(
Env.getDefault());
final List<ColumnFamilyDescriptor> cfDescs = new ArrayList<>();
String path = dbPath;
if (apiType == TestAPI.LOAD_LATEST_OPTIONS) {
OptionsUtil.loadLatestOptions(configOptions, path, dbOptions, cfDescs);
OptionsUtil.loadLatestOptions(path, Env.getDefault(), dbOptions, cfDescs, false);
} else if (apiType == TestAPI.LOAD_OPTIONS_FROM_FILE) {
path = dbPath + "/" + OptionsUtil.getLatestOptionsFileName(dbPath, Env.getDefault());
OptionsUtil.loadOptionsFromFile(configOptions, path, dbOptions, cfDescs);
OptionsUtil.loadOptionsFromFile(path, Env.getDefault(), dbOptions, cfDescs, false);
}
assertThat(dbOptions.createIfMissing()).isEqualTo(options.createIfMissing());
-1
View File
@@ -9,7 +9,6 @@
#include "rocksdb/write_buffer_manager.h"
#include "rocksdb/advanced_cache.h"
#include "test_util/testharness.h"
namespace ROCKSDB_NAMESPACE {
+29
View File
@@ -28,11 +28,13 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
{BLOCK_CACHE_INDEX_HIT, "rocksdb.block.cache.index.hit"},
{BLOCK_CACHE_INDEX_ADD, "rocksdb.block.cache.index.add"},
{BLOCK_CACHE_INDEX_BYTES_INSERT, "rocksdb.block.cache.index.bytes.insert"},
{BLOCK_CACHE_INDEX_BYTES_EVICT, "rocksdb.block.cache.index.bytes.evict"},
{BLOCK_CACHE_FILTER_MISS, "rocksdb.block.cache.filter.miss"},
{BLOCK_CACHE_FILTER_HIT, "rocksdb.block.cache.filter.hit"},
{BLOCK_CACHE_FILTER_ADD, "rocksdb.block.cache.filter.add"},
{BLOCK_CACHE_FILTER_BYTES_INSERT,
"rocksdb.block.cache.filter.bytes.insert"},
{BLOCK_CACHE_FILTER_BYTES_EVICT, "rocksdb.block.cache.filter.bytes.evict"},
{BLOCK_CACHE_DATA_MISS, "rocksdb.block.cache.data.miss"},
{BLOCK_CACHE_DATA_HIT, "rocksdb.block.cache.data.hit"},
{BLOCK_CACHE_DATA_ADD, "rocksdb.block.cache.data.add"},
@@ -43,6 +45,7 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
{BLOOM_FILTER_FULL_POSITIVE, "rocksdb.bloom.filter.full.positive"},
{BLOOM_FILTER_FULL_TRUE_POSITIVE,
"rocksdb.bloom.filter.full.true.positive"},
{BLOOM_FILTER_MICROS, "rocksdb.bloom.filter.micros"},
{PERSISTENT_CACHE_HIT, "rocksdb.persistent.cache.hit"},
{PERSISTENT_CACHE_MISS, "rocksdb.persistent.cache.miss"},
{SIM_BLOCK_CACHE_HIT, "rocksdb.sim.block.cache.hit"},
@@ -73,22 +76,35 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
{NUMBER_DB_NEXT_FOUND, "rocksdb.number.db.next.found"},
{NUMBER_DB_PREV_FOUND, "rocksdb.number.db.prev.found"},
{ITER_BYTES_READ, "rocksdb.db.iter.bytes.read"},
{NO_FILE_CLOSES, "rocksdb.no.file.closes"},
{NO_FILE_OPENS, "rocksdb.no.file.opens"},
{NO_FILE_ERRORS, "rocksdb.no.file.errors"},
{STALL_L0_SLOWDOWN_MICROS, "rocksdb.l0.slowdown.micros"},
{STALL_MEMTABLE_COMPACTION_MICROS, "rocksdb.memtable.compaction.micros"},
{STALL_L0_NUM_FILES_MICROS, "rocksdb.l0.num.files.stall.micros"},
{STALL_MICROS, "rocksdb.stall.micros"},
{DB_MUTEX_WAIT_MICROS, "rocksdb.db.mutex.wait.micros"},
{RATE_LIMIT_DELAY_MILLIS, "rocksdb.rate.limit.delay.millis"},
{NO_ITERATORS, "rocksdb.num.iterators"},
{NUMBER_MULTIGET_CALLS, "rocksdb.number.multiget.get"},
{NUMBER_MULTIGET_KEYS_READ, "rocksdb.number.multiget.keys.read"},
{NUMBER_MULTIGET_BYTES_READ, "rocksdb.number.multiget.bytes.read"},
{NUMBER_FILTERED_DELETES, "rocksdb.number.deletes.filtered"},
{NUMBER_MERGE_FAILURES, "rocksdb.number.merge.failures"},
{BLOOM_FILTER_PREFIX_CHECKED, "rocksdb.bloom.filter.prefix.checked"},
{BLOOM_FILTER_PREFIX_USEFUL, "rocksdb.bloom.filter.prefix.useful"},
{NUMBER_OF_RESEEKS_IN_ITERATION, "rocksdb.number.reseeks.iteration"},
{GET_UPDATES_SINCE_CALLS, "rocksdb.getupdatessince.calls"},
{BLOCK_CACHE_COMPRESSED_MISS, "rocksdb.block.cachecompressed.miss"},
{BLOCK_CACHE_COMPRESSED_HIT, "rocksdb.block.cachecompressed.hit"},
{BLOCK_CACHE_COMPRESSED_ADD, "rocksdb.block.cachecompressed.add"},
{BLOCK_CACHE_COMPRESSED_ADD_FAILURES,
"rocksdb.block.cachecompressed.add.failures"},
{WAL_FILE_SYNCED, "rocksdb.wal.synced"},
{WAL_FILE_BYTES, "rocksdb.wal.bytes"},
{WRITE_DONE_BY_SELF, "rocksdb.write.self"},
{WRITE_DONE_BY_OTHER, "rocksdb.write.other"},
{WRITE_TIMEDOUT, "rocksdb.write.timeout"},
{WRITE_WITH_WAL, "rocksdb.write.wal"},
{COMPACT_READ_BYTES, "rocksdb.compact.read.bytes"},
{COMPACT_WRITE_BYTES, "rocksdb.compact.write.bytes"},
@@ -142,7 +158,11 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
{BLOB_DB_GC_NUM_FILES, "rocksdb.blobdb.gc.num.files"},
{BLOB_DB_GC_NUM_NEW_FILES, "rocksdb.blobdb.gc.num.new.files"},
{BLOB_DB_GC_FAILURES, "rocksdb.blobdb.gc.failures"},
{BLOB_DB_GC_NUM_KEYS_OVERWRITTEN, "rocksdb.blobdb.gc.num.keys.overwritten"},
{BLOB_DB_GC_NUM_KEYS_EXPIRED, "rocksdb.blobdb.gc.num.keys.expired"},
{BLOB_DB_GC_NUM_KEYS_RELOCATED, "rocksdb.blobdb.gc.num.keys.relocated"},
{BLOB_DB_GC_BYTES_OVERWRITTEN, "rocksdb.blobdb.gc.bytes.overwritten"},
{BLOB_DB_GC_BYTES_EXPIRED, "rocksdb.blobdb.gc.bytes.expired"},
{BLOB_DB_GC_BYTES_RELOCATED, "rocksdb.blobdb.gc.bytes.relocated"},
{BLOB_DB_FIFO_NUM_FILES_EVICTED, "rocksdb.blobdb.fifo.num.files.evicted"},
{BLOB_DB_FIFO_NUM_KEYS_EVICTED, "rocksdb.blobdb.fifo.num.keys.evicted"},
@@ -164,6 +184,8 @@ const std::vector<std::pair<Tickers, std::string>> TickersNameMap = {
"rocksdb.block.cache.compression.dict.add"},
{BLOCK_CACHE_COMPRESSION_DICT_BYTES_INSERT,
"rocksdb.block.cache.compression.dict.bytes.insert"},
{BLOCK_CACHE_COMPRESSION_DICT_BYTES_EVICT,
"rocksdb.block.cache.compression.dict.bytes.evict"},
{BLOCK_CACHE_ADD_REDUNDANT, "rocksdb.block.cache.add.redundant"},
{BLOCK_CACHE_INDEX_ADD_REDUNDANT,
"rocksdb.block.cache.index.add.redundant"},
@@ -230,6 +252,11 @@ const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
{READ_BLOCK_COMPACTION_MICROS, "rocksdb.read.block.compaction.micros"},
{READ_BLOCK_GET_MICROS, "rocksdb.read.block.get.micros"},
{WRITE_RAW_BLOCK_MICROS, "rocksdb.write.raw.block.micros"},
{STALL_L0_SLOWDOWN_COUNT, "rocksdb.l0.slowdown.count"},
{STALL_MEMTABLE_COMPACTION_COUNT, "rocksdb.memtable.compaction.count"},
{STALL_L0_NUM_FILES_COUNT, "rocksdb.num.files.stall.count"},
{HARD_RATE_LIMIT_DELAY_COUNT, "rocksdb.hard.rate.limit.delay.count"},
{SOFT_RATE_LIMIT_DELAY_COUNT, "rocksdb.soft.rate.limit.delay.count"},
{NUM_FILES_IN_SINGLE_COMPACTION, "rocksdb.numfiles.in.singlecompaction"},
{DB_SEEK, "rocksdb.db.seek.micros"},
{WRITE_STALL, "rocksdb.db.write.stall"},
@@ -254,12 +281,14 @@ const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
{BLOB_DB_BLOB_FILE_WRITE_MICROS, "rocksdb.blobdb.blob.file.write.micros"},
{BLOB_DB_BLOB_FILE_READ_MICROS, "rocksdb.blobdb.blob.file.read.micros"},
{BLOB_DB_BLOB_FILE_SYNC_MICROS, "rocksdb.blobdb.blob.file.sync.micros"},
{BLOB_DB_GC_MICROS, "rocksdb.blobdb.gc.micros"},
{BLOB_DB_COMPRESSION_MICROS, "rocksdb.blobdb.compression.micros"},
{BLOB_DB_DECOMPRESSION_MICROS, "rocksdb.blobdb.decompression.micros"},
{FLUSH_TIME, "rocksdb.db.flush.micros"},
{SST_BATCH_SIZE, "rocksdb.sst.batch.size"},
{NUM_INDEX_AND_FILTER_BLOCKS_READ_PER_LEVEL,
"rocksdb.num.index.and.filter.blocks.read.per.level"},
{NUM_DATA_BLOCKS_READ_PER_LEVEL, "rocksdb.num.data.blocks.read.per.level"},
{NUM_SST_READ_PER_LEVEL, "rocksdb.num.sst.read.per.level"},
{ERROR_HANDLER_AUTORESUME_RETRY_COUNT,
"rocksdb.error.handler.autoresume.retry.count"},
-1
View File
@@ -16,7 +16,6 @@
#include "options/options_helper.h"
#include "options/options_parser.h"
#include "port/port.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/compaction_filter.h"
#include "rocksdb/concurrent_task_limiter.h"
#include "rocksdb/configurable.h"
-1
View File
@@ -12,7 +12,6 @@
#include "options/options_helper.h"
#include "options/options_parser.h"
#include "port/port.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/configurable.h"
#include "rocksdb/env.h"
#include "rocksdb/file_system.h"
+3
View File
@@ -125,6 +125,8 @@ TEST_F(OptionsSettableTest, BlockBasedTableOptionsAllFieldsSettable) {
sizeof(std::shared_ptr<Cache>)},
{offsetof(struct BlockBasedTableOptions, persistent_cache),
sizeof(std::shared_ptr<PersistentCache>)},
{offsetof(struct BlockBasedTableOptions, block_cache_compressed),
sizeof(std::shared_ptr<Cache>)},
{offsetof(struct BlockBasedTableOptions, cache_usage_options),
sizeof(CacheUsageOptions)},
{offsetof(struct BlockBasedTableOptions, filter_policy),
@@ -209,6 +211,7 @@ TEST_F(OptionsSettableTest, BlockBasedTableOptionsAllFieldsSettable) {
kBbtoExcluded));
ASSERT_TRUE(new_bbto->block_cache.get() != nullptr);
ASSERT_TRUE(new_bbto->block_cache_compressed.get() != nullptr);
ASSERT_TRUE(new_bbto->filter_policy.get() != nullptr);
bbto->~BlockBasedTableOptions();
+88
View File
@@ -936,6 +936,8 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(new_opt.checksum, ChecksumType::kxxHash);
ASSERT_TRUE(new_opt.block_cache != nullptr);
ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL*1024UL);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL);
ASSERT_EQ(new_opt.block_size, 1024UL);
ASSERT_EQ(new_opt.block_size_deviation, 8);
ASSERT_EQ(new_opt.block_restart_interval, 4);
@@ -1076,6 +1078,16 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
new_opt.block_cache)->GetHighPriPoolRatio(), 0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL*1024UL);
ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
4);
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), true);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
new_opt.block_cache_compressed)->GetHighPriPoolRatio(),
0.5);
// Set only block cache capacity. Check other values are
// reset to default values.
@@ -1094,6 +1106,18 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
->GetHighPriPoolRatio(),
0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 2*1024UL*1024UL);
// Default values
ASSERT_EQ(
std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
GetDefaultCacheShardBits(new_opt.block_cache_compressed->GetCapacity()));
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), false);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
->GetHighPriPoolRatio(),
0.5);
// Set couple of block cache options.
ASSERT_OK(GetBlockBasedTableOptionsFromString(
@@ -1109,6 +1133,16 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
new_opt.block_cache)->GetHighPriPoolRatio(), 0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 0);
ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
5);
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), false);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
->GetHighPriPoolRatio(),
0.0);
// Set couple of block cache options.
ASSERT_OK(GetBlockBasedTableOptionsFromString(
@@ -1127,6 +1161,16 @@ TEST_F(OptionsTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
->GetHighPriPoolRatio(),
0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL*1024UL);
ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
4);
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), true);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
->GetHighPriPoolRatio(),
0.5);
ASSERT_OK(GetBlockBasedTableOptionsFromString(
config_options, table_opt, "filter_policy=rocksdb.BloomFilter:1.234",
@@ -2899,6 +2943,8 @@ TEST_F(OptionsOldApiTest, GetBlockBasedTableOptionsFromString) {
ASSERT_TRUE(new_opt.no_block_cache);
ASSERT_TRUE(new_opt.block_cache != nullptr);
ASSERT_EQ(new_opt.block_cache->GetCapacity(), 1024UL*1024UL);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL);
ASSERT_EQ(new_opt.block_size, 1024UL);
ASSERT_EQ(new_opt.block_size_deviation, 8);
ASSERT_EQ(new_opt.block_restart_interval, 4);
@@ -2970,6 +3016,16 @@ TEST_F(OptionsOldApiTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), true);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
new_opt.block_cache)->GetHighPriPoolRatio(), 0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL*1024UL);
ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
4);
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), true);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
new_opt.block_cache_compressed)->GetHighPriPoolRatio(),
0.5);
// Set only block cache capacity. Check other values are
// reset to default values.
@@ -2988,6 +3044,18 @@ TEST_F(OptionsOldApiTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
->GetHighPriPoolRatio(),
0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 2*1024UL*1024UL);
// Default values
ASSERT_EQ(
std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
GetDefaultCacheShardBits(new_opt.block_cache_compressed->GetCapacity()));
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), false);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
->GetHighPriPoolRatio(),
0.5);
// Set couple of block cache options.
ASSERT_OK(GetBlockBasedTableOptionsFromString(
@@ -3003,6 +3071,16 @@ TEST_F(OptionsOldApiTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(new_opt.block_cache->HasStrictCapacityLimit(), false);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(
new_opt.block_cache)->GetHighPriPoolRatio(), 0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 0);
ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
5);
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), false);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
->GetHighPriPoolRatio(),
0.0);
// Set couple of block cache options.
ASSERT_OK(GetBlockBasedTableOptionsFromString(
@@ -3021,6 +3099,16 @@ TEST_F(OptionsOldApiTest, GetBlockBasedTableOptionsFromString) {
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache)
->GetHighPriPoolRatio(),
0.5);
ASSERT_TRUE(new_opt.block_cache_compressed != nullptr);
ASSERT_EQ(new_opt.block_cache_compressed->GetCapacity(), 1024UL*1024UL);
ASSERT_EQ(std::dynamic_pointer_cast<ShardedCacheBase>(
new_opt.block_cache_compressed)
->GetNumShardBits(),
4);
ASSERT_EQ(new_opt.block_cache_compressed->HasStrictCapacityLimit(), true);
ASSERT_EQ(std::dynamic_pointer_cast<LRUCache>(new_opt.block_cache_compressed)
->GetHighPriPoolRatio(),
0.5);
}
TEST_F(OptionsOldApiTest, GetPlainTableOptionsFromString) {
-1
View File
@@ -16,7 +16,6 @@
#include "db/pinned_iterators_manager.h"
#include "port/malloc.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/iterator.h"
#include "rocksdb/options.h"
#include "rocksdb/statistics.h"
+49 -2
View File
@@ -1284,6 +1284,7 @@ void BlockBasedTableBuilder::WriteMaybeCompressedBlock(
}
{
Status s = Status::OK();
bool warm_cache;
switch (r->table_options.prepopulate_block_cache) {
case BlockBasedTableOptions::PrepopulateBlockCache::kFlushOnly:
@@ -1298,13 +1299,18 @@ void BlockBasedTableBuilder::WriteMaybeCompressedBlock(
warm_cache = false;
}
if (warm_cache) {
Status s = InsertBlockInCacheHelper(*uncompressed_block_data, handle,
block_type);
s = InsertBlockInCacheHelper(*uncompressed_block_data, handle,
block_type);
if (!s.ok()) {
r->SetStatus(s);
return;
}
}
s = InsertBlockInCompressedCache(block_contents, type, handle);
if (!s.ok()) {
r->SetStatus(s);
return;
}
}
r->set_offset(r->get_offset() + block_contents.size() + kBlockTrailerSize);
@@ -1416,6 +1422,47 @@ IOStatus BlockBasedTableBuilder::io_status() const {
return rep_->GetIOStatus();
}
//
// Make a copy of the block contents and insert into compressed block cache
//
Status BlockBasedTableBuilder::InsertBlockInCompressedCache(
const Slice& block_contents, const CompressionType type,
const BlockHandle* handle) {
Rep* r = rep_;
CompressedBlockCacheInterface block_cache_compressed{
r->table_options.block_cache_compressed.get()};
Status s;
if (type != kNoCompression && block_cache_compressed) {
size_t size = block_contents.size();
auto ubuf = AllocateBlock(size + 1,
block_cache_compressed.get()->memory_allocator());
memcpy(ubuf.get(), block_contents.data(), size);
ubuf[size] = type;
BlockContents* block_contents_to_cache =
new BlockContents(std::move(ubuf), size);
#ifndef NDEBUG
block_contents_to_cache->has_trailer = true;
#endif // NDEBUG
CacheKey key = BlockBasedTable::GetCacheKey(rep_->base_cache_key, *handle);
s = block_cache_compressed.Insert(
key.AsSlice(), block_contents_to_cache,
block_contents_to_cache->ApproximateMemoryUsage());
if (s.ok()) {
RecordTick(rep_->ioptions.stats, BLOCK_CACHE_COMPRESSED_ADD);
} else {
RecordTick(rep_->ioptions.stats, BLOCK_CACHE_COMPRESSED_ADD_FAILURES);
}
// Invalidate OS cache.
r->file->InvalidateCache(static_cast<size_t>(r->get_offset()), size)
.PermitUncheckedError();
}
return s;
}
Status BlockBasedTableBuilder::InsertBlockInCacheHelper(
const Slice& block_contents, const BlockHandle* handle,
BlockType block_type) {
+71 -4
View File
@@ -230,6 +230,7 @@ static std::unordered_map<std::string, OptionTypeInfo>
block_based_table_type_info = {
/* currently not supported
std::shared_ptr<Cache> block_cache = nullptr;
std::shared_ptr<Cache> block_cache_compressed = nullptr;
CacheUsageOptions cache_usage_options;
*/
{"flush_block_policy_factory",
@@ -390,8 +391,15 @@ static std::unordered_map<std::string, OptionTypeInfo>
return Cache::CreateFromString(opts, value, cache);
}}},
{"block_cache_compressed",
{0, OptionType::kUnknown, OptionVerificationType::kDeprecated,
OptionTypeFlags::kNone}},
{offsetof(struct BlockBasedTableOptions, block_cache_compressed),
OptionType::kUnknown, OptionVerificationType::kNormal,
(OptionTypeFlags::kCompareNever | OptionTypeFlags::kDontSerialize),
// Parses the input value as a Cache
[](const ConfigOptions& opts, const std::string&,
const std::string& value, void* addr) {
auto* cache = static_cast<std::shared_ptr<Cache>*>(addr);
return Cache::CreateFromString(opts, value, cache);
}}},
{"max_auto_readahead_size",
{offsetof(struct BlockBasedTableOptions, max_auto_readahead_size),
OptionType::kSizeT, OptionVerificationType::kNormal,
@@ -497,12 +505,20 @@ namespace {
// they must not share an underlying key space with each other.
Status CheckCacheOptionCompatibility(const BlockBasedTableOptions& bbto) {
int cache_count = (bbto.block_cache != nullptr) +
(bbto.block_cache_compressed != nullptr) +
(bbto.persistent_cache != nullptr);
if (cache_count <= 1) {
// Nothing to share / overlap
return Status::OK();
}
// Simple pointer equality
if (bbto.block_cache == bbto.block_cache_compressed) {
return Status::InvalidArgument(
"block_cache same as block_cache_compressed not currently supported, "
"and would be bad for performance anyway");
}
// More complex test of shared key space, in case the instances are wrappers
// for some shared underlying cache.
static Cache::CacheItemHelper kHelper{CacheEntryRole::kMisc};
@@ -512,12 +528,19 @@ Status CheckCacheOptionCompatibility(const BlockBasedTableOptions& bbto) {
char c;
};
static SentinelValue kRegularBlockCacheMarker{'b'};
static SentinelValue kCompressedBlockCacheMarker{'c'};
static char kPersistentCacheMarker{'p'};
if (bbto.block_cache) {
bbto.block_cache
->Insert(sentinel_key.AsSlice(), &kRegularBlockCacheMarker, &kHelper, 1)
.PermitUncheckedError();
}
if (bbto.block_cache_compressed) {
bbto.block_cache_compressed
->Insert(sentinel_key.AsSlice(), &kCompressedBlockCacheMarker, &kHelper,
1)
.PermitUncheckedError();
}
if (bbto.persistent_cache) {
// Note: persistent cache copies the data, not keeping the pointer
bbto.persistent_cache
@@ -532,7 +555,11 @@ Status CheckCacheOptionCompatibility(const BlockBasedTableOptions& bbto) {
auto v = static_cast<SentinelValue*>(bbto.block_cache->Value(handle));
char c = v->c;
bbto.block_cache->Release(handle);
if (c == kPersistentCacheMarker) {
if (v == &kCompressedBlockCacheMarker) {
return Status::InvalidArgument(
"block_cache and block_cache_compressed share the same key space, "
"which is not supported");
} else if (c == kPersistentCacheMarker) {
return Status::InvalidArgument(
"block_cache and persistent_cache share the same key space, "
"which is not supported");
@@ -541,7 +568,28 @@ Status CheckCacheOptionCompatibility(const BlockBasedTableOptions& bbto) {
}
}
}
if (bbto.block_cache_compressed) {
auto handle = bbto.block_cache_compressed->Lookup(sentinel_key.AsSlice());
if (handle) {
auto v = static_cast<SentinelValue*>(
bbto.block_cache_compressed->Value(handle));
char c = v->c;
bbto.block_cache_compressed->Release(handle);
if (v == &kRegularBlockCacheMarker) {
return Status::InvalidArgument(
"block_cache_compressed and block_cache share the same key space, "
"which is not supported");
} else if (c == kPersistentCacheMarker) {
return Status::InvalidArgument(
"block_cache_compressed and persistent_cache share the same key "
"space, "
"which is not supported");
} else if (v != &kCompressedBlockCacheMarker) {
return Status::Corruption(
"Unexpected mutation to block_cache_compressed");
}
}
}
if (bbto.persistent_cache) {
std::unique_ptr<char[]> data;
size_t size = 0;
@@ -552,6 +600,11 @@ Status CheckCacheOptionCompatibility(const BlockBasedTableOptions& bbto) {
return Status::InvalidArgument(
"persistent_cache and block_cache share the same key space, "
"which is not supported");
} else if (data[0] == kCompressedBlockCacheMarker.c) {
return Status::InvalidArgument(
"persistent_cache and block_cache_compressed share the same key "
"space, "
"which is not supported");
} else if (data[0] != kPersistentCacheMarker) {
return Status::Corruption("Unexpected mutation to persistent_cache");
}
@@ -771,6 +824,20 @@ std::string BlockBasedTableFactory::GetPrintableOptions() const {
ret.append(" block_cache_options:\n");
ret.append(table_options_.block_cache->GetPrintableOptions());
}
snprintf(buffer, kBufferSize, " block_cache_compressed: %p\n",
static_cast<void*>(table_options_.block_cache_compressed.get()));
ret.append(buffer);
if (table_options_.block_cache_compressed) {
const char* block_cache_compressed_name =
table_options_.block_cache_compressed->Name();
if (block_cache_compressed_name != nullptr) {
snprintf(buffer, kBufferSize, " block_cache_name: %s\n",
block_cache_compressed_name);
ret.append(buffer);
}
ret.append(" block_cache_compressed_options:\n");
ret.append(table_options_.block_cache_compressed->GetPrintableOptions());
}
snprintf(buffer, kBufferSize, " persistent_cache: %p\n",
static_cast<void*>(table_options_.persistent_cache.get()));
ret.append(buffer);
+100 -7
View File
@@ -1253,7 +1253,10 @@ Status BlockBasedTable::ReadMetaIndexBlock(
template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::GetDataBlockFromCache(
const Slice& cache_key, BlockCacheInterface<TBlocklike> block_cache,
CachableEntry<TBlocklike>* out_parsed_block, const bool wait,
CompressedBlockCacheInterface block_cache_compressed,
const ReadOptions& read_options,
CachableEntry<TBlocklike>* out_parsed_block,
const UncompressionDict& uncompression_dict, const bool wait,
GetContext* get_context) const {
assert(out_parsed_block);
assert(out_parsed_block->IsEmpty());
@@ -1299,12 +1302,73 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::GetDataBlockFromCache(
// If not found, search from the compressed block cache.
assert(out_parsed_block->IsEmpty());
if (!block_cache_compressed) {
return s;
}
assert(!cache_key.empty());
BlockContents contents;
auto block_cache_compressed_handle =
block_cache_compressed.Lookup(cache_key, statistics);
// if we found in the compressed cache, then uncompress and insert into
// uncompressed cache
if (block_cache_compressed_handle == nullptr) {
RecordTick(statistics, BLOCK_CACHE_COMPRESSED_MISS);
return s;
}
// found compressed block
RecordTick(statistics, BLOCK_CACHE_COMPRESSED_HIT);
BlockContents* compressed_block =
block_cache_compressed.Value(block_cache_compressed_handle);
CompressionType compression_type = GetBlockCompressionType(*compressed_block);
assert(compression_type != kNoCompression);
// Retrieve the uncompressed contents into a new buffer
UncompressionContext context(compression_type);
UncompressionInfo info(context, uncompression_dict, compression_type);
s = UncompressSerializedBlock(
info, compressed_block->data.data(), compressed_block->data.size(),
&contents, rep_->table_options.format_version, rep_->ioptions,
GetMemoryAllocator(rep_->table_options));
// Insert parsed block into block cache, the priority is based on the
// data block type.
if (s.ok()) {
std::unique_ptr<TBlocklike> block_holder;
rep_->create_context.Create(&block_holder, std::move(contents));
if (block_cache && block_holder->own_bytes() && read_options.fill_cache) {
size_t charge = block_holder->ApproximateMemoryUsage();
BlockCacheTypedHandle<TBlocklike>* cache_handle = nullptr;
s = block_cache.InsertFull(cache_key, block_holder.get(), charge,
&cache_handle, priority,
rep_->ioptions.lowest_used_cache_tier);
if (s.ok()) {
assert(cache_handle != nullptr);
out_parsed_block->SetCachedValue(block_holder.release(),
block_cache.get(), cache_handle);
UpdateCacheInsertionMetrics(TBlocklike::kBlockType, get_context, charge,
s.IsOkOverwritten(), rep_->ioptions.stats);
} else {
RecordTick(statistics, BLOCK_CACHE_ADD_FAILURES);
}
} else {
out_parsed_block->SetOwnedValue(std::move(block_holder));
}
}
// Release hold on compressed cache entry
block_cache_compressed.Release(block_cache_compressed_handle);
return s;
}
template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::PutDataBlockToCache(
const Slice& cache_key, BlockCacheInterface<TBlocklike> block_cache,
CompressedBlockCacheInterface block_cache_compressed,
CachableEntry<TBlocklike>* out_parsed_block, BlockContents&& block_contents,
CompressionType block_comp_type,
const UncompressionDict& uncompression_dict,
@@ -1341,6 +1405,32 @@ WithBlocklikeCheck<Status, TBlocklike> BlockBasedTable::PutDataBlockToCache(
rep_->create_context.Create(&block_holder, std::move(block_contents));
}
// Insert compressed block into compressed block cache.
// Release the hold on the compressed cache entry immediately.
if (block_cache_compressed && block_comp_type != kNoCompression &&
block_contents.own_bytes()) {
assert(block_contents.has_trailer);
assert(!cache_key.empty());
// We cannot directly put block_contents because this could point to
// an object in the stack.
auto block_cont_for_comp_cache =
std::make_unique<BlockContents>(std::move(block_contents));
size_t charge = block_cont_for_comp_cache->ApproximateMemoryUsage();
s = block_cache_compressed.Insert(cache_key,
block_cont_for_comp_cache.get(), charge,
nullptr /*handle*/, Cache::Priority::LOW);
if (s.ok()) {
// Cache took ownership
block_cont_for_comp_cache.release();
RecordTick(statistics, BLOCK_CACHE_COMPRESSED_ADD);
} else {
RecordTick(statistics, BLOCK_CACHE_COMPRESSED_ADD_FAILURES);
}
}
// insert into uncompressed block cache
if (block_cache && block_holder->own_bytes()) {
size_t charge = block_holder->ApproximateMemoryUsage();
@@ -1451,6 +1541,8 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
const bool no_io = (ro.read_tier == kBlockCacheTier);
BlockCacheInterface<TBlocklike> block_cache{
rep_->table_options.block_cache.get()};
CompressedBlockCacheInterface block_cache_compressed{
rep_->table_options.block_cache_compressed.get()};
// First, try to get the block from the cache
//
@@ -1459,13 +1551,14 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
CacheKey key_data;
Slice key;
bool is_cache_hit = false;
if (block_cache) {
if (block_cache || block_cache_compressed) {
// create key for block cache
key_data = GetCacheKey(rep_->base_cache_key, handle);
key = key_data.AsSlice();
if (!contents) {
s = GetDataBlockFromCache(key, block_cache, out_parsed_block, wait,
s = GetDataBlockFromCache(key, block_cache, block_cache_compressed, ro,
out_parsed_block, uncompression_dict, wait,
get_context);
// Value could still be null at this point, so check the cache handle
// and update the read pattern for prefetching
@@ -1494,7 +1587,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
TBlocklike::kBlockType != BlockType::kFilter &&
TBlocklike::kBlockType != BlockType::kCompressionDictionary &&
rep_->blocks_maybe_compressed;
const bool do_uncompress = maybe_compressed;
const bool do_uncompress = maybe_compressed && !block_cache_compressed;
CompressionType contents_comp_type;
// Maybe serialized or uncompressed
BlockContents tmp_contents;
@@ -1508,7 +1601,7 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
TBlocklike::kBlockType, uncompression_dict,
rep_->persistent_cache_options,
GetMemoryAllocator(rep_->table_options),
/*allocator=*/nullptr);
GetMemoryAllocatorForCompressedBlock(rep_->table_options));
// If prefetch_buffer is not allocated, it will fallback to synchronous
// reading of block contents.
@@ -1544,8 +1637,8 @@ BlockBasedTable::MaybeReadBlockAndLoadToCache(
// If filling cache is allowed and a cache is configured, try to put the
// block to the cache.
s = PutDataBlockToCache(
key, block_cache, out_parsed_block, std::move(*contents),
contents_comp_type, uncompression_dict,
key, block_cache, block_cache_compressed, out_parsed_block,
std::move(*contents), contents_comp_type, uncompression_dict,
GetMemoryAllocator(rep_->table_options), get_context);
}
}
+6 -2
View File
@@ -379,7 +379,8 @@ class BlockBasedTable : public TableReader {
IndexBlockIter* input_iter, GetContext* get_context,
BlockCacheLookupContext* lookup_context) const;
// Read block cache from block caches (if set): block_cache.
// Read block cache from block caches (if set): block_cache and
// block_cache_compressed.
// On success, Status::OK with be returned and @block will be populated with
// pointer to the block as well as its block handle.
// @param uncompression_dict Data for presetting the compression library's
@@ -387,7 +388,9 @@ class BlockBasedTable : public TableReader {
template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> GetDataBlockFromCache(
const Slice& cache_key, BlockCacheInterface<TBlocklike> block_cache,
CachableEntry<TBlocklike>* block, const bool wait,
CompressedBlockCacheInterface block_cache_compressed,
const ReadOptions& read_options, CachableEntry<TBlocklike>* block,
const UncompressionDict& uncompression_dict, const bool wait,
GetContext* get_context) const;
// Put a maybe compressed block to the corresponding block caches.
@@ -403,6 +406,7 @@ class BlockBasedTable : public TableReader {
template <typename TBlocklike>
WithBlocklikeCheck<Status, TBlocklike> PutDataBlockToCache(
const Slice& cache_key, BlockCacheInterface<TBlocklike> block_cache,
CompressedBlockCacheInterface block_cache_compressed,
CachableEntry<TBlocklike>* cached_block, BlockContents&& block_contents,
CompressionType block_comp_type,
const UncompressionDict& uncompression_dict,
@@ -244,7 +244,9 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::RetrieveMultipleBlocks)
// heap buffer or there is no cache at all.
CompressionType compression_type =
GetBlockCompressionType(serialized_block);
if (use_shared_buffer && compression_type == kNoCompression) {
if (use_shared_buffer && (compression_type == kNoCompression ||
(compression_type != kNoCompression &&
rep_->table_options.block_cache_compressed))) {
Slice serialized =
Slice(req.result.data() + req_offset, BlockSizeWithTrailer(handle));
serialized_block = BlockContents(
@@ -521,6 +523,7 @@ DEFINE_SYNC_AND_ASYNC(void, BlockBasedTable::MultiGet)
// 3. If blocks are compressed and no compressed block cache, use
// stack buf
if (!rep_->file->use_direct_io() &&
rep_->table_options.block_cache_compressed == nullptr &&
rep_->blocks_maybe_compressed) {
if (total_len <= kMultiGetReadStackBufSize) {
scratch = stack_buf;
+4
View File
@@ -103,6 +103,10 @@ struct BlockCreateContext : public Cache::CreateContext {
BlockContents&& block);
};
// Convenient cache interface to use with block_cache_compressed
using CompressedBlockCacheInterface =
BasicTypedCacheInterface<BlockContents, CacheEntryRole::kOtherBlock>;
// Convenient cache interface to use for block_cache, with support for
// SecondaryCache.
template <typename TBlocklike>
+1 -1
View File
@@ -13,7 +13,7 @@
#include <type_traits>
#include "port/likely.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/cleanable.h"
namespace ROCKSDB_NAMESPACE {
+8 -1
View File
@@ -8,7 +8,7 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#pragma once
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/table.h"
namespace ROCKSDB_NAMESPACE {
@@ -22,6 +22,13 @@ inline MemoryAllocator* GetMemoryAllocator(
: nullptr;
}
inline MemoryAllocator* GetMemoryAllocatorForCompressedBlock(
const BlockBasedTableOptions& table_options) {
return table_options.block_cache_compressed.get()
? table_options.block_cache_compressed->memory_allocator()
: nullptr;
}
// Assumes block has a trailer as in format.h. file_name and offset provided
// for generating a diagnostic message in returned status.
extern Status VerifyBlockChecksum(ChecksumType type, const char* data,
+2 -5
View File
@@ -4022,11 +4022,7 @@ class Benchmark {
DBOptions db_opts;
std::vector<ColumnFamilyDescriptor> cf_descs;
if (FLAGS_options_file != "") {
ConfigOptions config_opts;
config_opts.ignore_unknown_options = false;
config_opts.input_strings_escaped = true;
config_opts.env = FLAGS_env;
auto s = LoadOptionsFromFile(config_opts, FLAGS_options_file, &db_opts,
auto s = LoadOptionsFromFile(FLAGS_options_file, FLAGS_env, &db_opts,
&cf_descs);
db_opts.env = FLAGS_env;
if (s.ok()) {
@@ -4286,6 +4282,7 @@ class Benchmark {
{/*.charged = */ FLAGS_charge_blob_cache
? CacheEntryRoleOptions::Decision::kEnabled
: CacheEntryRoleOptions::Decision::kDisabled}});
block_based_options.block_cache_compressed = compressed_cache_;
block_based_options.block_size = FLAGS_block_size;
block_based_options.block_restart_interval = FLAGS_block_restart_interval;
block_based_options.index_block_restart_interval =
+4 -12
View File
@@ -87,13 +87,9 @@ class DBBenchTest : public testing::Test {
void VerifyOptions(const Options& opt) {
DBOptions loaded_db_opts;
ConfigOptions config_opts;
config_opts.ignore_unknown_options = false;
config_opts.input_strings_escaped = true;
config_opts.env = Env::Default();
std::vector<ColumnFamilyDescriptor> cf_descs;
ASSERT_OK(
LoadLatestOptions(config_opts, db_path_, &loaded_db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(db_path_, Env::Default(), &loaded_db_opts,
&cf_descs));
ConfigOptions exact;
exact.input_strings_escaped = false;
@@ -306,13 +302,9 @@ TEST_F(DBBenchTest, OptionsFileFromFile) {
ASSERT_OK(writable->Close());
DBOptions db_opt;
ConfigOptions config_opt;
config_opt.ignore_unknown_options = false;
config_opt.input_strings_escaped = true;
config_opt.env = Env::Default();
std::vector<ColumnFamilyDescriptor> cf_descs;
ASSERT_OK(
LoadOptionsFromFile(config_opt, kOptionsFileName, &db_opt, &cf_descs));
ASSERT_OK(LoadOptionsFromFile(kOptionsFileName, Env::Default(), &db_opt,
&cf_descs));
Options opt(db_opt, cf_descs[0].options);
opt.create_if_missing = true;
+1 -1
View File
@@ -9,7 +9,7 @@
#include "rocksdb/utilities/leveldb_options.h"
#include "rocksdb/advanced_cache.h"
#include "rocksdb/cache.h"
#include "rocksdb/comparator.h"
#include "rocksdb/env.h"
#include "rocksdb/filter_policy.h"
+1
View File
@@ -40,6 +40,7 @@ class MemoryTest : public testing::Test {
const auto bbto = factory->GetOptions<BlockBasedTableOptions>();
if (bbto != nullptr) {
cache_set->insert(bbto->block_cache.get());
cache_set->insert(bbto->block_cache_compressed.get());
}
}
+40
View File
@@ -13,6 +13,20 @@
#include "table/block_based/block_based_table_factory.h"
namespace ROCKSDB_NAMESPACE {
Status LoadOptionsFromFile(const std::string& file_name, Env* env,
DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
bool ignore_unknown_options,
std::shared_ptr<Cache>* cache) {
ConfigOptions config_options;
config_options.ignore_unknown_options = ignore_unknown_options;
config_options.input_strings_escaped = true;
config_options.env = env;
return LoadOptionsFromFile(config_options, file_name, db_options, cf_descs,
cache);
}
Status LoadOptionsFromFile(const ConfigOptions& config_options,
const std::string& file_name, DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
@@ -75,6 +89,19 @@ Status GetLatestOptionsFileName(const std::string& dbpath, Env* env,
return Status::OK();
}
Status LoadLatestOptions(const std::string& dbpath, Env* env,
DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
bool ignore_unknown_options,
std::shared_ptr<Cache>* cache) {
ConfigOptions config_options;
config_options.ignore_unknown_options = ignore_unknown_options;
config_options.input_strings_escaped = true;
config_options.env = env;
return LoadLatestOptions(config_options, dbpath, db_options, cf_descs, cache);
}
Status LoadLatestOptions(const ConfigOptions& config_options,
const std::string& dbpath, DBOptions* db_options,
std::vector<ColumnFamilyDescriptor>* cf_descs,
@@ -89,6 +116,19 @@ Status LoadLatestOptions(const ConfigOptions& config_options,
db_options, cf_descs, cache);
}
Status CheckOptionsCompatibility(
const std::string& dbpath, Env* env, const DBOptions& db_options,
const std::vector<ColumnFamilyDescriptor>& cf_descs,
bool ignore_unknown_options) {
ConfigOptions config_options(db_options);
config_options.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
config_options.ignore_unknown_options = ignore_unknown_options;
config_options.input_strings_escaped = true;
config_options.env = env;
return CheckOptionsCompatibility(config_options, dbpath, db_options,
cf_descs);
}
Status CheckOptionsCompatibility(
const ConfigOptions& config_options, const std::string& dbpath,
const DBOptions& db_options,
+28 -25
View File
@@ -62,11 +62,7 @@ TEST_F(OptionsUtilTest, SaveAndLoad) {
DBOptions loaded_db_opt;
std::vector<ColumnFamilyDescriptor> loaded_cf_descs;
ConfigOptions config_options;
config_options.ignore_unknown_options = false;
config_options.input_strings_escaped = true;
config_options.env = env_.get();
ASSERT_OK(LoadOptionsFromFile(config_options, kFileName, &loaded_db_opt,
ASSERT_OK(LoadOptionsFromFile(kFileName, env_.get(), &loaded_db_opt,
&loaded_cf_descs));
ConfigOptions exact;
exact.sanity_level = ConfigOptions::kSanityLevelExactMatch;
@@ -145,6 +141,19 @@ TEST_F(OptionsUtilTest, SaveAndLoadWithCacheCheck) {
ASSERT_EQ(loaded_bbt_opt->block_cache.get(), cache.get());
}
}
// Test the old interface
ASSERT_OK(LoadOptionsFromFile(kFileName, env_.get(), &loaded_db_opt,
&loaded_cf_descs, false, &cache));
for (size_t i = 0; i < loaded_cf_descs.size(); i++) {
auto* loaded_bbt_opt =
loaded_cf_descs[i]
.options.table_factory->GetOptions<BlockBasedTableOptions>();
// Expect the same cache will be loaded
if (loaded_bbt_opt != nullptr) {
ASSERT_EQ(loaded_bbt_opt->block_cache.get(), cache.get());
}
}
ASSERT_OK(DestroyDB(dbname_, Options(loaded_db_opt, cf_opts[0])));
}
@@ -376,10 +385,13 @@ TEST_F(OptionsUtilTest, LatestOptionsNotFound) {
ASSERT_TRUE(s.IsNotFound());
ASSERT_TRUE(s.IsPathNotFound());
s = LoadLatestOptions(config_opts, dbname_, &options, &cf_descs);
s = LoadLatestOptions(dbname_, options.env, &options, &cf_descs);
ASSERT_TRUE(s.IsNotFound());
ASSERT_TRUE(s.IsPathNotFound());
s = LoadLatestOptions(config_opts, dbname_, &options, &cf_descs);
ASSERT_TRUE(s.IsPathNotFound());
s = GetLatestOptionsFileName(dbname_, options.env, &options_file_name);
ASSERT_TRUE(s.IsNotFound());
ASSERT_TRUE(s.IsPathNotFound());
@@ -391,7 +403,7 @@ TEST_F(OptionsUtilTest, LatestOptionsNotFound) {
ASSERT_TRUE(s.IsNotFound());
ASSERT_TRUE(s.IsPathNotFound());
s = LoadLatestOptions(config_opts, dbname_, &options, &cf_descs);
s = LoadLatestOptions(dbname_, options.env, &options, &cf_descs);
ASSERT_TRUE(s.IsNotFound());
ASSERT_TRUE(s.IsPathNotFound());
@@ -628,9 +640,6 @@ TEST_F(OptionsUtilTest, RenameDatabaseDirectory) {
DBOptions db_opts;
std::vector<ColumnFamilyDescriptor> cf_descs;
std::vector<ColumnFamilyHandle*> handles;
ConfigOptions ignore_opts;
ignore_opts.ignore_unknown_options = false;
ignore_opts.env = options.env;
options.create_if_missing = true;
@@ -641,7 +650,7 @@ TEST_F(OptionsUtilTest, RenameDatabaseDirectory) {
auto new_dbname = dbname_ + "_2";
ASSERT_OK(options.env->RenameFile(dbname_, new_dbname));
ASSERT_OK(LoadLatestOptions(ignore_opts, new_dbname, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(new_dbname, options.env, &db_opts, &cf_descs));
ASSERT_EQ(cf_descs.size(), 1U);
db_opts.create_if_missing = false;
@@ -665,23 +674,20 @@ TEST_F(OptionsUtilTest, WalDirSettings) {
DBOptions db_opts;
std::vector<ColumnFamilyDescriptor> cf_descs;
std::vector<ColumnFamilyHandle*> handles;
ConfigOptions ignore_opts;
ignore_opts.ignore_unknown_options = false;
ignore_opts.env = options.env;
options.create_if_missing = true;
// Open a DB with no wal dir set. The wal_dir should stay empty
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, "");
// Open a DB with wal_dir == dbname. The wal_dir should be set to empty
options.wal_dir = dbname_;
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, "");
// Open a DB with no wal_dir but a db_path==dbname_. The wal_dir should be
@@ -690,7 +696,7 @@ TEST_F(OptionsUtilTest, WalDirSettings) {
options.db_paths.emplace_back(dbname_, std::numeric_limits<uint64_t>::max());
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, "");
// Open a DB with no wal_dir==dbname_ and db_path==dbname_. The wal_dir
@@ -699,7 +705,7 @@ TEST_F(OptionsUtilTest, WalDirSettings) {
options.db_paths.emplace_back(dbname_, std::numeric_limits<uint64_t>::max());
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, "");
ASSERT_OK(DestroyDB(dbname_, options));
@@ -710,7 +716,7 @@ TEST_F(OptionsUtilTest, WalDirSettings) {
std::numeric_limits<uint64_t>::max());
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, dbname_);
ASSERT_OK(DestroyDB(dbname_, options));
@@ -719,7 +725,7 @@ TEST_F(OptionsUtilTest, WalDirSettings) {
options.db_paths.clear();
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, dbname_ + "/wal");
ASSERT_OK(DestroyDB(dbname_, options));
}
@@ -730,9 +736,6 @@ TEST_F(OptionsUtilTest, WalDirInOptins) {
DBOptions db_opts;
std::vector<ColumnFamilyDescriptor> cf_descs;
std::vector<ColumnFamilyHandle*> handles;
ConfigOptions ignore_opts;
ignore_opts.ignore_unknown_options = false;
ignore_opts.env = options.env;
// Store an options file with wal_dir=dbname_ and make sure it still loads
// when the input wal_dir is empty
@@ -746,12 +749,12 @@ TEST_F(OptionsUtilTest, WalDirInOptins) {
ASSERT_OK(PersistRocksDBOptions(options, {"default"}, {options},
dbname_ + "/" + options_file,
options.env->GetFileSystem().get()));
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, dbname_);
options.wal_dir = "";
ASSERT_OK(DB::Open(options, dbname_, &db));
delete db;
ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
ASSERT_OK(LoadLatestOptions(dbname_, options.env, &db_opts, &cf_descs));
ASSERT_EQ(db_opts.wal_dir, "");
}
} // namespace ROCKSDB_NAMESPACE
@@ -295,7 +295,7 @@ PersistentCacheDBTest::PersistentCacheDBTest()
// test template
void PersistentCacheDBTest::RunTest(
const std::function<std::shared_ptr<PersistentCacheTier>(bool)>& new_pcache,
const size_t max_keys = 100 * 1024, const size_t max_usecase = 3) {
const size_t max_keys = 100 * 1024, const size_t max_usecase = 5) {
// number of insertion interations
int num_iter = static_cast<int>(max_keys * kStressFactor);
@@ -319,21 +319,43 @@ void PersistentCacheDBTest::RunTest(
pcache = new_pcache(/*is_compressed=*/true);
table_options.persistent_cache = pcache;
table_options.block_cache = NewLRUCache(size_max);
table_options.block_cache_compressed = nullptr;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
case 1:
// page cache, block cache, compressed cache
pcache = new_pcache(/*is_compressed=*/true);
table_options.persistent_cache = pcache;
table_options.block_cache = NewLRUCache(size_max);
table_options.block_cache_compressed = NewLRUCache(size_max);
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
case 2:
// page cache, block cache, compressed cache + KNoCompression
// both block cache and compressed cache, but DB is not compressed
// also, make block cache sizes bigger, to trigger block cache hits
pcache = new_pcache(/*is_compressed=*/true);
table_options.persistent_cache = pcache;
table_options.block_cache = NewLRUCache(size_max);
table_options.block_cache_compressed = NewLRUCache(size_max);
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
options.compression = kNoCompression;
break;
case 3:
// page cache, no block cache, no compressed cache
pcache = new_pcache(/*is_compressed=*/false);
table_options.persistent_cache = pcache;
table_options.block_cache = nullptr;
table_options.block_cache_compressed = nullptr;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
case 2:
case 4:
// page cache, no block cache, no compressed cache
// Page cache caches compressed blocks
pcache = new_pcache(/*is_compressed=*/true);
table_options.persistent_cache = pcache;
table_options.block_cache = nullptr;
table_options.block_cache_compressed = nullptr;
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
break;
default:
@@ -349,6 +371,10 @@ void PersistentCacheDBTest::RunTest(
Verify(num_iter, values);
auto block_miss = TestGetTickerCount(options, BLOCK_CACHE_MISS);
auto compressed_block_hit =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_HIT);
auto compressed_block_miss =
TestGetTickerCount(options, BLOCK_CACHE_COMPRESSED_MISS);
auto page_hit = TestGetTickerCount(options, PERSISTENT_CACHE_HIT);
auto page_miss = TestGetTickerCount(options, PERSISTENT_CACHE_MISS);
@@ -359,12 +385,31 @@ void PersistentCacheDBTest::RunTest(
ASSERT_GT(page_miss, 0);
ASSERT_GT(page_hit, 0);
ASSERT_GT(block_miss, 0);
ASSERT_EQ(compressed_block_miss, 0);
ASSERT_EQ(compressed_block_hit, 0);
break;
case 1:
// page cache, block cache, compressed cache
ASSERT_GT(page_miss, 0);
ASSERT_GT(block_miss, 0);
ASSERT_GT(compressed_block_miss, 0);
break;
case 2:
// page cache, block cache, compressed cache + KNoCompression
ASSERT_GT(page_miss, 0);
ASSERT_GT(page_hit, 0);
ASSERT_GT(block_miss, 0);
ASSERT_GT(compressed_block_miss, 0);
// remember kNoCompression
ASSERT_EQ(compressed_block_hit, 0);
break;
case 3:
case 4:
// page cache, no block cache, no compressed cache
ASSERT_GT(page_miss, 0);
ASSERT_GT(page_hit, 0);
ASSERT_EQ(compressed_block_hit, 0);
ASSERT_EQ(compressed_block_miss, 0);
break;
default:
FAIL();
+25 -26
View File
@@ -151,22 +151,20 @@ class SimCacheImpl : public SimCache {
// capacity for real cache (ShardedLRUCache)
// test_capacity for key only cache
SimCacheImpl(std::shared_ptr<Cache> sim_cache, std::shared_ptr<Cache> cache)
: SimCache(cache),
: cache_(cache),
key_only_cache_(sim_cache),
miss_times_(0),
hit_times_(0),
stats_(nullptr) {}
~SimCacheImpl() override {}
const char* Name() const override { return "SimCache"; }
void SetCapacity(size_t capacity) override { target_->SetCapacity(capacity); }
void SetCapacity(size_t capacity) override { cache_->SetCapacity(capacity); }
void SetStrictCapacityLimit(bool strict_capacity_limit) override {
target_->SetStrictCapacityLimit(strict_capacity_limit);
cache_->SetStrictCapacityLimit(strict_capacity_limit);
}
using Cache::Insert;
Status Insert(const Slice& key, Cache::ObjectPtr value,
const CacheItemHelper* helper, size_t charge, Handle** handle,
Priority priority) override {
@@ -186,10 +184,10 @@ class SimCacheImpl : public SimCache {
}
cache_activity_logger_.ReportAdd(key, charge);
if (!target_) {
if (!cache_) {
return Status::OK();
}
return target_->Insert(key, value, helper, charge, handle, priority);
return cache_->Insert(key, value, helper, charge, handle, priority);
}
Handle* Lookup(const Slice& key, const CacheItemHelper* helper,
@@ -197,54 +195,54 @@ class SimCacheImpl : public SimCache {
Priority priority = Priority::LOW, bool wait = true,
Statistics* stats = nullptr) override {
HandleLookup(key, stats);
if (!target_) {
if (!cache_) {
return nullptr;
}
return target_->Lookup(key, helper, create_context, priority, wait, stats);
return cache_->Lookup(key, helper, create_context, priority, wait, stats);
}
bool Ref(Handle* handle) override { return target_->Ref(handle); }
bool Ref(Handle* handle) override { return cache_->Ref(handle); }
using Cache::Release;
bool Release(Handle* handle, bool erase_if_last_ref = false) override {
return target_->Release(handle, erase_if_last_ref);
return cache_->Release(handle, erase_if_last_ref);
}
void Erase(const Slice& key) override {
target_->Erase(key);
cache_->Erase(key);
key_only_cache_->Erase(key);
}
Cache::ObjectPtr Value(Handle* handle) override {
return target_->Value(handle);
return cache_->Value(handle);
}
uint64_t NewId() override { return target_->NewId(); }
uint64_t NewId() override { return cache_->NewId(); }
size_t GetCapacity() const override { return target_->GetCapacity(); }
size_t GetCapacity() const override { return cache_->GetCapacity(); }
bool HasStrictCapacityLimit() const override {
return target_->HasStrictCapacityLimit();
return cache_->HasStrictCapacityLimit();
}
size_t GetUsage() const override { return target_->GetUsage(); }
size_t GetUsage() const override { return cache_->GetUsage(); }
size_t GetUsage(Handle* handle) const override {
return target_->GetUsage(handle);
return cache_->GetUsage(handle);
}
size_t GetCharge(Handle* handle) const override {
return target_->GetCharge(handle);
return cache_->GetCharge(handle);
}
const CacheItemHelper* GetCacheItemHelper(Handle* handle) const override {
return target_->GetCacheItemHelper(handle);
return cache_->GetCacheItemHelper(handle);
}
size_t GetPinnedUsage() const override { return target_->GetPinnedUsage(); }
size_t GetPinnedUsage() const override { return cache_->GetPinnedUsage(); }
void DisownData() override {
target_->DisownData();
cache_->DisownData();
key_only_cache_->DisownData();
}
@@ -252,11 +250,11 @@ class SimCacheImpl : public SimCache {
const std::function<void(const Slice& key, ObjectPtr value, size_t charge,
const CacheItemHelper* helper)>& callback,
const ApplyToAllEntriesOptions& opts) override {
target_->ApplyToAllEntries(callback, opts);
cache_->ApplyToAllEntries(callback, opts);
}
void EraseUnRefEntries() override {
target_->EraseUnRefEntries();
cache_->EraseUnRefEntries();
key_only_cache_->EraseUnRefEntries();
}
@@ -297,7 +295,7 @@ class SimCacheImpl : public SimCache {
std::string GetPrintableOptions() const override {
std::ostringstream oss;
oss << " cache_options:" << std::endl;
oss << target_->GetPrintableOptions();
oss << cache_->GetPrintableOptions();
oss << " sim_cache_options:" << std::endl;
oss << key_only_cache_->GetPrintableOptions();
return oss.str();
@@ -316,6 +314,7 @@ class SimCacheImpl : public SimCache {
}
private:
std::shared_ptr<Cache> cache_;
std::shared_ptr<Cache> key_only_cache_;
std::atomic<uint64_t> miss_times_;
std::atomic<uint64_t> hit_times_;