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_base.hpp>
16#include <userver/components/component_fwd.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
155 CachingComponentBase(
const ComponentConfig& config,
const ComponentContext&);
156 ~CachingComponentBase()
override;
168 utils::SharedReadablePtr<T>
Get()
const;
175 template <
class Class>
177 UpdateAndListen(Class* obj, std::string name,
void (Class::*func)(
const std::shared_ptr<
const T>&));
181 static yaml_config::Schema GetStaticConfigSchema();
189 void Set(std::unique_ptr<
const T> value_ptr);
195 template <
typename... Args>
196 void Emplace(Args&&... args);
208 virtual std::unique_ptr<
const T> ReadContents(dump::Reader& reader)
const;
214 virtual void PreAssignCheck(
const T* old_value_ptr,
const T* new_value_ptr)
const;
217 void OnAllComponentsLoaded()
final;
219 void Cleanup()
final;
221 void MarkAsExpired()
final;
223 void GetAndWrite(
dump::
Writer& writer)
const final;
226 std::shared_ptr<
const T> TransformNewValue(std::unique_ptr<
const T> new_value);
228 rcu::Variable<std::shared_ptr<
const T>> cache_;
230 utils::impl::WaitTokenStorage wait_token_storage_;
234CachingComponentBase<T>::CachingComponentBase(
const ComponentConfig& config,
const ComponentContext& context)
238 const auto ptr = cache_.ReadCopy();
239 if (ptr) function(ptr);
241 const auto initial_config = GetConfig();
247 cache_.Assign(
nullptr);
250 wait_token_storage_.WaitForAllTokens();
263template <
typename Class>
267 void (Class::*func)(
const std::shared_ptr<
const T>&)
269 return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] {
277 return event_channel_;
282 return utils::SharedReadablePtr<T>(cache_.ReadCopy());
287 const std::shared_ptr<
const T> new_value = TransformNewValue(std::move(value_ptr));
289 if (HasPreAssignCheck()) {
290 auto old_value = cache_.Read();
291 PreAssignCheck(old_value->get(), new_value.get());
294 cache_.Assign(new_value);
295 event_channel_.SendEvent(new_value);
301 Emplace(std::move(value));
305template <
typename... Args>
307 Set(std::make_unique<T>(std::forward<Args>(args)...)
);
312 cache_.Assign(std::make_unique<
const T>());
323 if (!contents)
throw cache::EmptyCacheError(
Name());
329 auto data = ReadContents(reader);
330 if constexpr (meta::kIsSizable<T>) {
332 SetDataSizeStatistic(std::size(*data));
335 Set(std::move(data));
340 if constexpr (
dump::kIsDumpable<T>) {
341 writer.Write(contents);
349 if constexpr (
dump::kIsDumpable<T>) {
351 return std::unique_ptr<
const T>{
new T(reader.Read<T>())};
359 AssertPeriodicUpdateStarted();
369 Set(std::unique_ptr<
const T>{});
374yaml_config::Schema GetCachingComponentBaseSchema();
376template <
typename T,
typename Deleter>
377auto MakeAsyncDeleter(engine::TaskProcessor& task_processor, Deleter deleter) {
378 return [&task_processor, deleter = std::move(deleter)](
const T* raw_ptr)
mutable {
379 std::unique_ptr<
const T, Deleter> ptr(raw_ptr, std::move(deleter));
381 engine::CriticalAsyncNoSpan(task_processor, [ptr = std::move(ptr)]()
mutable {}).Detach();
389 return impl::GetCachingComponentBaseSchema();
397 "{} type does not support std::size(), add implementation of "
398 "the method size() for this type or "
399 "override cache::CachingComponentBase::PreAssignCheck.",
400 compiler::GetTypeName<T>()
404 if constexpr (meta::kIsSizable<T>) {
405 if (!new_value_ptr || std::size(*new_value_ptr) == 0) {
412std::shared_ptr<
const T>
CachingComponentBase<T>::TransformNewValue(std::unique_ptr<
const T> new_value) {
414 if (IsSafeDataLifetime()) {
416 auto deleter_with_token = [token = wait_token_storage_.GetToken()](
const T* raw_ptr) {
418 std::default_delete<
const T>{}(raw_ptr);
420 return std::shared_ptr<
const T>(
421 new_value.release(), impl::MakeAsyncDeleter<T>(GetCacheTaskProcessor(), std::move(deleter_with_token))
424 return std::shared_ptr<
const T>(
425 new_value.release(), impl::MakeAsyncDeleter<T>(GetCacheTaskProcessor(), std::default_delete<
const T>{})