Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SynchronizedTimedCache.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4
6
7 /*
8 ********************************************************************************
9 ***************** SynchronizedTimedCache<KEY, VALUE, TRAITS> *******************
10 ********************************************************************************
11 */
12 template <typename KEY, typename VALUE, typename TRAITS>
17 template <typename KEY, typename VALUE, typename TRAITS>
19 : inherited{src.GetMinimumAllowedFreshness ()}
20 {
21 [[maybe_unused]] auto&& srcLock = shared_lock{src.fMutex_}; // shared locks intrinsically recursive - not needed here but good to assure no locks in between
22 for (const auto& ci : src.Elements ()) {
23 inherited::Add (ci.fKey, ci.fValue, ci.fLastRefreshedAt);
24 }
25 }
26 template <typename KEY, typename VALUE, typename TRAITS>
28 {
29 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
30 return inherited::GetMinimumAllowedFreshness ();
31 }
32 template <typename KEY, typename VALUE, typename TRAITS>
34 {
35 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
36 inherited::SetMinimumAllowedFreshness (minimumAllowedFreshness);
37 }
38 template <typename KEY, typename VALUE, typename TRAITS>
39 inline auto SynchronizedTimedCache<KEY, VALUE, TRAITS>::Elements () const -> Traversal::Iterable<CacheElement>
40 {
41 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
42 return inherited::Elements ();
43 }
44 template <typename KEY, typename VALUE, typename TRAITS>
47 {
48 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
49 return inherited::Lookup (key);
50 }
51 template <typename KEY, typename VALUE, typename TRAITS>
53 [[maybe_unused]] LookupMarksDataAsRefreshed successfulLookupRefreshesAcceesFlag)
55 {
56 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
57 return inherited::Lookup (key);
58 }
59 template <typename KEY, typename VALUE, typename TRAITS>
61 const function<VALUE (typename Common::ArgByValueType<KEY>)>& cacheFiller,
62 [[maybe_unused]] LookupMarksDataAsRefreshed successfulLookupRefreshesAcceesFlag,
63 PurgeSpoiledDataFlagType purgeSpoiledData) -> VALUE
64 {
65 /*
66 * The main reason for this class (as opposed to Syncrhonized<TimedCache>), is this logic: unlocking the shared
67 * lock and then fetching the new value (oprionally with a write lock).
68 */
69 auto&& readLock = shared_lock{fMutex_}; // try shared_lock for case where present, and then lose it if we need to update object
70 if (optional<VALUE> o = inherited::Lookup (key)) {
71 return *o;
72 }
73 else {
74 readLock.unlock (); // don't hold read lock, upgrade to write, and condition when we hold the write lock
75 if (fHoldWriteLockDuringCacheFill) {
76 // Avoid two threds calling cache for same key value at the same time
77 [[maybe_unused]] auto&& newRWLock = lock_guard{fMutex_};
78 VALUE v = cacheFiller (key);
79 inherited::Add (key, v, purgeSpoiledData); // if purgeSpoiledData must be done, do while holding lock
80 return v;
81 }
82 else {
83 // Avoid needlessly blocking lookups (shared_lock above) until after we've filled the cache (typically slow)
84 // and keep it to minimum logically required (inherited add).
85 VALUE v = cacheFiller (key);
86 Add (key, v, purgeSpoiledData); // OUR top-level implementation does right thing with locking and purgeSpoiledData, so can use that.
87 return v;
88 }
89 }
90 }
91 template <typename KEY, typename VALUE, typename TRAITS>
93 TimedCacheSupport::PurgeSpoiledDataFlagType purgeSpoiledData)
94 {
95 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
96 // NOTE - COULD handle purgeSpoiledData directly here, and use two lock_guards, so other callers get a chance before purge loop
97 // but this is probably better as fewer lock calls and not likely doing a purge loop anyhow...
98 inherited::Add (key, result, purgeSpoiledData);
99 }
100 template <typename KEY, typename VALUE, typename TRAITS>
103 {
104 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
105 inherited::Add (key, result, freshAsOf);
106 }
107 template <typename KEY, typename VALUE, typename TRAITS>
109 {
110 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
111 inherited::Remove (key);
112 }
113 template <typename KEY, typename VALUE, typename TRAITS>
115 {
116 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
117 inherited::clear ();
118 }
119 template <typename KEY, typename VALUE, typename TRAITS>
121 {
122 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
123 inherited::PurgeSpoiledData ();
124 }
125
126}
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)
SynchronizedTimedCache(const Time::Duration &minimumAllowedFreshness)
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
nonvirtual void Add(typename Common::ArgByValueType< KEY > key, typename Common::ArgByValueType< VALUE > result, PurgeSpoiledDataFlagType purgeSpoiledData=PurgeSpoiledDataFlagType::eAutomaticallyPurgeSpoiledData)
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
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