#ifndef ROCKSDB_LITE
#include "utilities/persistent_cache/volatile_tier_impl.h"
#include <string>
namespace
rocksdb {
void
VolatileCacheTier::DeleteCacheData(VolatileCacheTier::CacheData* data) {
assert
(data);
delete
data;
}
VolatileCacheTier::~VolatileCacheTier() { index_.Clear(&DeleteCacheData); }
PersistentCache::StatsType VolatileCacheTier::Stats() {
std::map<std::string,
double
> stat;
stat.insert({
"persistent_cache.volatile_cache.hits"
,
static_cast
<
double
>(stats_.cache_hits_)});
stat.insert({
"persistent_cache.volatile_cache.misses"
,
static_cast
<
double
>(stats_.cache_misses_)});
stat.insert({
"persistent_cache.volatile_cache.inserts"
,
static_cast
<
double
>(stats_.cache_inserts_)});
stat.insert({
"persistent_cache.volatile_cache.evicts"
,
static_cast
<
double
>(stats_.cache_evicts_)});
stat.insert({
"persistent_cache.volatile_cache.hit_pct"
,
static_cast
<
double
>(stats_.CacheHitPct())});
stat.insert({
"persistent_cache.volatile_cache.miss_pct"
,
static_cast
<
double
>(stats_.CacheMissPct())});
auto
out = PersistentCacheTier::Stats();
out.push_back(stat);
return
out;
}
Status VolatileCacheTier::Insert(
const
Slice& page_key,
const
char
* data,
const
size_t
size) {
assert
(data);
assert
(size);
size_ += size;
while
(size_ > max_size_) {
if
(!Evict()) {
assert
(size_ >= size);
size_ -= size;
return
Status::TryAgain(
"Unable to evict any data"
);
}
}
assert
(size_ >= size);
std::string key(page_key.data(), page_key.size());
std::string value(data, size);
std::unique_ptr<CacheData> cache_data(
new
CacheData(std::move(key), std::move(value)));
bool
ok = index_.Insert(cache_data.get());
if
(!ok) {
assert
(size_ >= size);
size_ -= size;
return
Status::TryAgain(
"key already exists in volatile cache"
);
}
cache_data.release();
stats_.cache_inserts_++;
return
Status::OK();
}
Status VolatileCacheTier::Lookup(
const
Slice& page_key,
std::unique_ptr<
char
[]>* result,
size_t
* size) {
CacheData key(std::move(page_key.ToString()));
CacheData* kv;
bool
ok = index_.Find(&key, &kv);
if
(ok) {
result->reset(
new
char
[kv->value.size()]);
memcpy
(result->get(), kv->value.c_str(), kv->value.size());
*size = kv->value.size();
kv->refs_--;
stats_.cache_hits_++;
return
Status::OK();
}
stats_.cache_misses_++;
if
(next_tier()) {
return
next_tier()->Lookup(page_key, result, size);
}
return
Status::NotFound(
"key not found in volatile cache"
);
}
bool
VolatileCacheTier::Erase(
const
Slice&
) {
assert
(!
"not supported"
);
return
true
;
}
bool
VolatileCacheTier::Evict() {
CacheData* edata = index_.Evict();
if
(!edata) {
return
false
;
}
stats_.cache_evicts_++;
if
(next_tier()) {
next_tier()->Insert(Slice(edata->key), edata->value.c_str(),
edata->value.size());
}
size_ -= edata->value.size();
delete
edata;
return
true
;
}
}
#endif