std::unique_ptr<SecondaryCacheResultHandle> CompressedSecondaryCache::Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool /*wait*/, bool advise_erase,
- bool& kept_in_sec_cache) {
+ Statistics* stats, bool& kept_in_sec_cache) {
assert(helper);
// This is a minor optimization. Its ok to skip it in TSAN in order to
// avoid a false positive.
void* handle_value = cache_->Value(lru_handle);
if (handle_value == nullptr) {
cache_->Release(lru_handle, /*erase_if_last_ref=*/false);
+ RecordTick(stats, COMPRESSED_SECONDARY_CACHE_DUMMY_HITS);
return nullptr;
}
cache_->Release(lru_handle, /*erase_if_last_ref=*/false);
}
handle.reset(new CompressedSecondaryCacheResultHandle(value, charge));
+ RecordTick(stats, COMPRESSED_SECONDARY_CACHE_HITS);
return handle;
}
std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool /*wait*/, bool advise_erase,
- bool& kept_in_sec_cache) override;
+ Statistics* stats, bool& kept_in_sec_cache) override;
bool SupportForceErase() const override { return true; }
// Lookup an non-existent key.
std::unique_ptr<SecondaryCacheResultHandle> handle0 =
sec_cache->Lookup(key0, GetHelper(), this, true, /*advise_erase=*/true,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle0, nullptr);
Random rnd(301);
std::unique_ptr<SecondaryCacheResultHandle> handle1_1 =
sec_cache->Lookup(key1, GetHelper(), this, true, /*advise_erase=*/false,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle1_1, nullptr);
// Insert and Lookup the item k1 for the second time and advise erasing it.
std::unique_ptr<SecondaryCacheResultHandle> handle1_2 =
sec_cache->Lookup(key1, GetHelper(), this, true, /*advise_erase=*/true,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_NE(handle1_2, nullptr);
ASSERT_FALSE(kept_in_sec_cache);
if (sec_cache_is_compressed) {
// Lookup the item k1 again.
std::unique_ptr<SecondaryCacheResultHandle> handle1_3 =
sec_cache->Lookup(key1, GetHelper(), this, true, /*advise_erase=*/true,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle1_3, nullptr);
// Insert and Lookup the item k2.
ASSERT_EQ(get_perf_context()->compressed_sec_cache_insert_dummy_count, 2);
std::unique_ptr<SecondaryCacheResultHandle> handle2_1 =
sec_cache->Lookup(key2, GetHelper(), this, true, /*advise_erase=*/false,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle2_1, nullptr);
ASSERT_OK(sec_cache->Insert(key2, &item2, GetHelper(), false));
}
std::unique_ptr<SecondaryCacheResultHandle> handle2_2 =
sec_cache->Lookup(key2, GetHelper(), this, true, /*advise_erase=*/false,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_NE(handle2_2, nullptr);
std::unique_ptr<TestItem> val2 =
std::unique_ptr<TestItem>(static_cast<TestItem*>(handle2_2->Value()));
bool kept_in_sec_cache{false};
std::unique_ptr<SecondaryCacheResultHandle> handle1 =
sec_cache->Lookup(key1, GetHelper(), this, true, /*advise_erase=*/false,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle1, nullptr);
// Insert k2 and k1 is evicted.
ASSERT_OK(sec_cache->Insert(key2, &item2, GetHelper(), false));
std::unique_ptr<SecondaryCacheResultHandle> handle2 =
sec_cache->Lookup(key2, GetHelper(), this, true, /*advise_erase=*/false,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_NE(handle2, nullptr);
std::unique_ptr<TestItem> val2 =
std::unique_ptr<TestItem>(static_cast<TestItem*>(handle2->Value()));
std::unique_ptr<SecondaryCacheResultHandle> handle1_1 =
sec_cache->Lookup(key1, GetHelper(), this, true, /*advise_erase=*/false,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle1_1, nullptr);
// Create Fails.
SetFailCreate(true);
std::unique_ptr<SecondaryCacheResultHandle> handle2_1 =
sec_cache->Lookup(key2, GetHelper(), this, true, /*advise_erase=*/true,
- kept_in_sec_cache);
+ /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_EQ(handle2_1, nullptr);
// Save Fails.
ASSERT_EQ(get_perf_context()->compressed_sec_cache_insert_real_count, 1U);
bool kept_in_sec_cache{true};
- std::unique_ptr<SecondaryCacheResultHandle> handle =
- sec_cache->Lookup(ith_key, GetHelper(role), this, true,
- /*advise_erase=*/true, kept_in_sec_cache);
+ std::unique_ptr<SecondaryCacheResultHandle> handle = sec_cache->Lookup(
+ ith_key, GetHelper(role), this, true,
+ /*advise_erase=*/true, /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_NE(handle, nullptr);
// Lookup returns the right data
std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool /*wait*/,
- bool /*advise_erase*/, bool& kept_in_sec_cache) override {
+ bool /*advise_erase*/, Statistics* /*stats*/,
+ bool& kept_in_sec_cache) override {
std::string key_str = key.ToString();
TEST_SYNC_POINT_CALLBACK("TestSecondaryCache::Lookup", &key_str);
bool kept_in_sec_cache = false;
std::unique_ptr<SecondaryCacheResultHandle> secondary_handle =
secondary_cache_->Lookup(key, helper, create_context, /*wait*/ true,
- found_dummy_entry, /*out*/ kept_in_sec_cache);
+ found_dummy_entry, stats,
+ /*out*/ kept_in_sec_cache);
if (secondary_handle) {
result = Promote(std::move(secondary_handle), key, helper, priority,
stats, found_dummy_entry, kept_in_sec_cache);
assert(async_handle.result_handle == nullptr);
std::unique_ptr<SecondaryCacheResultHandle> secondary_handle =
- secondary_cache_->Lookup(async_handle.key, async_handle.helper,
- async_handle.create_context, /*wait*/ false,
- async_handle.found_dummy_entry,
- /*out*/ async_handle.kept_in_sec_cache);
+ secondary_cache_->Lookup(
+ async_handle.key, async_handle.helper, async_handle.create_context,
+ /*wait*/ false, async_handle.found_dummy_entry, async_handle.stats,
+ /*out*/ async_handle.kept_in_sec_cache);
if (secondary_handle) {
// TODO with stacked secondaries: Check & process if already ready?
async_handle.pending_handle = secondary_handle.release();
#include "cache/tiered_secondary_cache.h"
+#include "monitoring/statistics_impl.h"
+
namespace ROCKSDB_NAMESPACE {
// Creation callback for use in the lookup path. It calls the upper layer
// TODO: Don't hardcode the source
context->comp_sec_cache->InsertSaved(*context->key, data, type, source)
.PermitUncheckedError();
+ RecordTick(context->stats, COMPRESSED_SECONDARY_CACHE_PROMOTIONS);
+ } else {
+ RecordTick(context->stats, COMPRESSED_SECONDARY_CACHE_PROMOTION_SKIPS);
}
// Primary cache will accept the object, so call its helper to create
// the object
std::unique_ptr<SecondaryCacheResultHandle> TieredSecondaryCache::Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool wait, bool advise_erase,
- bool& kept_in_sec_cache) {
+ Statistics* stats, bool& kept_in_sec_cache) {
bool dummy = false;
std::unique_ptr<SecondaryCacheResultHandle> result =
- target()->Lookup(key, helper, create_context, wait, advise_erase,
+ target()->Lookup(key, helper, create_context, wait, advise_erase, stats,
/*kept_in_sec_cache=*/dummy);
// We never want the item to spill back into the secondary cache
kept_in_sec_cache = true;
ctx.helper = helper;
ctx.inner_ctx = create_context;
ctx.comp_sec_cache = target();
+ ctx.stats = stats;
return nvm_sec_cache_->Lookup(key, outer_helper, &ctx, wait, advise_erase,
- kept_in_sec_cache);
+ stats, kept_in_sec_cache);
}
// If wait is false, i.e its an async lookup, we have to allocate a result
handle->ctx()->helper = helper;
handle->ctx()->inner_ctx = create_context;
handle->ctx()->comp_sec_cache = target();
- handle->SetInnerHandle(nvm_sec_cache_->Lookup(
- key, outer_helper, handle->ctx(), wait, advise_erase, kept_in_sec_cache));
+ handle->ctx()->stats = stats;
+ handle->SetInnerHandle(
+ nvm_sec_cache_->Lookup(key, outer_helper, handle->ctx(), wait,
+ advise_erase, stats, kept_in_sec_cache));
if (!handle->inner_handle()) {
handle.reset();
} else {
virtual std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool wait, bool advise_erase,
- bool& kept_in_sec_cache) override;
+ Statistics* stats, bool& kept_in_sec_cache) override;
virtual void WaitAll(
std::vector<SecondaryCacheResultHandle*> handles) override;
Cache::CreateContext* inner_ctx;
std::shared_ptr<SecondaryCacheResultHandle> inner_handle;
SecondaryCache* comp_sec_cache;
+ Statistics* stats;
};
class ResultHandle : public SecondaryCacheResultHandle {
std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool wait, bool /*advise_erase*/,
- bool& kept_in_sec_cache) override {
+ Statistics* /*stats*/, bool& kept_in_sec_cache) override {
std::string key_str = key.ToString();
TEST_SYNC_POINT_CALLBACK("TestSecondaryCache::Lookup", &key_str);
auto sec_handle0 = secondary_cache->Lookup(
key0, BlobSource::SharedCacheInterface::GetFullHelper(),
/*context*/ nullptr, true,
- /*advise_erase=*/true, kept_in_sec_cache);
+ /*advise_erase=*/true, /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_FALSE(kept_in_sec_cache);
ASSERT_NE(sec_handle0, nullptr);
ASSERT_TRUE(sec_handle0->IsReady());
auto sec_handle1 = secondary_cache->Lookup(
key1, BlobSource::SharedCacheInterface::GetFullHelper(),
/*context*/ nullptr, true,
- /*advise_erase=*/true, kept_in_sec_cache);
+ /*advise_erase=*/true, /*stats=*/nullptr, kept_in_sec_cache);
ASSERT_FALSE(kept_in_sec_cache);
ASSERT_EQ(sec_handle1, nullptr);
virtual std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool wait, bool advise_erase,
- bool& kept_in_sec_cache) = 0;
+ Statistics* stats, bool& kept_in_sec_cache) = 0;
// Indicate whether a handle can be erased in this secondary cache.
[[nodiscard]] virtual bool SupportForceErase() const = 0;
virtual std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool wait, bool advise_erase,
- bool& kept_in_sec_cache) override {
+ Statistics* stats, bool& kept_in_sec_cache) override {
return target()->Lookup(key, helper, create_context, wait, advise_erase,
- kept_in_sec_cache);
+ stats, kept_in_sec_cache);
}
virtual bool SupportForceErase() const override {
// Number of FS reads avoided due to scan prefetching
PREFETCH_HITS,
+ // Compressed secondary cache related stats
+ COMPRESSED_SECONDARY_CACHE_DUMMY_HITS,
+ COMPRESSED_SECONDARY_CACHE_HITS,
+ COMPRESSED_SECONDARY_CACHE_PROMOTIONS,
+ COMPRESSED_SECONDARY_CACHE_PROMOTION_SKIPS,
+
TICKER_ENUM_MAX
};
return -0x41;
case ROCKSDB_NAMESPACE::Tickers::PREFETCH_HITS:
return -0x42;
+ case ROCKSDB_NAMESPACE::Tickers::COMPRESSED_SECONDARY_CACHE_DUMMY_HITS:
+ return -0x43;
+ case ROCKSDB_NAMESPACE::Tickers::COMPRESSED_SECONDARY_CACHE_HITS:
+ return -0x44;
+ case ROCKSDB_NAMESPACE::Tickers::COMPRESSED_SECONDARY_CACHE_PROMOTIONS:
+ return -0x45;
+ case ROCKSDB_NAMESPACE::Tickers::
+ COMPRESSED_SECONDARY_CACHE_PROMOTION_SKIPS:
+ return -0x46;
case ROCKSDB_NAMESPACE::Tickers::TICKER_ENUM_MAX:
// 0x5F was the max value in the initial copy of tickers to Java.
// Since these values are exposed directly to Java clients, we keep
return ROCKSDB_NAMESPACE::Tickers::PREFETCH_BYTES_USEFUL;
case -0x42:
return ROCKSDB_NAMESPACE::Tickers::PREFETCH_HITS;
+ case -0x43:
+ return ROCKSDB_NAMESPACE::Tickers::
+ COMPRESSED_SECONDARY_CACHE_DUMMY_HITS;
+ case -0x44:
+ return ROCKSDB_NAMESPACE::Tickers::COMPRESSED_SECONDARY_CACHE_HITS;
+ case -0x45:
+ return ROCKSDB_NAMESPACE::Tickers::
+ COMPRESSED_SECONDARY_CACHE_PROMOTIONS;
+ case -0x46:
+ return ROCKSDB_NAMESPACE::Tickers::
+ COMPRESSED_SECONDARY_CACHE_PROMOTION_SKIPS;
case 0x5F:
// 0x5F was the max value in the initial copy of tickers to Java.
// Since these values are exposed directly to Java clients, we keep
{PREFETCH_BYTES, "rocksdb.prefetch.bytes"},
{PREFETCH_BYTES_USEFUL, "rocksdb.prefetch.bytes.useful"},
{PREFETCH_HITS, "rocksdb.prefetch.hits"},
+ {COMPRESSED_SECONDARY_CACHE_DUMMY_HITS,
+ "rocksdb.compressed.secondary.cache.dummy.hits"},
+ {COMPRESSED_SECONDARY_CACHE_HITS,
+ "rocksdb.compressed.secondary.cache.hits"},
+ {COMPRESSED_SECONDARY_CACHE_PROMOTIONS,
+ "rocksdb.compressed.secondary.cache.promotions"},
+ {COMPRESSED_SECONDARY_CACHE_PROMOTION_SKIPS,
+ "rocksdb.compressed.secondary.cache.promotion.skips"},
};
const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& /*key*/, const Cache::CacheItemHelper* /*helper*/,
Cache::CreateContext* /*create_context*/, bool /*wait*/,
- bool /*advise_erase*/, bool& kept_in_sec_cache) override {
+ bool /*advise_erase*/, Statistics* /*stats*/,
+ bool& kept_in_sec_cache) override {
kept_in_sec_cache = true;
return nullptr;
}
const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context,
bool wait, bool advise_erase,
+ Statistics* stats,
bool& kept_in_sec_cache) {
ErrorContext* ctx = GetErrorContext();
if (base_is_compressed_sec_cache_) {
return nullptr;
} else {
return base_->Lookup(key, helper, create_context, wait, advise_erase,
- kept_in_sec_cache);
+ stats, kept_in_sec_cache);
}
} else {
- std::unique_ptr<SecondaryCacheResultHandle> hdl = base_->Lookup(
- key, helper, create_context, wait, advise_erase, kept_in_sec_cache);
+ std::unique_ptr<SecondaryCacheResultHandle> hdl =
+ base_->Lookup(key, helper, create_context, wait, advise_erase, stats,
+ kept_in_sec_cache);
if (wait && ctx->rand.OneIn(prob_)) {
hdl.reset();
}
std::unique_ptr<SecondaryCacheResultHandle> Lookup(
const Slice& key, const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context, bool wait, bool advise_erase,
- bool& kept_in_sec_cache) override;
+ Statistics* stats, bool& kept_in_sec_cache) override;
bool SupportForceErase() const override { return base_->SupportForceErase(); }