Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SynchronizedTimedCache.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Cache_SynchronizedTimedCache_h_
5#define _Stroika_Foundation_Cache_SynchronizedTimedCache_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <mutex>
10#include <shared_mutex>
11
12#include "Stroika/Foundation/Cache/TimedCache.h"
13
14/**
15 * \file
16 *
17 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
18 *
19 */
20
22
23 /**
24 * @see TimedCache but internally synchronized. You could use Synchronized<TimedCache>, but this is simpler to use and
25 * performs better, due to not write locking until the last minute needed (you expect a cache to mostly be read
26 * from and have writes - cache misses - expensive/slow but not slow the rest of the cache (hits).
27 *
28 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
29 *
30 * @see TimedCache<> - for unsynchronized implementation
31 *
32 */
33 template <typename KEY, typename VALUE, typename TRAITS = TimedCacheSupport::DefaultTraits<KEY, VALUE>>
34 class SynchronizedTimedCache : private TimedCache<KEY, VALUE, TRAITS> {
35 private:
37
38 public:
39 using LookupMarksDataAsRefreshed = typename inherited::LookupMarksDataAsRefreshed;
40
41 public:
42 using PurgeSpoiledDataFlagType = typename inherited::PurgeSpoiledDataFlagType;
43
44 public:
45 using CacheElement = typename inherited::CacheElement;
46
47 public:
48 /**
49 * \par Example Usage
50 * \code
51 * optional<String> ReverseDNSLookup_ (const InternetAddress& inetAddr)
52 * {
53 * static const Time::Duration kCacheTTL_{5min}; // @todo fix when Stroika Duration bug supports constexpr this should
54 * static Cache::SynchronizedTimedCache<InternetAddress, optional<String>> sCache_{kCacheTTL_};
55 * try {
56 * return sCache_.LookupValue (inetAddr, [] (const InternetAddress& inetAddr) {
57 * return DNS::kThe.ReverseLookup (inetAddr);
58 * });
59 * }
60 * catch (...) {
61 * // NOTE - to NEGATIVELY CACHE failure, you could call sCache_.Add (inetAddr, nullopt);
62 * return nullopt; // if DNS is failing, just dont do this match, dont abandon all data collection
63 * }
64 * }
65 * \endcode
66 *
67 * @see TimedCache constructor for more examples
68 */
71
72 public:
73 // support eventually, but not trivial
74 nonvirtual SynchronizedTimedCache& operator= (const SynchronizedTimedCache&) = delete;
75
76 public:
77 /*
78 * Note: We choose to not hold any lock while filling the cache (fHoldWriteLockDuringCacheFill false by default).
79 * This is because typically, filling the cache
80 * will be slow (otherwise you would be us using the SynchronizedTimedCache).
81 *
82 * But this has the downside, that you could try filling the cache multiple times with the same value.
83 *
84 * That's perfectly safe, but not speedy.
85 *
86 * Which is better depends on the likihood the caller will make multiple requests for the same non-existent value at
87 * the same time. If yes, you should set fHoldWriteLockDuringCacheFill. If no (or if you care more about being able to
88 * read the rest of the data and not having threads block needlessly for other values) set fHoldWriteLockDuringCacheFill false (default).
89 *
90 * \note Design Note
91 * This probably should be a constructor parameter, but if its a plain bool, looks potentially confusing.
92 * Forcing explicit name probably better, and typically will be set just after construction before any threads could access
93 * so no real race risk.
94 */
95 bool fHoldWriteLockDuringCacheFill{false};
96
97 public:
98 /**
99 * @see TimedCache::GetMinimumAllowedFreshness
100 */
101 nonvirtual Time::Duration GetMinimumAllowedFreshness () const;
102
103 public:
104 /**
105 * @see TimedCache::SetMinimumAllowedFreshness
106 */
108
109 public:
110 /**
111 * @see TimedCache::Elements
112 */
114
115 public:
116 /**
117 * @see TimedCache::Lookup
118 */
120 nonvirtual optional<VALUE> Lookup (typename Common::ArgByValueType<KEY> key, LookupMarksDataAsRefreshed successfulLookupRefreshesAcceesFlag);
121
122 public:
123 /**
124 * @see TimedCache::LookupValue
125 */
126 nonvirtual VALUE LookupValue (typename Common::ArgByValueType<KEY> key, const function<VALUE (typename Common::ArgByValueType<KEY>)>& cacheFiller,
127 LookupMarksDataAsRefreshed successfulLookupRefreshesAcceesFlag = LookupMarksDataAsRefreshed::eDontTreatFoundThroughLookupAsRefreshed,
128 PurgeSpoiledDataFlagType purgeSpoiledData = PurgeSpoiledDataFlagType::eAutomaticallyPurgeSpoiledData);
129
130 public:
131 /**
132 * @see TimedCache::Add
133 */
134 nonvirtual void Add (typename Common::ArgByValueType<KEY> key, typename Common::ArgByValueType<VALUE> result,
135 TimedCacheSupport::PurgeSpoiledDataFlagType purgeSpoiledData = PurgeSpoiledDataFlagType::eAutomaticallyPurgeSpoiledData);
137
138 public:
139 /**
140 * @see TimedCache::Remove
141 */
142 nonvirtual void Remove (typename Common::ArgByValueType<KEY> key);
143
144 public:
145 /**
146 * @see TimedCache::clear
147 */
148 nonvirtual void clear ();
149
150 public:
151 /**
152 * @see TimedCache::PurgeSpoiledData
153 */
154 nonvirtual void PurgeSpoiledData ();
155
156 public:
157 [[deprecated ("Since Stroika v3.0d1, use PurgeSpoiledData or count on Add's purgeSpoiledData parameter)")]] nonvirtual void DoBookkeeping ()
158 {
160 }
161 [[deprecated ("Since Stroika 3.0d1 use GetMinimumAllowedFreshness")]] Time::Duration GetTimeout () const
162 {
164 }
165 [[deprecated ("Since Stroika 3.0d1 use GetMinimumAllowedFreshness")]] void SetTimeout (Time::Duration timeout)
166 {
168 }
169
170 private:
171 mutable shared_timed_mutex fMutex_; // careful this is non-recursive
172 };
173
174}
175
176/*
177 ********************************************************************************
178 ***************************** Implementation Details ***************************
179 ********************************************************************************
180 */
181#include "SynchronizedTimedCache.inl"
182
183#endif /*_Stroika_Foundation_Cache_SynchronizedTimedCache_h_*/
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
LRUCache implements a simple least-recently-used caching strategy, with optional hashing (of keys) to...
Definition LRUCache.h:94
nonvirtual void Add(typename Common::ArgByValueType< KEY > key, typename Common::ArgByValueType< VALUE > result, TimedCacheSupport::PurgeSpoiledDataFlagType purgeSpoiledData=PurgeSpoiledDataFlagType::eAutomaticallyPurgeSpoiledData)
nonvirtual VALUE LookupValue(typename Common::ArgByValueType< KEY > key, const function< VALUE(typename Common::ArgByValueType< KEY >)> &cacheFiller, LookupMarksDataAsRefreshed successfulLookupRefreshesAcceesFlag=LookupMarksDataAsRefreshed::eDontTreatFoundThroughLookupAsRefreshed, PurgeSpoiledDataFlagType purgeSpoiledData=PurgeSpoiledDataFlagType::eAutomaticallyPurgeSpoiledData)
nonvirtual void SetMinimumAllowedFreshness(Time::Duration minimumAllowedFreshness)
nonvirtual void Remove(typename Common::ArgByValueType< KEY > key)
nonvirtual optional< VALUE > Lookup(typename Common::ArgByValueType< KEY > key, Time::TimePointSeconds *lastRefreshedAt=nullptr) const
nonvirtual Traversal::Iterable< CacheElement > Elements() const
Keep track of a bunch of objects, each with an associated 'freshness' which meet a TimedCache-associa...
Definition TimedCache.h:257
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32