userver: userver/cache/cache_update_trait.hpp Source File
Loading...
Searching...
No Matches
cache_update_trait.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/cache/cache_update_trait.hpp
4/// @brief @copybrief cache::CacheUpdateTrait
5
6#include <memory>
7#include <string>
8
9#include <userver/cache/cache_statistics.hpp>
10#include <userver/cache/update_type.hpp>
11#include <userver/components/component_fwd.hpp>
12#include <userver/dump/fwd.hpp>
13#include <userver/engine/task/task_processor_fwd.hpp>
14#include <userver/rcu/fwd.hpp>
15#include <userver/utils/flags.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace cache {
20
21struct CacheDependencies;
22struct Config;
23
24/// @ingroup userver_base_classes
25///
26/// @brief Base class for periodically updated caches.
27///
28/// @note Don't use directly, inherit from components::CachingComponentBase
29/// instead
31public:
32 CacheUpdateTrait(CacheUpdateTrait&&) = delete;
33 CacheUpdateTrait& operator=(CacheUpdateTrait&&) = delete;
34
35 /// @brief Non-blocking forced cache update of specified type
36 /// @see PeriodicTask::ForceStepAsync for behavior details
37 void InvalidateAsync(UpdateType update_type);
38
39 /// @brief Forces a synchronous cache update of specified type
40 ///
41 /// @warning This method is intended for tests and debugging only. In
42 /// production code use `InvalidateAsync` instead. The reasons are:
43 ///
44 /// 1. `InvalidateAsync` shifts the time of the next update as if a periodic
45 /// update has just happened. `UpdateSyncDebug` does not do that: it locks
46 /// the mutex and performs an additional update on the side, which puts
47 /// extra load on the CPU and on the data source.
48 /// 2. The cache we subscribe to sends events *as part of its own update*. If
49 /// the callback does something lengthy, e.g. updating another cache, this
50 /// affects the cache we subscribe to: it may disrupt its updates and
51 /// cause a traffic jam in the whole chain of caches. `InvalidateAsync` is
52 /// not subject to this. On top of that, `UpdateSyncDebug` will block the
53 /// cache we subscribe to for the time we wait for the previous update of
54 /// the dependent cache to finish (if one was in progress).
55 /// 3. `InvalidateAsync` robustly handles situations with repeated update
56 /// requests, see the docs of `PeriodicTask::ForceStepAsync`, on top of
57 /// which it is implemented. `UpdateSyncDebug` tries to lock the mutex over
58 /// and over and performs as many updates as were requested, even if they
59 /// were requested many times in a row.
60 /// 4. If `UpdateSyncDebug` is called before the periodic updates of the
61 /// current cache have started (they start after the constructor of the
62 /// derived cache finishes), the behavior is undefined, because the state
63 /// of the periodic updates is not set up yet, while an update was already
64 /// requested. `InvalidateAsync` handles this case: in that situation
65 /// nothing happens.
66 ///
67 /// @see InvalidateAsync
68 /// @throws If `Update` throws
69 void UpdateSyncDebug(UpdateType update_type);
70
71 /// @return name of the component
72 const std::string& Name() const noexcept;
73
74protected:
75 /// @cond
76 // For internal use only
77 CacheUpdateTrait(const components::ComponentConfig& config, const components::ComponentContext& context);
78
79 // For internal use only
80 explicit CacheUpdateTrait(CacheDependencies&& dependencies);
81
82 virtual ~CacheUpdateTrait();
83 /// @endcond
84
85 /// Update types configured for the cache
87
88 /// Periodic update flags
89 enum class Flag {
90 kNone = 0,
91
92 /// @brief Disable initial update on start
93 /// @deprecated Use `first-update-fail-ok: true` instead
95 };
96
97 /// Called in `CachingComponentBase::Set` during update to indicate
98 /// that the cached data has been modified
99 void OnCacheModified() noexcept;
100
101 /// @cond
102 // For internal use only
103 rcu::ReadablePtr<Config> GetConfig() const;
104
105 // Checks for the presence of the flag for pre-assign check.
106 // For internal use only.
107 bool HasPreAssignCheck() const noexcept;
108
109 // Returns value of the flag safe-data-lifetime.
110 // For internal use only.
111 bool IsSafeDataLifetime() const noexcept;
112
113 // For internal use only.
114 void SetDataSizeStatistic(std::size_t size) noexcept;
115
116 // For internal use only
117 // TODO remove after TAXICOMMON-3959
118 engine::TaskProcessor& GetCacheTaskProcessor() const noexcept;
119 /// @endcond
120
121 /// @brief Should be overridden in a derived class to align the stored data
122 /// with some data source.
123 ///
124 /// `Update` implementation should do one of the following:
125 ///
126 /// A. If the update succeeded and has changes...
127 /// 1. call CachingComponentBase::Set to update the stored value and send a
128 /// notification to subscribers
129 /// 2. call UpdateStatisticsScope::Finish
130 /// 3. return normally (an exception is allowed in edge cases)
131 ///
132 /// B. If the update succeeded and verified that there are no changes...
133 /// 1. DON'T call CachingComponentBase::Set
134 /// 2. call UpdateStatisticsScope::FinishNoChanges
135 /// 3. return normally (an exception is allowed in edge cases)
136 ///
137 /// C. If the update failed...
138 /// 1. DON'T call CachingComponentBase::Set
139 /// 2. call UpdateStatisticsScope::FinishWithError, or...
140 /// 3. throw an exception, which will be logged nicely
141 /// (if there already is an exception, prefer rethrowing it instead
142 /// of calling UpdateStatisticsScope::FinishWithError)
143 ///
144 /// @param type type of the update
145 /// @param last_update time of the last update (value of `now` from previous
146 /// invocation of Update or default constructed value if this is the first
147 /// Update).
148 /// @param now current time point
149 /// @param stats_scope the scope that expects
150 /// one of `Finish`, `FinishNoChanges`, `FinishWithError` or an exception.
151 ///
152 /// @throws std::exception on update failure
153 ///
154 /// @warning If `Update` returns without throwing an exception and without
155 /// calling one of the `Finish*` methods, the behavior is undefined.
156 ///
157 /// @see @ref scripts/docs/en/userver/caches.md
158 virtual void Update(
159 UpdateType type,
160 const std::chrono::system_clock::time_point& last_update,
161 const std::chrono::system_clock::time_point& now,
162 UpdateStatisticsScope& stats_scope
163 ) = 0;
164
165 /// @brief Returns flags for cache start.
166 virtual utils::Flags<Flag> GetStartFlags() const;
167
168 /// @brief Call this to start periodic updates just now,
169 /// not after the constructor.
171
172 /// @cond
173 // For internal use only
174 void EarlyStopPeriodicUpdates();
175 /// @endcond
176
177private:
178 void StartPeriodicUpdates();
179
180 void StopPeriodicUpdates();
181
182 virtual void Cleanup() = 0;
183
184 virtual void MarkAsExpired();
185
186 virtual void GetAndWrite(dump::Writer& writer) const;
187
188 virtual void ReadAndSet(dump::Reader& reader);
189
190 class Impl;
191 std::unique_ptr<Impl> impl_;
192};
193
194} // namespace cache
195
196USERVER_NAMESPACE_END