rocksdb/utilities/fault_injection_secondary_cache.cc
anand76 a1743e85be Implement a allow cache hits admission policy for the compressed secondary cache (#11713)
Summary:
This PR implements a new admission policy for the compressed secondary cache, which includes the functionality of the existing policy, and also admits items evicted from the primary block cache with the hit bit set. Effectively, the new policy works as follows -
1. When an item is demoted from the primary cache without a hit, a placeholder is inserted in the compressed cache. A second demotion will insert the full entry.
2. When an item is promoted from the compressed cache to the primary cache for the first time, a placeholder is inserted in the primary. The second promotion inserts the full entry, while erasing it form the compressed cache.
3. If an item is demoted from the primary cache with the hit bit set, it is immediately inserted in the compressed secondary cache.
The ```TieredVolatileCacheOptions``` has been updated with a new option, ```adm_policy```, which allows the policy to be selected.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11713

Reviewed By: pdillinger

Differential Revision: D48444512

Pulled By: anand1976

fbshipit-source-id: b4cbf8c169a88097dff08e36e8bc4b3088de1492
2023-08-18 11:19:48 -07:00

137 lines
4.3 KiB
C++

// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// 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).
// This class implements a custom SecondaryCache that randomly injects an
// error status into Inserts/Lookups based on a specified probability.
#include "utilities/fault_injection_secondary_cache.h"
namespace ROCKSDB_NAMESPACE {
void FaultInjectionSecondaryCache::ResultHandle::UpdateHandleValue(
FaultInjectionSecondaryCache::ResultHandle* handle) {
ErrorContext* ctx = handle->cache_->GetErrorContext();
if (!ctx->rand.OneIn(handle->cache_->prob_)) {
handle->value_ = handle->base_->Value();
handle->size_ = handle->base_->Size();
}
handle->base_.reset();
}
bool FaultInjectionSecondaryCache::ResultHandle::IsReady() {
bool ready = true;
if (base_) {
ready = base_->IsReady();
if (ready) {
UpdateHandleValue(this);
}
}
return ready;
}
void FaultInjectionSecondaryCache::ResultHandle::Wait() {
base_->Wait();
UpdateHandleValue(this);
}
Cache::ObjectPtr FaultInjectionSecondaryCache::ResultHandle::Value() {
return value_;
}
size_t FaultInjectionSecondaryCache::ResultHandle::Size() { return size_; }
void FaultInjectionSecondaryCache::ResultHandle::WaitAll(
FaultInjectionSecondaryCache* cache,
std::vector<SecondaryCacheResultHandle*> handles) {
std::vector<SecondaryCacheResultHandle*> base_handles;
for (SecondaryCacheResultHandle* hdl : handles) {
FaultInjectionSecondaryCache::ResultHandle* handle =
static_cast<FaultInjectionSecondaryCache::ResultHandle*>(hdl);
if (!handle->base_) {
continue;
}
base_handles.emplace_back(handle->base_.get());
}
cache->base_->WaitAll(base_handles);
for (SecondaryCacheResultHandle* hdl : handles) {
FaultInjectionSecondaryCache::ResultHandle* handle =
static_cast<FaultInjectionSecondaryCache::ResultHandle*>(hdl);
if (handle->base_) {
UpdateHandleValue(handle);
}
}
}
FaultInjectionSecondaryCache::ErrorContext*
FaultInjectionSecondaryCache::GetErrorContext() {
ErrorContext* ctx = static_cast<ErrorContext*>(thread_local_error_->Get());
if (!ctx) {
ctx = new ErrorContext(seed_);
thread_local_error_->Reset(ctx);
}
return ctx;
}
Status FaultInjectionSecondaryCache::Insert(
const Slice& key, Cache::ObjectPtr value,
const Cache::CacheItemHelper* helper, bool force_insert) {
ErrorContext* ctx = GetErrorContext();
if (ctx->rand.OneIn(prob_)) {
return Status::IOError();
}
return base_->Insert(key, value, helper, force_insert);
}
std::unique_ptr<SecondaryCacheResultHandle>
FaultInjectionSecondaryCache::Lookup(const Slice& key,
const Cache::CacheItemHelper* helper,
Cache::CreateContext* create_context,
bool wait, bool advise_erase,
bool& kept_in_sec_cache) {
ErrorContext* ctx = GetErrorContext();
if (base_is_compressed_sec_cache_) {
if (ctx->rand.OneIn(prob_)) {
return nullptr;
} else {
return base_->Lookup(key, helper, create_context, wait, advise_erase,
kept_in_sec_cache);
}
} else {
std::unique_ptr<SecondaryCacheResultHandle> hdl = base_->Lookup(
key, helper, create_context, wait, advise_erase, kept_in_sec_cache);
if (wait && ctx->rand.OneIn(prob_)) {
hdl.reset();
}
return std::unique_ptr<FaultInjectionSecondaryCache::ResultHandle>(
new FaultInjectionSecondaryCache::ResultHandle(this, std::move(hdl)));
}
}
void FaultInjectionSecondaryCache::Erase(const Slice& key) {
base_->Erase(key);
}
void FaultInjectionSecondaryCache::WaitAll(
std::vector<SecondaryCacheResultHandle*> handles) {
if (base_is_compressed_sec_cache_) {
ErrorContext* ctx = GetErrorContext();
std::vector<SecondaryCacheResultHandle*> base_handles;
for (SecondaryCacheResultHandle* hdl : handles) {
if (ctx->rand.OneIn(prob_)) {
continue;
}
base_handles.push_back(hdl);
}
base_->WaitAll(base_handles);
} else {
FaultInjectionSecondaryCache::ResultHandle::WaitAll(this, handles);
}
}
} // namespace ROCKSDB_NAMESPACE