10#include <fmt/format.h>
12#include <userver/cache/cache_update_trait.hpp>
13#include <userver/cache/exceptions.hpp>
14#include <userver/compiler/demangle.hpp>
15#include <userver/components/component_fwd.hpp>
16#include <userver/components/loggable_component_base.hpp>
17#include <userver/concurrent/async_event_channel.hpp>
18#include <userver/dump/helpers.hpp>
19#include <userver/dump/meta.hpp>
20#include <userver/dump/operations.hpp>
21#include <userver/engine/async.hpp>
22#include <userver/rcu/rcu.hpp>
23#include <userver/utils/assert.hpp>
24#include <userver/utils/impl/wait_token_storage.hpp>
25#include <userver/utils/meta.hpp>
26#include <userver/utils/shared_readable_ptr.hpp>
27#include <userver/yaml_config/schema.hpp>
29USERVER_NAMESPACE_BEGIN
128 CachingComponentBase(
const ComponentConfig& config,
const ComponentContext&);
129 ~CachingComponentBase()
override;
137 utils::SharedReadablePtr<T>
Get()
const;
144 template <
class Class>
146 Class* obj, std::string name,
147 void (Class::*func)(
const std::shared_ptr<
const T>&));
152 static yaml_config::Schema GetStaticConfigSchema();
155 void Set(std::unique_ptr<
const T> value_ptr);
158 template <
typename... Args>
159 void Emplace(Args&&... args);
172 virtual std::unique_ptr<
const T> ReadContents(dump::Reader& reader)
const;
179 const T* new_value_ptr)
const;
182 void OnAllComponentsLoaded()
final;
184 void Cleanup()
final;
186 void MarkAsExpired()
final;
188 void GetAndWrite(
dump::
Writer& writer)
const final;
191 rcu::Variable<std::shared_ptr<
const T>> cache_;
193 utils::impl::WaitTokenStorage wait_token_storage_;
198 const ComponentContext& context)
202 [
this](
auto& function) {
203 const auto ptr = cache_.ReadCopy();
204 if (ptr) function(ptr);
206 const auto initial_config = GetConfig();
212 cache_.Assign(
nullptr);
215 wait_token_storage_.WaitForAllTokens();
222 throw cache::EmptyCacheError(
Name());
228template <
typename Class>
230 Class* obj, std::string name,
231 void (Class::*func)(
const std::shared_ptr<
const T>&)) {
232 return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] {
241 return event_channel_;
246 return utils::SharedReadablePtr<T>(cache_.ReadCopy());
251 auto deleter = [token = wait_token_storage_.GetToken(),
252 &cache_task_processor =
253 GetCacheTaskProcessor()](
const T* raw_ptr)
mutable {
254 std::unique_ptr<
const T> ptr{raw_ptr};
257 engine::CriticalAsyncNoSpan(cache_task_processor, [ptr = std::move(ptr),
265 const std::shared_ptr<
const T> new_value(value_ptr.release(),
268 if (HasPreAssignCheck()) {
269 auto old_value = cache_.Read();
270 PreAssignCheck(old_value->get(), new_value.get());
273 cache_.Assign(new_value);
274 event_channel_.SendEvent(new_value);
280 Emplace(std::move(value));
284template <
typename... Args>
286 Set(std::make_unique<T>(std::forward<Args>(args)...));
291 cache_.Assign(std::make_unique<
const T>());
302 if (!contents)
throw cache::EmptyCacheError(
Name());
308 auto data = ReadContents(reader);
309 if constexpr (meta::kIsSizable<T>) {
311 SetDataSizeStatistic(std::size(*data));
314 Set(std::move(data));
319 const T& contents)
const {
320 if constexpr (
dump::kIsDumpable<T>) {
321 writer.Write(contents);
329 dump::Reader& reader)
const {
330 if constexpr (
dump::kIsDumpable<T>) {
332 return std::unique_ptr<
const T>{
new T(reader.Read<T>())};
340 AssertPeriodicUpdateStarted();
350 Set(std::unique_ptr<
const T>{});
355yaml_config::Schema GetCachingComponentBaseSchema();
361 return impl::GetCachingComponentBaseSchema();
366 const T*, [[
maybe_unused]]
const T* new_value_ptr)
const {
369 fmt::format(
"{} type does not support std::size(), add implementation of "
370 "the method size() for this type or "
371 "override cache::CachingComponentBase::PreAssignCheck.",
372 compiler::GetTypeName<T>()));
374 if constexpr (meta::kIsSizable<T>) {
375 if (!new_value_ptr || std::size(*new_value_ptr) == 0) {
376 throw cache::EmptyDataError(
Name());