Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SynchronizedCallerStalenessCache.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Cache_SynchronizedCallerStalenessCache_h_
5#define _Stroika_Foundation_Cache_SynchronizedCallerStalenessCache_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <mutex>
10#include <shared_mutex>
11
12#include "Stroika/Foundation/Cache/CallerStalenessCache.h"
13
14/**
15 * \file
16 *
17 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
18 *
19 */
20
22
23 /**
24 * \brief simple wrapper on CallerStalenessCache (with the same API) - but internally synchronized in a way that is
25 * more performant than using RWSyncrhonzied<CallerStalenessCache<...>>
26 *
27 * @see CallerStalenessCache<> - for unsynchronized base version
28 *
29 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
30 *
31 * TODO:
32 * o @todo consider if better hiding using aggregation instead of private inheritance.
33 */
34 template <typename KEY, typename VALUE, typename TIME_TRAITS = CallerStalenessCache_Traits_DEFAULT>
35 class SynchronizedCallerStalenessCache : private CallerStalenessCache<KEY, VALUE, TIME_TRAITS> {
36 private:
38
39 public:
40 /*
41 * Note: We choose to not hold any lock while filling the cache (fHoldWriteLockDuringCacheFill false by default).
42 * This is because typically, filling the cache will be slow (otherwise you wouldn't be us using a cache).
43 *
44 * But this has the downside, that you could try filling the cache multiple times with the same value.
45 *
46 * That's perfectly safe, but not speedy.
47 *
48 * Which is better depends on the likihood the caller will make multiple requests for the same non-existent value at
49 * the same time. If yes, you should set fHoldWriteLockDuringCacheFill. If no (or if you care more about being able to
50 * read the rest of the data and not having threads block needlessly for other values) set fHoldWriteLockDuringCacheFill false (default).
51 *
52 * \note Another thing to be aware of, if setting fHoldWriteLockDuringCacheFill true, is that it increases the risk
53 * of Deadlock (if what you don the fill code is complicated and difficult to analyze for what locks it might acquire).
54 *
55 * \note See http://stroika-bugs.sophists.com/browse/STK-906 - possible enhancement to this configuration to work better avoiding
56 * deadlocks
57 * \note See http://stroika-bugs.sophists.com/browse/STK-907 - about needing some new mechanism in Stroika for deadlock detection/avoidance.
58 *
59 */
60 bool fHoldWriteLockDuringCacheFill{false};
61
62 public:
63 /**
64 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::TimeStampType;
65 */
66 using TimeStampType = typename inherited::TimeStampType;
67
68 public:
69 /**
70 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::GetCurrentTimestamp;
71 */
72 using inherited::GetCurrentTimestamp;
73
74 public:
75 /**
76 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::Ago;
77 */
78 using inherited::Ago;
79
80 public:
81 /**
82 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::ClearOlderThan;
83 */
84 nonvirtual void ClearOlderThan (TimeStampType t);
85
86 public:
87 /**
88 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::Clear;
89 */
90 nonvirtual void Clear ();
91 template <typename K1 = KEY>
92 nonvirtual void Clear (Common::ArgByValueType<K1> k)
93 requires (IsKeyedCache<K1>);
94
95 public:
97
98 public:
99 /**
100 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::Add;
101 */
102 nonvirtual void Add (Common::ArgByValueType<VALUE> v)
103 requires (not IsKeyedCache<KEY>);
104 template <typename K = KEY>
105 nonvirtual void Add (Common::ArgByValueType<K> k, Common::ArgByValueType<VALUE> v, AddReplaceMode addReplaceMode = AddReplaceMode::eAddReplaces)
106 requires (IsKeyedCache<K>);
107
108 public:
109 /**
110 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::Lookup;
111 */
113 requires (not IsKeyedCache<KEY>);
114 template <typename K = KEY>
116 requires (IsKeyedCache<K>);
117 nonvirtual VALUE LookupValue (TimeStampType staleIfOlderThan, const function<VALUE ()>& cacheFiller)
118 requires (not IsKeyedCache<KEY>);
119 template <typename F, typename K = KEY>
122 template <typename K = KEY>
123 nonvirtual VALUE LookupValue (Common::ArgByValueType<K> k, TimeStampType staleIfOlderThan, const VALUE& defaultValue) const
124 requires (IsKeyedCache<KEY>);
125
126 public:
127 /**
128 * @see CallerStalenessCache<KEY, VALUE, TIME_TRAITS>::clear;
129 */
130 nonvirtual void clear ();
131
132 private:
133 mutable shared_timed_mutex fMutex_;
134 };
135
136}
137
138/*
139 ********************************************************************************
140 ***************************** Implementation Details ***************************
141 ********************************************************************************
142 */
143#include "SynchronizedCallerStalenessCache.inl"
144
145#endif /*_Stroika_Foundation_Cache_SynchronizedCallerStalenessCache_h_*/
static TimeStampType Ago(TimeStampDifferenceType backThisTime)
LRUCache implements a simple least-recently-used caching strategy, with optional hashing (of keys) to...
Definition LRUCache.h:94
simple wrapper on CallerStalenessCache (with the same API) - but internally synchronized in a way tha...
nonvirtual optional< VALUE > Lookup(TimeStampType staleIfOlderThan) const
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
AddReplaceMode
Mode flag to say if Adding to a container replaces, or if the first addition wins.