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
156 CachingComponentBase(
const ComponentConfig& config,
const ComponentContext&);
157 ~CachingComponentBase()
override;
167 utils::SharedReadablePtr<T>
Get()
const;
174 template <
class Class>
176 Class* obj, std::string name,
177 void (Class::*func)(
const std::shared_ptr<
const T>&));
182 static yaml_config::Schema GetStaticConfigSchema();
190 void Set(std::unique_ptr<
const T> value_ptr);
196 template <
typename... Args>
197 void Emplace(Args&&... args);
209 virtual std::unique_ptr<
const T> ReadContents(dump::Reader& reader)
const;
216 const T* new_value_ptr)
const;
219 void OnAllComponentsLoaded()
final;
221 void Cleanup()
final;
223 void MarkAsExpired()
final;
225 void GetAndWrite(
dump::
Writer& writer)
const final;
228 std::shared_ptr<
const T> TransformNewValue(
229 std::unique_ptr<
const T> new_value);
231 rcu::Variable<std::shared_ptr<
const T>> cache_;
233 utils::impl::WaitTokenStorage wait_token_storage_;
238 const ComponentContext& context)
242 [
this](
auto& function) {
243 const auto ptr = cache_.ReadCopy();
244 if (ptr) function(ptr);
246 const auto initial_config = GetConfig();
252 cache_.Assign(
nullptr);
255 wait_token_storage_.WaitForAllTokens();
268template <
typename Class>
270 Class* obj, std::string name,
271 void (Class::*func)(
const std::shared_ptr<
const T>&)) {
272 return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] {
281 return event_channel_;
286 return utils::SharedReadablePtr<T>(cache_.ReadCopy());
291 const std::shared_ptr<
const T> new_value =
292 TransformNewValue(std::move(value_ptr));
294 if (HasPreAssignCheck()) {
295 auto old_value = cache_.Read();
296 PreAssignCheck(old_value->get(), new_value.get());
299 cache_.Assign(new_value);
300 event_channel_.SendEvent(new_value);
306 Emplace(std::move(value));
310template <
typename... Args>
312 Set(std::make_unique<T>(std::forward<Args>(args)...)
);
317 cache_.Assign(std::make_unique<
const T>());
328 if (!contents)
throw cache::EmptyCacheError(
Name());
334 auto data = ReadContents(reader);
335 if constexpr (meta::kIsSizable<T>) {
337 SetDataSizeStatistic(std::size(*data));
340 Set(std::move(data));
345 const T& contents)
const {
346 if constexpr (
dump::kIsDumpable<T>) {
347 writer.Write(contents);
355 dump::Reader& reader)
const {
356 if constexpr (
dump::kIsDumpable<T>) {
358 return std::unique_ptr<
const T>{
new T(reader.Read<T>())};
366 AssertPeriodicUpdateStarted();
376 Set(std::unique_ptr<
const T>{});
381yaml_config::Schema GetCachingComponentBaseSchema();
383template <
typename T,
typename Deleter>
384auto MakeAsyncDeleter(engine::TaskProcessor& task_processor, Deleter deleter) {
385 return [&task_processor,
386 deleter = std::move(deleter)](
const T* raw_ptr)
mutable {
387 std::unique_ptr<
const T, Deleter> ptr(raw_ptr, std::move(deleter));
389 engine::CriticalAsyncNoSpan(task_processor, [ptr =
390 std::move(ptr)]()
mutable {
399 return impl::GetCachingComponentBaseSchema();
404 const T*, [[
maybe_unused]]
const T* new_value_ptr)
const {
407 fmt::format(
"{} type does not support std::size(), add implementation of "
408 "the method size() for this type or "
409 "override cache::CachingComponentBase::PreAssignCheck.",
410 compiler::GetTypeName<T>()));
412 if constexpr (meta::kIsSizable<T>) {
413 if (!new_value_ptr || std::size(*new_value_ptr) == 0) {
421 std::unique_ptr<
const T> new_value) {
423 if (IsSafeDataLifetime()) {
425 auto deleter_with_token =
426 [token = wait_token_storage_.GetToken()](
const T* raw_ptr) {
428 std::default_delete<
const T>{}(raw_ptr);
430 return std::shared_ptr<
const T>(
432 impl::MakeAsyncDeleter<T>(GetCacheTaskProcessor(),
433 std::move(deleter_with_token)));
435 return std::shared_ptr<
const T>(
437 impl::MakeAsyncDeleter<T>(GetCacheTaskProcessor(),
438 std::default_delete<
const T>{}));