// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once #include "cache.h" #include "cache_stats.h" #include "lrucache_map.hpp" namespace vespalib { template< typename P > cache
& cache
::maxElements(size_t elems) { Lru::maxElements(elems); return *this; } template< typename P > cache
& cache
::setCapacityBytes(size_t sz) { _maxBytes.store(sz, std::memory_order_relaxed); return *this; } template< typename P > void cache
::invalidate(const K & key) { UniqueLock guard(_hashLock); invalidate(guard, key); } template< typename P > bool cache
::hasKey(const K & key) const { UniqueLock guard(_hashLock); return hasKey(guard, key); } template< typename P > cache
::~cache() = default; template< typename P > cache
::cache(BackingStore & b, size_t maxBytes) : Lru(Lru::UNLIMITED), _maxBytes(maxBytes), _sizeBytes(0), _hit(0), _miss(0), _noneExisting(0), _race(0), _insert(0), _write(0), _update(0), _invalidate(0), _lookup(0), _store(b) { } template< typename P > MemoryUsage cache
::getStaticMemoryUsage() const { MemoryUsage usage; auto cacheGuard = getGuard(); usage.incAllocatedBytes(sizeof(*this)); usage.incUsedBytes(sizeof(*this)); return usage; } template< typename P > bool cache
::removeOldest(const value_type & v) {
bool remove(Lru::removeOldest(v) || (sizeBytes() >= capacityBytes()));
if (remove) {
_sizeBytes.store(sizeBytes() - calcSize(v.first, v.second._value), std::memory_order_relaxed);
}
return remove;
}
template< typename P >
std::unique_lock ::getGuard() const {
return UniqueLock(_hashLock);
}
template< typename P >
typename P::Value
cache ::read(const K & key)
{
{
std::lock_guard guard(_hashLock);
if (Lru::hasKey(key)) {
increment_stat(_hit, guard);
return (*this)[key];
} else {
increment_stat(_miss, guard);
}
}
std::lock_guard storeGuard(getLock(key));
{
std::lock_guard guard(_hashLock);
if (Lru::hasKey(key)) {
// Somebody else just fetched it ahead of me.
increment_stat(_race, guard);
return (*this)[key];
}
}
V value;
if (_store.read(key, value)) {
std::lock_guard guard(_hashLock);
Lru::insert(key, value);
_sizeBytes.store(sizeBytes() + calcSize(key, value), std::memory_order_relaxed);
increment_stat(_insert, guard);
} else {
_noneExisting.fetch_add(1);
}
return value;
}
template< typename P >
void
cache ::write(const K & key, V value)
{
size_t newSize = calcSize(key, value);
std::lock_guard storeGuard(getLock(key));
{
std::lock_guard guard(_hashLock);
if (Lru::hasKey(key)) {
_sizeBytes.store(sizeBytes() - calcSize(key, (*this)[key]), std::memory_order_relaxed);
increment_stat(_update, guard);
}
}
_store.write(key, value);
{
std::lock_guard guard(_hashLock);
(*this)[key] = std::move(value);
_sizeBytes.store(sizeBytes() + newSize, std::memory_order_relaxed);
increment_stat(_write, guard);
}
}
template< typename P >
void
cache ::erase(const K & key)
{
std::lock_guard storeGuard(getLock(key));
invalidate(key);
_store.erase(key);
}
template< typename P >
void
cache ::invalidate(const UniqueLock & guard, const K & key)
{
verifyHashLock(guard);
if (Lru::hasKey(key)) {
_sizeBytes.store(sizeBytes() - calcSize(key, (*this)[key]), std::memory_order_relaxed);
increment_stat(_invalidate, guard);
Lru::erase(key);
}
}
template< typename P >
bool
cache ::hasKey(const UniqueLock & guard, const K & key) const
{
verifyHashLock(guard);
increment_stat(_lookup, guard);
return Lru::hasKey(key);
}
template< typename P >
void
cache ::verifyHashLock(const UniqueLock & guard) const {
assert(guard.mutex() == & _hashLock);
assert(guard.owns_lock());
}
template ::get_stats() const
{
std::lock_guard guard(_hashLock);
return CacheStats(getHit(), getMiss(), Lru::size(), sizeBytes(), getInvalidate());
}
}