mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 22:55:23 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e876b1b42f | |||
| ca38d391cb | |||
| fb261e5157 | |||
| fecd0eeb06 | |||
| 0771260c5d | |||
| 1518dff897 | |||
| 530612ba0a |
+1
-4
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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"
|
||||
|
||||
Vendored
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "rocksdb/advanced_cache.h"
|
||||
#include "rocksdb/cache.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
Vendored
+1
-1
@@ -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"
|
||||
|
||||
Vendored
+1
-1
@@ -8,7 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/advanced_cache.h"
|
||||
#include "rocksdb/cache.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
|
||||
Vendored
+37
@@ -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 */,
|
||||
|
||||
Vendored
+1
-1
@@ -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"
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -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 {
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "rocksdb/write_buffer_manager.h"
|
||||
|
||||
#include "rocksdb/advanced_cache.h"
|
||||
#include "test_util/testharness.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,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,
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user