20#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
21#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
23#include <xrpl/basics/Log.h>
24#include <xrpl/basics/UnorderedContainers.h>
25#include <xrpl/basics/hardened_hash.h>
26#include <xrpl/beast/clock/abstract_clock.h>
27#include <xrpl/beast/insight/Insight.h>
53 bool IsKeyCache =
false,
54 class Hash = hardened_hash<>,
184 template <
class KeyComparable>
230 if (when_expire > (now - minimumAge))
231 when_expire = now - minimumAge;
236 << (now - when_expire).count() <<
" of "
262 <<
m_name <<
" TaggedCache sweep lock duration "
263 << std::chrono::duration_cast<std::chrono::milliseconds>(
281 Entry& entry = cit->second;
285 if (entry.isCached())
292 if (!
valid || entry.isExpired())
327 std::piecewise_construct,
334 Entry& entry = cit->second;
337 if (entry.isCached())
339 if (replace(entry.ptr))
342 entry.weak_ptr = data;
352 auto cachedData = entry.lock();
356 if (replace(entry.ptr))
359 entry.weak_ptr = data;
363 entry.ptr = cachedData;
372 entry.weak_ptr = data;
410 template <
class ReturnType =
bool>
415 auto p = std::make_shared<T>(
std::cref(value));
419 template <
class ReturnType =
bool>
426 std::piecewise_construct,
430 it->second.last_access = now;
443 auto entry =
fetch(key);
482 return double(
m_hits) / tot;
490 template <
class Handler>
506 auto const [it, inserted] =
510 return it->second.ptr;
522 Entry& entry = cit->second;
523 if (entry.isCached())
529 entry.ptr = entry.lock();
530 if (entry.isCached())
553 hit_rate = (
m_hits * 100) / total;
562 template <
class Handler>
565 Handler
const& handler,
567 :
hook(collector->make_hook(handler))
568 ,
size(collector->make_gauge(prefix,
"size"))
569 ,
hit_rate(collector->make_gauge(prefix,
"hit_rate"))
617 return ptr ==
nullptr;
622 return ptr !=
nullptr;
664 int cacheRemovals = 0;
669 stuffToSweep.
first.reserve(partition.size());
670 stuffToSweep.
second.reserve(partition.size());
672 auto cit = partition.begin();
673 while (cit != partition.end())
675 if (cit->second.isWeak())
678 if (cit->second.isExpired())
680 stuffToSweep.second.push_back(
681 std::move(cit->second.weak_ptr));
683 cit = partition.erase(cit);
690 else if (cit->second.last_access <= when_expire)
694 if (cit->second.ptr.use_count() == 1)
696 stuffToSweep.first.push_back(
697 std::move(cit->second.ptr));
699 cit = partition.erase(cit);
704 cit->second.ptr.reset();
716 if (mapRemovals || cacheRemovals)
719 <<
"TaggedCache partition sweep " <<
m_name
720 <<
": cache = " << partition.size() <<
"-" << cacheRemovals
721 <<
", map-=" << mapRemovals;
724 allRemovals += cacheRemovals;
738 int cacheRemovals = 0;
744 auto cit = partition.begin();
745 while (cit != partition.end())
747 if (cit->second.last_access > now)
749 cit->second.last_access = now;
752 else if (cit->second.last_access <= when_expire)
754 cit = partition.erase(cit);
763 if (mapRemovals || cacheRemovals)
765 JLOG(m_journal.debug())
766 <<
"TaggedCache partition sweep " << m_name
767 <<
": cache = " << partition.size() <<
"-" << cacheRemovals
768 <<
", map-=" << mapRemovals;
771 allRemovals += cacheRemovals;
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
typename Clock::time_point time_point
virtual time_point now() const =0
Returns the current time.
typename Clock::duration duration
A metric for measuring an integral value.
void set(value_type value) const
Set the value on the gauge.
A reference to a handler for performing polled collection.
static std::shared_ptr< Collector > New()
clock_type::time_point last_access
KeyOnlyEntry(clock_type::time_point const &last_access_)
void touch(clock_type::time_point const &now)
clock_type::time_point last_access
std::weak_ptr< mapped_type > weak_ptr
void touch(clock_type::time_point const &now)
std::shared_ptr< mapped_type > lock()
ValueEntry(clock_type::time_point const &last_access_, std::shared_ptr< mapped_type > const &ptr_)
std::shared_ptr< mapped_type > ptr
std::thread sweepHelper(clock_type::time_point const &when_expire, clock_type::time_point const &now, typename KeyValueCacheType::map_type &partition, SweptPointersVector &stuffToSweep, std::atomic< int > &allRemovals, std::lock_guard< std::recursive_mutex > const &)
bool retrieve(const key_type &key, T &data)
std::conditional< IsKeyCache, KeyOnlyEntry, ValueEntry >::type Entry
std::shared_ptr< T > fetch(const key_type &key)
auto insert(key_type const &key, T const &value) -> std::enable_if_t<!IsKeyCache, ReturnType >
Insert the element into the container.
void setTargetAge(clock_type::duration s)
std::shared_ptr< T > initialFetch(key_type const &key, std::lock_guard< mutex_type > const &l)
bool canonicalize_replace_cache(const key_type &key, std::shared_ptr< T > const &data)
bool del(const key_type &key, bool valid)
void setTargetSize(int s)
bool canonicalize_replace_client(const key_type &key, std::shared_ptr< T > &data)
bool canonicalize(const key_type &key, std::shared_ptr< T > &data, std::function< bool(std::shared_ptr< T > const &)> &&replace)
Replace aliased objects with originals.
bool touch_if_exists(KeyComparable const &key)
Refresh the last access time on a key if present.
clock_type & clock()
Return the clock associated with the cache.
TaggedCache(std::string const &name, int size, clock_type::duration expiration, clock_type &clock, beast::Journal journal, beast::insight::Collector::ptr const &collector=beast::insight::NullCollector::New())
beast::abstract_clock< std::chrono::steady_clock > clock_type
clock_type::duration getTargetAge() const
std::vector< key_type > getKeys() const
auto insert(key_type const &key) -> std::enable_if_t< IsKeyCache, ReturnType >
std::size_t size() const
Returns the number of items in the container.
std::thread sweepHelper(clock_type::time_point const &when_expire, clock_type::time_point const &now, typename KeyOnlyCacheType::map_type &partition, SweptPointersVector &, std::atomic< int > &allRemovals, std::lock_guard< std::recursive_mutex > const &)
double rate() const
Returns the fraction of cache hits.
std::shared_ptr< T > fetch(key_type const &digest, Handler const &h)
Fetch an item from the cache.
clock_type::duration m_target_age
iterator erase(const_iterator position)
std::pair< iterator, bool > emplace(std::piecewise_construct_t const &, T &&keyTuple, U &&valueTuple)
partition_map_type & map()
void find(key_type const &key, T &it) const
std::size_t partitions() const
T forward_as_tuple(T... args)
TER valid(PreclaimContext const &ctx, AccountID const &src)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
beast::insight::Hook hook
Stats(std::string const &prefix, Handler const &handler, beast::insight::Collector::ptr const &collector)
beast::insight::Gauge size
beast::insight::Gauge hit_rate