LCOV - code coverage report
Current view: top level - source/common/stats - isolated_store_impl.h (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 108 213 50.7 %
Date: 2024-01-05 06:35:25 Functions: 32 80 40.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <algorithm>
       4             : #include <cstring>
       5             : #include <functional>
       6             : #include <string>
       7             : 
       8             : #include "envoy/stats/stats.h"
       9             : #include "envoy/stats/store.h"
      10             : 
      11             : #include "source/common/common/utility.h"
      12             : #include "source/common/stats/allocator_impl.h"
      13             : #include "source/common/stats/null_counter.h"
      14             : #include "source/common/stats/null_gauge.h"
      15             : #include "source/common/stats/symbol_table.h"
      16             : #include "source/common/stats/tag_utility.h"
      17             : #include "source/common/stats/utility.h"
      18             : 
      19             : #include "absl/container/flat_hash_map.h"
      20             : 
      21             : namespace Envoy {
      22             : namespace Stats {
      23             : 
      24             : /**
      25             :  * A stats cache template that is used by the isolated store.
      26             :  */
      27             : template <class Base> class IsolatedStatsCache {
      28             : public:
      29             :   using CounterAllocator = std::function<RefcountPtr<Base>(
      30             :       const TagUtility::TagStatNameJoiner& joiner, StatNameTagVectorOptConstRef tags)>;
      31             :   using GaugeAllocator =
      32             :       std::function<RefcountPtr<Base>(const TagUtility::TagStatNameJoiner& joiner,
      33             :                                       StatNameTagVectorOptConstRef tags, Gauge::ImportMode)>;
      34             :   using HistogramAllocator =
      35             :       std::function<RefcountPtr<Base>(const TagUtility::TagStatNameJoiner& joiner,
      36             :                                       StatNameTagVectorOptConstRef tags, Histogram::Unit)>;
      37             :   using TextReadoutAllocator =
      38             :       std::function<RefcountPtr<Base>(const TagUtility::TagStatNameJoiner& joiner,
      39             :                                       StatNameTagVectorOptConstRef tags, TextReadout::Type)>;
      40             :   using BaseOptConstRef = absl::optional<std::reference_wrapper<const Base>>;
      41             : 
      42       21325 :   IsolatedStatsCache(CounterAllocator alloc) : counter_alloc_(alloc) {}
      43       21325 :   IsolatedStatsCache(GaugeAllocator alloc) : gauge_alloc_(alloc) {}
      44       21325 :   IsolatedStatsCache(HistogramAllocator alloc) : histogram_alloc_(alloc) {}
      45       21325 :   IsolatedStatsCache(TextReadoutAllocator alloc) : text_readout_alloc_(alloc) {}
      46             : 
      47             :   Base& get(StatName prefix, StatName basename, StatNameTagVectorOptConstRef tags,
      48      264650 :             SymbolTable& symbol_table) {
      49      264650 :     TagUtility::TagStatNameJoiner joiner(prefix, basename, tags, symbol_table);
      50      264650 :     StatName name = joiner.nameWithTags();
      51      264650 :     auto stat = stats_.find(name);
      52      264650 :     if (stat != stats_.end()) {
      53       41988 :       return *stat->second;
      54       41988 :     }
      55             : 
      56      222662 :     RefcountPtr<Base> new_stat = counter_alloc_(joiner, tags);
      57      222662 :     stats_.emplace(new_stat->statName(), new_stat);
      58      222662 :     return *new_stat;
      59      264650 :   }
      60             : 
      61             :   Base& get(StatName prefix, StatName basename, StatNameTagVectorOptConstRef tags,
      62       68595 :             SymbolTable& symbol_table, Gauge::ImportMode import_mode) {
      63       68595 :     TagUtility::TagStatNameJoiner joiner(prefix, basename, tags, symbol_table);
      64       68595 :     StatName name = joiner.nameWithTags();
      65       68595 :     auto stat = stats_.find(name);
      66       68595 :     if (stat != stats_.end()) {
      67        8675 :       return *stat->second;
      68        8675 :     }
      69             : 
      70       59920 :     RefcountPtr<Base> new_stat = gauge_alloc_(joiner, tags, import_mode);
      71       59920 :     stats_.emplace(new_stat->statName(), new_stat);
      72       59920 :     return *new_stat;
      73       68595 :   }
      74             : 
      75             :   Base& get(StatName prefix, StatName basename, StatNameTagVectorOptConstRef tags,
      76       18922 :             SymbolTable& symbol_table, Histogram::Unit unit) {
      77       18922 :     TagUtility::TagStatNameJoiner joiner(prefix, basename, tags, symbol_table);
      78       18922 :     StatName name = joiner.nameWithTags();
      79       18922 :     auto stat = stats_.find(name);
      80       18922 :     if (stat != stats_.end()) {
      81           0 :       return *stat->second;
      82           0 :     }
      83             : 
      84       18922 :     RefcountPtr<Base> new_stat = histogram_alloc_(joiner, tags, unit);
      85       18922 :     stats_.emplace(new_stat->statName(), new_stat);
      86       18922 :     return *new_stat;
      87       18922 :   }
      88             : 
      89             :   Base& get(StatName prefix, StatName basename, StatNameTagVectorOptConstRef tags,
      90           2 :             SymbolTable& symbol_table, TextReadout::Type type) {
      91           2 :     TagUtility::TagStatNameJoiner joiner(prefix, basename, tags, symbol_table);
      92           2 :     StatName name = joiner.nameWithTags();
      93           2 :     auto stat = stats_.find(name);
      94           2 :     if (stat != stats_.end()) {
      95           0 :       return *stat->second;
      96           0 :     }
      97             : 
      98           2 :     RefcountPtr<Base> new_stat = text_readout_alloc_(joiner, tags, type);
      99           2 :     stats_.emplace(new_stat->statName(), new_stat);
     100           2 :     return *new_stat;
     101           2 :   }
     102             : 
     103           0 :   std::vector<RefcountPtr<Base>> toVector() const {
     104           0 :     std::vector<RefcountPtr<Base>> vec;
     105           0 :     vec.reserve(stats_.size());
     106           0 :     for (auto& stat : stats_) {
     107           0 :       vec.push_back(stat.second);
     108           0 :     }
     109             : 
     110           0 :     return vec;
     111           0 :   }
     112             : 
     113           0 :   bool iterate(const IterateFn<Base>& fn) const {
     114           0 :     for (auto& stat : stats_) {
     115           0 :       if (!fn(stat.second)) {
     116           0 :         return false;
     117           0 :       }
     118           0 :     }
     119           0 :     return true;
     120           0 :   }
     121             : 
     122          39 :   void forEachStat(SizeFn f_size, StatFn<Base> f_stat) const {
     123          39 :     if (f_size != nullptr) {
     124          39 :       f_size(stats_.size());
     125          39 :     }
     126        1630 :     for (auto const& stat : stats_) {
     127        1630 :       f_stat(*stat.second);
     128        1630 :     }
     129          39 :   }
     130             : 
     131           0 :   BaseOptConstRef find(StatName name) const {
     132           0 :     auto stat = stats_.find(name);
     133           0 :     if (stat == stats_.end()) {
     134           0 :       return absl::nullopt;
     135           0 :     }
     136           0 :     return std::cref(*stat->second);
     137           0 :   }
     138             : 
     139             : private:
     140             :   StatNameHashMap<RefcountPtr<Base>> stats_;
     141             :   CounterAllocator counter_alloc_;
     142             :   GaugeAllocator gauge_alloc_;
     143             :   HistogramAllocator histogram_alloc_;
     144             :   TextReadoutAllocator text_readout_alloc_;
     145             : };
     146             : 
     147             : // Isolated implementation of Stats::Store. This class is not thread-safe by
     148             : // itself, but a thread-safe wrapper can be built, e.g. TestIsolatedStoreImpl
     149             : // in test/integration/server.h.
     150             : class IsolatedStoreImpl : public Store {
     151             : public:
     152             :   IsolatedStoreImpl();
     153             :   explicit IsolatedStoreImpl(SymbolTable& symbol_table);
     154             :   ~IsolatedStoreImpl() override;
     155             : 
     156             :   // Stats::Store
     157           0 :   const SymbolTable& constSymbolTable() const override { return alloc_.constSymbolTable(); }
     158     1575829 :   SymbolTable& symbolTable() override { return alloc_.symbolTable(); }
     159             : 
     160         360 :   void deliverHistogramToSinks(const Histogram&, uint64_t) override {}
     161             :   ScopeSharedPtr rootScope() override;
     162             :   ConstScopeSharedPtr constRootScope() const override;
     163           0 :   std::vector<CounterSharedPtr> counters() const override { return counters_.toVector(); }
     164           0 :   std::vector<GaugeSharedPtr> gauges() const override {
     165             :     // TODO(jmarantz): should we filter out gauges where
     166             :     // gauge.importMode() != Gauge::ImportMode::Uninitialized ?
     167             :     // I don't think this matters because that should only occur for gauges
     168             :     // received in a hot-restart transfer, and isolated-store gauges should
     169             :     // never be transmitted that way.
     170           0 :     return gauges_.toVector();
     171           0 :   }
     172           0 :   std::vector<ParentHistogramSharedPtr> histograms() const override {
     173           0 :     return std::vector<ParentHistogramSharedPtr>{};
     174           0 :   }
     175           0 :   std::vector<TextReadoutSharedPtr> textReadouts() const override {
     176           0 :     return text_readouts_.toVector();
     177           0 :   }
     178             : 
     179          13 :   void forEachCounter(SizeFn f_size, StatFn<Counter> f_stat) const override {
     180          13 :     counters_.forEachStat(f_size, f_stat);
     181          13 :   }
     182             : 
     183          13 :   void forEachGauge(SizeFn f_size, StatFn<Gauge> f_stat) const override {
     184          13 :     gauges_.forEachStat(f_size, f_stat);
     185          13 :   }
     186             : 
     187          13 :   void forEachTextReadout(SizeFn f_size, StatFn<TextReadout> f_stat) const override {
     188          13 :     text_readouts_.forEachStat(f_size, f_stat);
     189          13 :   }
     190             : 
     191           0 :   void forEachHistogram(SizeFn f_size, StatFn<ParentHistogram> f_stat) const override {
     192           0 :     UNREFERENCED_PARAMETER(f_size);
     193           0 :     UNREFERENCED_PARAMETER(f_stat);
     194           0 :   }
     195             : 
     196           0 :   void forEachScope(SizeFn f_size, StatFn<const Scope> f_stat) const override {
     197           0 :     if (f_size != nullptr) {
     198           0 :       f_size(scopes_.size() + 1);
     199           0 :     }
     200           0 :     f_stat(*constRootScope());
     201           0 :     for (const ScopeSharedPtr& scope : scopes_) {
     202           0 :       f_stat(*scope);
     203           0 :     }
     204           0 :   }
     205             : 
     206          13 :   void forEachSinkedCounter(SizeFn f_size, StatFn<Counter> f_stat) const override {
     207          13 :     forEachCounter(f_size, f_stat);
     208          13 :   }
     209             : 
     210          13 :   void forEachSinkedGauge(SizeFn f_size, StatFn<Gauge> f_stat) const override {
     211          13 :     forEachGauge(f_size, f_stat);
     212          13 :   }
     213             : 
     214          13 :   void forEachSinkedTextReadout(SizeFn f_size, StatFn<TextReadout> f_stat) const override {
     215          13 :     forEachTextReadout(f_size, f_stat);
     216          13 :   }
     217             : 
     218          13 :   void forEachSinkedHistogram(SizeFn f_size, StatFn<ParentHistogram> f_stat) const override {
     219          13 :     UNREFERENCED_PARAMETER(f_size);
     220          13 :     UNREFERENCED_PARAMETER(f_stat);
     221          13 :   }
     222             : 
     223           0 :   NullCounterImpl& nullCounter() override { return *null_counter_; }
     224           0 :   NullGaugeImpl& nullGauge() override { return *null_gauge_; }
     225             : 
     226           0 :   bool iterate(const IterateFn<Counter>& fn) const override {
     227           0 :     return constRootScope()->iterate(fn);
     228           0 :   }
     229           0 :   bool iterate(const IterateFn<Gauge>& fn) const override { return constRootScope()->iterate(fn); }
     230           0 :   bool iterate(const IterateFn<Histogram>& fn) const override {
     231           0 :     return constRootScope()->iterate(fn);
     232           0 :   }
     233           0 :   bool iterate(const IterateFn<TextReadout>& fn) const override {
     234           0 :     return constRootScope()->iterate(fn);
     235           0 :   }
     236             : 
     237           0 :   void extractAndAppendTags(StatName, StatNamePool&, StatNameTagVector&) override {}
     238           0 :   void extractAndAppendTags(absl::string_view, StatNamePool&, StatNameTagVector&) override {}
     239           0 :   const TagVector& fixedTags() override { CONSTRUCT_ON_FIRST_USE(TagVector); }
     240             : 
     241             : protected:
     242             :   /**
     243             :    * Provides a hook for sub-classes to define how to create new scopes. When
     244             :    * subclassing IsolatedStoreImpl you likely want to also subclass
     245             :    * IsolatedScopeImpl. Overriding this method enables scopes of the appropriate
     246             :    * type to be created from Store::rootScope(), Scope::scopeFromStatName, and
     247             :    * Scope::createScope, without needing to override those. makeScope is usually
     248             :    * implemented by "return std::make_shared<YourScopeType>(name, *this)".
     249             :    *
     250             :    * @param name the fully qualified stat name -- no further prefixing needed.
     251             :    */
     252             :   virtual ScopeSharedPtr makeScope(StatName name);
     253             : 
     254             : private:
     255             :   friend class IsolatedScopeImpl;
     256             : 
     257             :   IsolatedStoreImpl(std::unique_ptr<SymbolTable>&& symbol_table);
     258             : 
     259             :   SymbolTablePtr symbol_table_storage_;
     260             :   AllocatorImpl alloc_;
     261             :   IsolatedStatsCache<Counter> counters_;
     262             :   IsolatedStatsCache<Gauge> gauges_;
     263             :   IsolatedStatsCache<Histogram> histograms_;
     264             :   IsolatedStatsCache<TextReadout> text_readouts_;
     265             :   RefcountPtr<NullCounterImpl> null_counter_;
     266             :   RefcountPtr<NullGaugeImpl> null_gauge_;
     267             : 
     268             :   // We construct the default-scope lazily to allow subclasses to override
     269             :   // makeScope(), making it easier to share infrastructure across subclasses
     270             :   // around managing scopes. Since you can't call an overridden virtual method
     271             :   // from a parent-class constructor, we instantiate this lazily after the
     272             :   // object has been fully constructed.
     273             :   //
     274             :   // This technically does not need to be declared mutable, but is conceptually
     275             :   // mutable because we can update this in the const method constRootScope().
     276             :   mutable ScopeSharedPtr lazy_default_scope_;
     277             : 
     278             :   std::vector<ScopeSharedPtr> scopes_;
     279             : };
     280             : 
     281             : class IsolatedScopeImpl : public Scope {
     282             : public:
     283             :   IsolatedScopeImpl(const std::string& prefix, IsolatedStoreImpl& store)
     284           0 :       : prefix_(prefix, store.symbolTable()), store_(store) {}
     285             : 
     286             :   IsolatedScopeImpl(StatName prefix, IsolatedStoreImpl& store)
     287       24713 :       : prefix_(prefix, store.symbolTable()), store_(store) {}
     288             : 
     289       24713 :   ~IsolatedScopeImpl() override { prefix_.free(store_.symbolTable()); }
     290             : 
     291             :   // Stats::Scope
     292     1428747 :   SymbolTable& symbolTable() override { return store_.symbolTable(); }
     293           0 :   const SymbolTable& constSymbolTable() const override { return store_.symbolTable(); }
     294             :   Counter& counterFromStatNameWithTags(const StatName& name,
     295      264650 :                                        StatNameTagVectorOptConstRef tags) override {
     296      264650 :     return store_.counters_.get(prefix(), name, tags, symbolTable());
     297      264650 :   }
     298             :   ScopeSharedPtr createScope(const std::string& name) override;
     299             :   ScopeSharedPtr scopeFromStatName(StatName name) override;
     300             :   Gauge& gaugeFromStatNameWithTags(const StatName& name, StatNameTagVectorOptConstRef tags,
     301       68595 :                                    Gauge::ImportMode import_mode) override {
     302       68595 :     Gauge& gauge = store_.gauges_.get(prefix(), name, tags, symbolTable(), import_mode);
     303       68595 :     gauge.mergeImportMode(import_mode);
     304       68595 :     return gauge;
     305       68595 :   }
     306             :   Histogram& histogramFromStatNameWithTags(const StatName& name, StatNameTagVectorOptConstRef tags,
     307       18922 :                                            Histogram::Unit unit) override {
     308       18922 :     return store_.histograms_.get(prefix(), name, tags, symbolTable(), unit);
     309       18922 :   }
     310             :   TextReadout& textReadoutFromStatNameWithTags(const StatName& name,
     311           2 :                                                StatNameTagVectorOptConstRef tags) override {
     312           2 :     return store_.text_readouts_.get(prefix(), name, tags, symbolTable(),
     313           2 :                                      TextReadout::Type::Default);
     314           2 :   }
     315           0 :   CounterOptConstRef findCounter(StatName name) const override {
     316           0 :     return store_.counters_.find(name);
     317           0 :   }
     318           0 :   GaugeOptConstRef findGauge(StatName name) const override { return store_.gauges_.find(name); }
     319           0 :   HistogramOptConstRef findHistogram(StatName name) const override {
     320           0 :     return store_.histograms_.find(name);
     321           0 :   }
     322           0 :   TextReadoutOptConstRef findTextReadout(StatName name) const override {
     323           0 :     return store_.text_readouts_.find(name);
     324           0 :   }
     325             : 
     326           0 :   bool iterate(const IterateFn<Counter>& fn) const override {
     327           0 :     return store_.counters_.iterate(iterFilter(fn));
     328           0 :   }
     329           0 :   bool iterate(const IterateFn<Gauge>& fn) const override {
     330           0 :     return store_.gauges_.iterate(iterFilter(fn));
     331           0 :   }
     332           0 :   bool iterate(const IterateFn<Histogram>& fn) const override {
     333           0 :     return store_.histograms_.iterate(iterFilter(fn));
     334           0 :   }
     335           0 :   bool iterate(const IterateFn<TextReadout>& fn) const override {
     336           0 :     return store_.text_readouts_.iterate(iterFilter(fn));
     337           0 :   }
     338             : 
     339       63665 :   Counter& counterFromString(const std::string& name) override {
     340       63665 :     StatNameManagedStorage storage(name, symbolTable());
     341       63665 :     return counterFromStatName(storage.statName());
     342       63665 :   }
     343       15964 :   Gauge& gaugeFromString(const std::string& name, Gauge::ImportMode import_mode) override {
     344       15964 :     StatNameManagedStorage storage(name, symbolTable());
     345       15964 :     return gaugeFromStatName(storage.statName(), import_mode);
     346       15964 :   }
     347         923 :   Histogram& histogramFromString(const std::string& name, Histogram::Unit unit) override {
     348         923 :     StatNameManagedStorage storage(name, symbolTable());
     349         923 :     return histogramFromStatName(storage.statName(), unit);
     350         923 :   }
     351           0 :   TextReadout& textReadoutFromString(const std::string& name) override {
     352           0 :     StatNameManagedStorage storage(name, symbolTable());
     353           0 :     return textReadoutFromStatName(storage.statName());
     354           0 :   }
     355             : 
     356      623697 :   StatName prefix() const override { return prefix_.statName(); }
     357           0 :   IsolatedStoreImpl& store() override { return store_; }
     358           0 :   const IsolatedStoreImpl& constStore() const override { return store_; }
     359             : 
     360             : protected:
     361        5127 :   void addScopeToStore(const ScopeSharedPtr& scope) { store_.scopes_.push_back(scope); }
     362             : 
     363             : private:
     364           0 :   template <class StatType> IterateFn<StatType> iterFilter(const IterateFn<StatType>& fn) const {
     365             :     // We determine here what's in the scope by looking at name
     366             :     // prefixes. Strictly speaking this is not correct, as the same stat can be
     367             :     // in different scopes, e.g. counter "b.c" in scope "a", and counter "c"
     368             :     // created in scope "a.b".
     369             :     //
     370             :     // There is currently no mechanism to resurrect actual membership of a stat
     371             :     // in a scope, so we go by name matching. Note that this hack is not needed
     372             :     // in `ThreadLocalStore`, which has accurate maps describing which stats are
     373             :     // in which scopes.
     374             :     //
     375             :     // TODO(jmarantz): In the scope of this limited implementation, it would be
     376             :     // faster to match on the StatName prefix. This would be possible if
     377             :     // SymbolTable exposed a split() method.
     378           0 :     std::string prefix_str = constSymbolTable().toString(prefix_.statName());
     379           0 :     if (!prefix_str.empty() && !absl::EndsWith(prefix_str, ".")) {
     380           0 :       prefix_str += ".";
     381           0 :     }
     382           0 :     return [fn, prefix_str](const RefcountPtr<StatType>& stat) -> bool {
     383           0 :       return !absl::StartsWith(stat->name(), prefix_str) || fn(stat);
     384           0 :     };
     385           0 :   }
     386             : 
     387             :   StatNameStorage prefix_;
     388             :   IsolatedStoreImpl& store_;
     389             : };
     390             : 
     391             : } // namespace Stats
     392             : } // namespace Envoy

Generated by: LCOV version 1.15