xrpld
Loading...
Searching...
No Matches
TaggedCache.h
1#pragma once
2
3#include <xrpl/basics/IntrusivePointer.h>
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/SharedWeakCachePointer.ipp>
6#include <xrpl/basics/UnorderedContainers.h>
7#include <xrpl/basics/hardened_hash.h>
8#include <xrpl/beast/clock/abstract_clock.h>
9#include <xrpl/beast/insight/Insight.h>
10
11#include <atomic>
12#include <cstddef>
13#include <functional>
14#include <mutex>
15#include <thread>
16#include <type_traits>
17#include <vector>
18
19namespace xrpl {
20
21namespace detail {
22
23// Replace-policy tags selecting how TaggedCache::canonicalizeImpl resolves a
24// collision when the key already exists (defined in TaggedCache.ipp):
25// - ReplaceCached: always replace the cached value with `data`. `data` is
26// never written back and may be const.
27// - ReplaceClient: keep the cached value and write it back into `data` (the
28// client's pointer), which must therefore be writable.
29// - ReplaceDynamically: call the supplied callback to decide per call; `data`
30// is written back when the cached value is kept, so it must be writable.
31struct ReplaceCached;
32struct ReplaceClient;
33struct ReplaceDynamically;
34
35} // namespace detail
36
49template <
50 class Key,
51 class T,
52 bool IsKeyCache = false,
53 class SharedWeakUnionPointerType = SharedWeakCachePointer<T>,
54 class SharedPointerType = std::shared_ptr<T>,
55 class Hash = HardenedHash<>,
56 class KeyEqual = std::equal_to<Key>,
57 class Mutex = std::recursive_mutex>
59{
60public:
61 using mutex_type = Mutex;
62 using key_type = Key;
63 using mapped_type = T;
65 using shared_weak_combo_pointer_type = SharedWeakUnionPointerType;
66 using shared_pointer_type = SharedPointerType;
67
68public:
70 std::string const& name,
71 int size,
72 clock_type::duration expiration,
74 beast::Journal journal,
76
77public:
81
84 size() const;
85
86 int
87 getCacheSize() const;
88
89 int
90 getTrackSize() const;
91
92 float
94
95 void
97
98 void
100
104 template <class KeyComparable>
105 bool
106 touchIfExists(KeyComparable const& key);
107
109
110 void
112
113 bool
114 del(key_type const& key, bool valid);
115
116private:
117 // Selects the `data` parameter type of canonicalizeImpl from the replace
118 // policy: const for detail::ReplaceCached (never written back), otherwise
119 // writable.
120 template <typename Policy>
123 SharedPointerType const&,
124 SharedPointerType&>;
125
134 template <class Policy, class Callback = std::nullptr_t>
135 bool
137 key_type const& key,
139 Policy policy,
140 Callback&& replaceCallback = nullptr);
141
142public:
162 template <class Callback>
163 bool
164 canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback);
165
179 bool
180 canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data);
181
196 bool
197 canonicalizeReplaceClient(key_type const& key, SharedPointerType& data);
198
199 SharedPointerType
200 fetch(key_type const& key);
201
206 template <class ReturnType = bool>
207 auto
209
210 template <class ReturnType = bool>
211 auto
213
214 // VFALCO NOTE It looks like this returns a copy of the data in
215 // the output parameter 'data'. This could be expensive.
216 // Perhaps it should work like standard containers, which
217 // simply return an iterator.
218 //
219 bool
220 retrieve(key_type const& key, T& data);
221
224
226 getKeys() const;
227
228 // CachedSLEs functions.
230 double
231 rate() const;
232
238 template <class Handler>
239 SharedPointerType
240 fetch(key_type const& digest, Handler const& h);
241 // End CachedSLEs functions.
242
243private:
244 SharedPointerType
246
247 void
249
250private:
251 struct Stats
252 {
253 template <class Handler>
255 std::string const& prefix,
256 Handler const& handler,
257 beast::insight::Collector::ptr const& collector)
258 : hook(collector->makeHook(handler))
259 , size(collector->makeGauge(prefix, "size"))
260 , hitRate(collector->makeGauge(prefix, "hit_rate"))
261
262 {
263 }
264
268
271 };
272
274 {
275 public:
277
281
282 void
284 {
285 lastAccess = now;
286 }
287 };
288
290 {
291 public:
294
299
300 [[nodiscard]] bool
301 isWeak() const
302 {
303 if (!ptr)
304 return true;
305 return ptr.isWeak();
306 }
307 [[nodiscard]] bool
308 isCached() const
309 {
310 return ptr && ptr.isStrong();
311 }
312 [[nodiscard]] bool
313 isExpired() const
314 {
315 return ptr.expired();
316 }
317 SharedPointerType
319 {
320 return ptr.lock();
321 }
322 void
324 {
325 lastAccess = now;
326 }
327 };
328
330
332
334
336
337 [[nodiscard]] std::thread
339 clock_type::time_point const& whenExpire,
340 [[maybe_unused]] clock_type::time_point const& now,
342 SweptPointersVector& stuffToSweep,
343 std::atomic<int>& allRemovals,
345
346 [[nodiscard]] std::thread
348 clock_type::time_point const& whenExpire,
349 clock_type::time_point const& now,
352 std::atomic<int>& allRemovals,
354
357 Stats stats_;
358
360
361 // Used for logging
363
364 // Desired number of cache entries (0 = ignore)
365 int const targetSize_;
366
367 // Desired maximum cache age
369
370 // Number of items cached
372 cache_type cache_; // Hold strong reference to recent objects
375};
376
377} // namespace xrpl
Abstract interface to a clock.
std::chrono::steady_clock::duration duration
std::chrono::steady_clock::time_point time_point
A generic endpoint for log messages.
Definition Journal.h:38
std::shared_ptr< Collector > ptr
Definition Collector.h:26
A metric for measuring an integral value.
Definition Gauge.h:20
A reference to a handler for performing polled collection.
Definition Hook.h:12
static std::shared_ptr< Collector > make()
Seed functor once per construction.
std::unordered_map< key_type, mapped_type, hasher, key_equal, allocator_type > map_type
A combination of a std::shared_ptr and a std::weak_pointer.
void touch(clock_type::time_point const &now)
clock_type::time_point lastAccess
KeyOnlyEntry(clock_type::time_point const &lastAccess)
clock_type::time_point lastAccess
SharedPointerType lock()
void touch(clock_type::time_point const &now)
shared_weak_combo_pointer_type ptr
ValueEntry(clock_type::time_point const &lastAccess, shared_pointer_type const &ptr)
std::shared_ptr< int > shared_pointer_type
Definition TaggedCache.h:66
std::vector< key_type > getKeys() const
hardened_partitioned_hash_map< key_type, ValueEntry, HardenedHash<>, std::equal_to< uint256 > > KeyValueCacheType
bool del(key_type const &key, bool valid)
bool retrieve(key_type const &key, T &data)
int getTrackSize() const
int getCacheSize() const
bool canonicalizeReplaceClient(key_type const &key, SharedPointerType &data)
Insert the canonical entry for key, keeping any existing cached value.
auto insert(key_type const &key, T const &value) -> std::enable_if_t<!IsKeyCache, ReturnType >
Insert the element into the container.
std::thread sweepHelper(clock_type::time_point const &whenExpire, clock_type::time_point const &now, KeyOnlyCacheType::map_type &partition, SweptPointersVector &, std::atomic< int > &allRemovals, std::scoped_lock< std::recursive_mutex > const &)
bool touchIfExists(KeyComparable const &key)
Refresh the last access time on a key if present.
SharedWeakCachePointer< int > shared_weak_combo_pointer_type
Definition TaggedCache.h:65
beast::AbstractClock< std::chrono::steady_clock > clock_type
Definition TaggedCache.h:64
SharedPointerType fetch(key_type const &digest, Handler const &h)
Fetch an item from the cache.
hardened_partitioned_hash_map< key_type, KeyOnlyEntry, HardenedHash<>, std::equal_to< uint256 > > KeyOnlyCacheType
std::thread sweepHelper(clock_type::time_point const &whenExpire, clock_type::time_point const &now, KeyValueCacheType::map_type &partition, SweptPointersVector &stuffToSweep, std::atomic< int > &allRemovals, std::scoped_lock< std::recursive_mutex > const &)
auto insert(key_type const &key) -> std::enable_if_t< IsKeyCache, ReturnType >
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::make())
std::conditional_t< std::is_same_v< detail::ReplaceCached, Policy >, std::shared_ptr< int > const &, std::shared_ptr< int > & > CanonicalizeClientPointerType
hardened_partitioned_hash_map< key_type, Entry, HardenedHash<>, std::equal_to< uint256 > > cache_type
bool canonicalizeImpl(key_type const &key, CanonicalizeClientPointerType< Policy > data, Policy policy, Callback &&replaceCallback=nullptr)
Shared implementation of the canonicalize family.
SharedPointerType initialFetch(key_type const &key, std::scoped_lock< mutex_type > const &l)
bool canonicalize(key_type const &key, SharedPointerType &data, Callback &&replaceCallback)
Replace aliased objects with originals.
std::vector< SharedWeakCachePointer< int > > SweptPointersVector
bool canonicalizeReplaceCache(key_type const &key, SharedPointerType const &data)
Insert/update the canonical entry for key, always replacing the cached value with data.
clock_type::duration const targetAge_
SharedPointerType fetch(key_type const &key)
double rate() const
Returns the fraction of cache hits.
std::conditional_t< IsKeyCache, KeyOnlyEntry, ValueEntry > Entry
mutex_type & peekMutex()
T is_same_v
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition tokens.cpp:139
PartitionedUnorderedMap< Key, Value, Hash, Pred, Allocator > hardened_partitioned_hash_map
Stats(std::string const &prefix, Handler const &handler, beast::insight::Collector::ptr const &collector)
beast::insight::Gauge size
beast::insight::Hook hook
beast::insight::Gauge hitRate