4c9447d889
Summary: This is useful when we put the entries in the block cache for accounting purposes and do not expect it to be used after it is released. If the cache does not erase the item in such cases not only the performance of cache is negatively affected but the item's destructor not being called at the time of release might violate the assumptions about the lifetime of the object. The new change adds a force_erase option to the Release method and returns a boolean to indicate whehter the item is successfully deleted. Closes https://github.com/facebook/rocksdb/pull/2180 Differential Revision: D4916032 Pulled By: maysamyabandeh fbshipit-source-id: 94409a346069923cac9de8e57adc313b4ed46f28
185 lines
6.1 KiB
C++
185 lines
6.1 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
#include "rocksdb/utilities/sim_cache.h"
|
|
#include <atomic>
|
|
#include "monitoring/statistics.h"
|
|
#include "port/port.h"
|
|
|
|
namespace rocksdb {
|
|
|
|
namespace {
|
|
// SimCacheImpl definition
|
|
class SimCacheImpl : public SimCache {
|
|
public:
|
|
// capacity for real cache (ShardedLRUCache)
|
|
// test_capacity for key only cache
|
|
SimCacheImpl(std::shared_ptr<Cache> cache, size_t sim_capacity,
|
|
int num_shard_bits)
|
|
: cache_(cache),
|
|
key_only_cache_(NewLRUCache(sim_capacity, num_shard_bits)),
|
|
miss_times_(0),
|
|
hit_times_(0) {}
|
|
|
|
virtual ~SimCacheImpl() {}
|
|
virtual void SetCapacity(size_t capacity) override {
|
|
cache_->SetCapacity(capacity);
|
|
}
|
|
|
|
virtual void SetStrictCapacityLimit(bool strict_capacity_limit) override {
|
|
cache_->SetStrictCapacityLimit(strict_capacity_limit);
|
|
}
|
|
|
|
virtual Status Insert(const Slice& key, void* value, size_t charge,
|
|
void (*deleter)(const Slice& key, void* value),
|
|
Handle** handle, Priority priority) override {
|
|
// The handle and value passed in are for real cache, so we pass nullptr
|
|
// to key_only_cache_ for both instead. Also, the deleter function pointer
|
|
// will be called by user to perform some external operation which should
|
|
// be applied only once. Thus key_only_cache accepts an empty function.
|
|
// *Lambda function without capture can be assgined to a function pointer
|
|
Handle* h = key_only_cache_->Lookup(key);
|
|
if (h == nullptr) {
|
|
key_only_cache_->Insert(key, nullptr, charge,
|
|
[](const Slice& k, void* v) {}, nullptr,
|
|
priority);
|
|
} else {
|
|
key_only_cache_->Release(h);
|
|
}
|
|
return cache_->Insert(key, value, charge, deleter, handle, priority);
|
|
}
|
|
|
|
virtual Handle* Lookup(const Slice& key, Statistics* stats) override {
|
|
Handle* h = key_only_cache_->Lookup(key);
|
|
if (h != nullptr) {
|
|
key_only_cache_->Release(h);
|
|
inc_hit_counter();
|
|
RecordTick(stats, SIM_BLOCK_CACHE_HIT);
|
|
} else {
|
|
inc_miss_counter();
|
|
RecordTick(stats, SIM_BLOCK_CACHE_MISS);
|
|
}
|
|
return cache_->Lookup(key, stats);
|
|
}
|
|
|
|
virtual bool Ref(Handle* handle) override { return cache_->Ref(handle); }
|
|
|
|
virtual bool Release(Handle* handle, bool force_erase = false) override {
|
|
return cache_->Release(handle, force_erase);
|
|
}
|
|
|
|
virtual void Erase(const Slice& key) override {
|
|
cache_->Erase(key);
|
|
key_only_cache_->Erase(key);
|
|
}
|
|
|
|
virtual void* Value(Handle* handle) override { return cache_->Value(handle); }
|
|
|
|
virtual uint64_t NewId() override { return cache_->NewId(); }
|
|
|
|
virtual size_t GetCapacity() const override { return cache_->GetCapacity(); }
|
|
|
|
virtual bool HasStrictCapacityLimit() const override {
|
|
return cache_->HasStrictCapacityLimit();
|
|
}
|
|
|
|
virtual size_t GetUsage() const override { return cache_->GetUsage(); }
|
|
|
|
virtual size_t GetUsage(Handle* handle) const override {
|
|
return cache_->GetUsage(handle);
|
|
}
|
|
|
|
virtual size_t GetPinnedUsage() const override {
|
|
return cache_->GetPinnedUsage();
|
|
}
|
|
|
|
virtual void DisownData() override {
|
|
cache_->DisownData();
|
|
key_only_cache_->DisownData();
|
|
}
|
|
|
|
virtual void ApplyToAllCacheEntries(void (*callback)(void*, size_t),
|
|
bool thread_safe) override {
|
|
// only apply to _cache since key_only_cache doesn't hold value
|
|
cache_->ApplyToAllCacheEntries(callback, thread_safe);
|
|
}
|
|
|
|
virtual void EraseUnRefEntries() override {
|
|
cache_->EraseUnRefEntries();
|
|
key_only_cache_->EraseUnRefEntries();
|
|
}
|
|
|
|
virtual size_t GetSimCapacity() const override {
|
|
return key_only_cache_->GetCapacity();
|
|
}
|
|
virtual size_t GetSimUsage() const override {
|
|
return key_only_cache_->GetUsage();
|
|
}
|
|
virtual void SetSimCapacity(size_t capacity) override {
|
|
key_only_cache_->SetCapacity(capacity);
|
|
}
|
|
|
|
virtual uint64_t get_miss_counter() const override {
|
|
return miss_times_.load(std::memory_order_relaxed);
|
|
}
|
|
|
|
virtual uint64_t get_hit_counter() const override {
|
|
return hit_times_.load(std::memory_order_relaxed);
|
|
}
|
|
|
|
virtual void reset_counter() override {
|
|
miss_times_.store(0, std::memory_order_relaxed);
|
|
hit_times_.store(0, std::memory_order_relaxed);
|
|
SetTickerCount(stats_, SIM_BLOCK_CACHE_HIT, 0);
|
|
SetTickerCount(stats_, SIM_BLOCK_CACHE_MISS, 0);
|
|
}
|
|
|
|
virtual std::string ToString() const override {
|
|
std::string res;
|
|
res.append("SimCache MISSes: " + std::to_string(get_miss_counter()) + "\n");
|
|
res.append("SimCache HITs: " + std::to_string(get_hit_counter()) + "\n");
|
|
char buff[350];
|
|
auto lookups = get_miss_counter() + get_hit_counter();
|
|
snprintf(buff, sizeof(buff), "SimCache HITRATE: %.2f%%\n",
|
|
(lookups == 0 ? 0 : get_hit_counter() * 100.0f / lookups));
|
|
res.append(buff);
|
|
return res;
|
|
}
|
|
|
|
virtual std::string GetPrintableOptions() const override {
|
|
std::string ret;
|
|
ret.reserve(20000);
|
|
ret.append(" cache_options:\n");
|
|
ret.append(cache_->GetPrintableOptions());
|
|
ret.append(" sim_cache_options:\n");
|
|
ret.append(key_only_cache_->GetPrintableOptions());
|
|
return ret;
|
|
}
|
|
|
|
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_;
|
|
Statistics* stats_;
|
|
void inc_miss_counter() {
|
|
miss_times_.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
void inc_hit_counter() { hit_times_.fetch_add(1, std::memory_order_relaxed); }
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
// For instrumentation purpose, use NewSimCache instead
|
|
std::shared_ptr<SimCache> NewSimCache(std::shared_ptr<Cache> cache,
|
|
size_t sim_capacity, int num_shard_bits) {
|
|
if (num_shard_bits >= 20) {
|
|
return nullptr; // the cache cannot be sharded into too many fine pieces
|
|
}
|
|
return std::make_shared<SimCacheImpl>(cache, sim_capacity, num_shard_bits);
|
|
}
|
|
|
|
} // end namespace rocksdb
|