Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
SynchronizedLRUCache.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4
6
7 /*
8 ********************************************************************************
9 * SynchronizedLRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE> **
10 ********************************************************************************
11 */
12 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
13 template <typename... ARGS>
15 : inherited (forward<ARGS> (args)...) // allow implicit conversions so int converted to size_t like with direct call to LRUCache
16 {
17 }
18 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
20 : inherited{src.GetMaxCacheSize (), src.GetKeyEqualsCompareFunction (), src.GetHashTableSize (), src.GetKeyHashFunction ()}
21 , fHoldWriteLockDuringCacheFill{src.fHoldWriteLockDuringCacheFill}
22 {
23 // @todo I think I can redo this using inheirted CTOR, while holding lock?? then stats copied and all this simpler
24 for (auto i : src.Elements ()) {
25 Add (i.fKey, i.fValue);
26 }
27 // @todo - no way to copy the stats
28 }
29 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
31 {
32 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
33 return inherited::GetMaxCacheSize ();
34 }
35 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
37 {
38 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
39 inherited::SetMaxCacheSize (maxCacheSize);
40 }
41 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
43 {
44 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
45 return inherited::GetStats ();
46 }
47 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
49 -> KeyEqualsCompareFunctionType
50 {
51 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
52 return inherited::GetKeyEqualsCompareFunction ();
53 }
54 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
56 {
57 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
58 return inherited::GetHashTableSize ();
59 }
60 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
62 {
63 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
64 return inherited::GetKeyHashFunction ();
65 }
66 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
68 {
69 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
70 inherited::clear ();
71 }
72 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
74 {
75 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
76 inherited::clear (key);
77 }
78 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
80 function<bool (typename Common::ArgByValueType<KEY>)> clearPredicate)
81 {
82 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
83 inherited::clear (clearPredicate);
84 }
85 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
86 inline optional<VALUE>
88 {
89 // Avoid issue with Lookup updating the stats object - if there is one - with whichKindOfLocker
90 using whichKindOfLocker =
91 conditional_t<same_as<Statistics::Stats_Null, STATS_TYPE>, shared_lock<decltype (fMutex_)>, lock_guard<decltype (fMutex_)>>;
92 [[maybe_unused]] auto&& lock = whichKindOfLocker{fMutex_};
93 return const_cast<SynchronizedLRUCache*> (this)->inherited::Lookup (key); // really mutates this, but this method treated as const since we hold a lock during this so threadsafe
94 }
95 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
98 {
99 /*
100 * The main reason for this class, is this logic: unlocking the shared lock and then fetching the new value (with a write lock).
101 */
102 // Avoid issue with Lookup updating the stats object - if there is one - with whichKindOfLocker
103 using whichKindOfLocker =
104 conditional_t<same_as<Statistics::Stats_Null, STATS_TYPE>, shared_lock<decltype (fMutex_)>, unique_lock<decltype (fMutex_)>>;
105 auto&& lock = whichKindOfLocker{fMutex_};
106 if (optional<VALUE> o = inherited::Lookup (key)) {
107 return *o;
108 }
109 else {
110 lock.unlock ();
111 if (fHoldWriteLockDuringCacheFill) {
112 // Avoid two threads calling cache filler for same key value at the same time
113 [[maybe_unused]] auto&& newRWLock = lock_guard{fMutex_};
114 VALUE v = valueFetcher (key);
115 inherited::Add (key, v);
116 return v;
117 }
118 else {
119 // Avoid needlessly blocking lookups (shared_lock above) until after we've filled the cache (typically slow)
120 // and keep it to minimum logically required (inherited add).
121 VALUE v = valueFetcher (key);
122 Add (key, v); // this locks internally
123 return v;
124 }
125 }
126 }
127 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
129 typename Common::ArgByValueType<VALUE> value)
130 {
131 [[maybe_unused]] auto&& lock = lock_guard{fMutex_};
132 inherited::Add (key, value);
133 }
134 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION, typename STATS_TYPE>
136 {
137 [[maybe_unused]] auto&& lock = shared_lock{fMutex_};
138 return inherited::Elements ();
139 }
140
141}
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 > value)
Definition LRUCache.inl:265
simple wrapper on LRUCache (with the same API) - but internally synchronized in a way that is more pe...
nonvirtual optional< VALUE > Lookup(typename Common::ArgByValueType< KEY > key) const
nonvirtual void SetMaxCacheSize(size_t maxCacheSize)
nonvirtual KEY_HASH_FUNCTION GetKeyHashFunction() const
nonvirtual Containers::Mapping< KEY, VALUE > Elements() const
nonvirtual KeyEqualsCompareFunctionType GetKeyEqualsCompareFunction() const
nonvirtual VALUE LookupValue(typename Common::ArgByValueType< KEY > key, const function< VALUE(typename Common::ArgByValueType< KEY >)> &valueFetcher)
nonvirtual void Add(typename Common::ArgByValueType< KEY > key, typename Common::ArgByValueType< VALUE > value)
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