LCOV - code coverage report
Current view: top level - source/common/stats - deferred_creation.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 9 33 27.3 %
Date: 2024-01-05 06:35:25 Functions: 3 10 30.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "envoy/common/pure.h"
       4             : #include "envoy/stats/scope.h"
       5             : #include "envoy/stats/stats.h"
       6             : 
       7             : #include "source/common/common/cleanup.h"
       8             : #include "source/common/common/thread.h"
       9             : #include "source/common/stats/symbol_table.h"
      10             : #include "source/common/stats/utility.h"
      11             : 
      12             : namespace Envoy {
      13             : namespace Stats {
      14             : 
      15             : /**
      16             :  * Lazy-initialization wrapper for StatsStructType, intended for deferred instantiation of a block
      17             :  * of stats that might not be needed in a given Envoy process.
      18             :  *
      19             :  * This class is thread-safe -- instantiations can occur on multiple concurrent threads.
      20             :  * This is used when
      21             :  * :ref:`enable_deferred_creation_stats
      22             :  * <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.deferred_stat_options>` is enabled.
      23             :  */
      24             : template <typename StatsStructType>
      25             : class DeferredStats : public DeferredCreationCompatibleInterface<StatsStructType> {
      26             : public:
      27             :   // Capture the stat names object and the scope with a ctor, that can be used to instantiate a
      28             :   // StatsStructType object later.
      29             :   // Caller should make sure scope and stat_names outlive this object.
      30             :   DeferredStats(const typename StatsStructType::StatNameType& stat_names,
      31             :                 Stats::ScopeSharedPtr scope)
      32             :       : initialized_(
      33             :             // A lambda is used as we need to register the name into the symbol table.
      34             :             // Note: there is no issue to capture a reference of the scope here as this lambda is
      35             :             // only used to initialize the 'initialized_' Gauge.
      36           0 :             [&scope]() -> Gauge& {
      37           0 :               Stats::StatNamePool pool(scope->symbolTable());
      38           0 :               return Stats::Utility::gaugeFromElements(
      39           0 :                   *scope, {pool.add(StatsStructType::typeName()), pool.add("initialized")},
      40           0 :                   Stats::Gauge::ImportMode::HiddenAccumulate);
      41           0 :             }()),
      42           0 :         ctor_([this, &stat_names, stats_scope = std::move(scope)]() -> StatsStructType* {
      43           0 :           initialized_.inc();
      44             :           // Reset ctor_ to save some RAM.
      45           0 :           Cleanup reset_ctor([this] { ctor_ = nullptr; });
      46           0 :           return new StatsStructType(stat_names, *stats_scope);
      47           0 :         }) {
      48           0 :     if (initialized_.value() > 0) {
      49           0 :       getOrCreateHelper();
      50           0 :     }
      51           0 :   }
      52           0 :   ~DeferredStats() override {
      53           0 :     if (ctor_ == nullptr) {
      54           0 :       initialized_.dec();
      55           0 :     }
      56           0 :   }
      57           0 :   inline StatsStructType& getOrCreate() override { return getOrCreateHelper(); }
      58             : 
      59             : private:
      60             :   // We can't call getOrCreate directly from constructor, otherwise the compiler complains about
      61             :   // bypassing virtual dispatch even though it's fine.
      62           0 :   inline StatsStructType& getOrCreateHelper() { return *internal_stats_.get(ctor_); }
      63             : 
      64             :   // In order to preserve stat value continuity across a config reload, we need to automatically
      65             :   // re-instantiate lazy stats when they are constructed, if there is already a live instantiation
      66             :   // to the same stats. Consider the following alternate scenarios:
      67             : 
      68             :   // Scenario 1: a cluster is instantiated but receives no requests, so its traffic-related stats
      69             :   // are never instantiated. When this cluster gets reloaded on a config update, a new lazy-init
      70             :   // block is created, but the stats should again not be instantiated.
      71             : 
      72             :   // Scenario 2: a cluster is instantiated and receives traffic, so its traffic-related stats are
      73             :   // instantiated. We must ensure that a new instance for the same cluster gets its lazy-stats
      74             :   // instantiated before the previous cluster of the same name is destructed.
      75             : 
      76             :   // To do that we keep an "initialized" gauge in the cluster's scope, which will be associated by
      77             :   // name to the previous generation's cluster's lazy-init block. We use the value in this shared
      78             :   // gauge to determine whether to instantiate the lazy block on construction.
      79             :   Gauge& initialized_;
      80             :   // TODO(#26957): Clean up this ctor_ by moving its ownership to AtomicPtr, and drop
      81             :   // the setter lambda when the nested object is created.
      82             :   std::function<StatsStructType*()> ctor_;
      83             :   Thread::AtomicPtr<StatsStructType, Thread::AtomicPtrAllocMode::DeleteOnDestruct> internal_stats_;
      84             : };
      85             : 
      86             : // Non-deferred wrapper over StatsStructType. This is used when
      87             : // :ref:`enable_deferred_creation_stats
      88             : // <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.deferred_stat_options>` is not enabled.
      89             : template <typename StatsStructType>
      90             : class DirectStats : public DeferredCreationCompatibleInterface<StatsStructType> {
      91             : public:
      92             :   DirectStats(const typename StatsStructType::StatNameType& stat_names, Stats::Scope& scope)
      93        2376 :       : stats_(stat_names, scope) {}
      94        2529 :   inline StatsStructType& getOrCreate() override { return stats_; }
      95             : 
      96             : private:
      97             :   StatsStructType stats_;
      98             : };
      99             : 
     100             : // Template that lazily initializes a StatsStruct.
     101             : // The bootstrap config :ref:`enable_deferred_creation_stats
     102             : // <envoy_v3_api_field_config.bootstrap.v3.Bootstrap.deferred_stat_options>` decides if
     103             : // stats lazy initialization is enabled or not.
     104             : template <typename StatsStructType>
     105             : DeferredCreationCompatibleStats<StatsStructType>
     106             : createDeferredCompatibleStats(Stats::ScopeSharedPtr scope,
     107             :                               const typename StatsStructType::StatNameType& stat_names,
     108        2376 :                               bool defer_creation) {
     109        2376 :   if (defer_creation) {
     110           0 :     return DeferredCreationCompatibleStats<StatsStructType>(
     111           0 :         std::make_unique<DeferredStats<StatsStructType>>(stat_names, scope));
     112        2376 :   } else {
     113        2376 :     return DeferredCreationCompatibleStats<StatsStructType>(
     114        2376 :         std::make_unique<DirectStats<StatsStructType>>(stat_names, *scope));
     115        2376 :   }
     116        2376 : }
     117             : 
     118             : } // namespace Stats
     119             : } // namespace Envoy

Generated by: LCOV version 1.15