1
#pragma once
2

            
3
#include <string>
4
#include <vector>
5

            
6
#include "envoy/stats/stats.h"
7
#include "envoy/stats/tag.h"
8

            
9
#include "source/common/common/assert.h"
10
#include "source/common/stats/symbol_table.h"
11

            
12
namespace Envoy {
13
namespace Stats {
14

            
15
/**
16
 * Helper class for implementing Metrics. This does not participate in any
17
 * inheritance chains, but can be instantiated by classes that do. It just
18
 * implements the mechanics of representing the name, tag-extracted-name,
19
 * and all tags as a StatNameList.
20
 */
21
class MetricHelper {
22
public:
23
  MetricHelper(StatName name, StatName tag_extracted_name, const StatNameTagVector& stat_name_tags,
24
               SymbolTable& symbol_table);
25
  ~MetricHelper();
26

            
27
  StatName statName() const;
28
  std::string name(const SymbolTable& symbol_table) const;
29
  TagVector tags(const SymbolTable& symbol_table) const;
30
  StatName tagExtractedStatName() const;
31
  void iterateTagStatNames(const Metric::TagStatNameIterFn& fn) const;
32
39887829
  void clear(SymbolTable& symbol_table) { stat_names_.clear(symbol_table); }
33

            
34
  // Hasher for metrics.
35
  struct Hash {
36
    using is_transparent = void; // NOLINT(readability-identifier-naming)
37
63000569
    size_t operator()(const Metric* a) const { return a->statName().hash(); }
38
57462641
    size_t operator()(StatName a) const { return a.hash(); }
39
  };
40

            
41
  // Comparator for metrics.
42
  struct Compare {
43
    using is_transparent = void; // NOLINT(readability-identifier-naming)
44
2396172
    bool operator()(const Metric* a, const Metric* b) const {
45
2396172
      return a->statName() == b->statName();
46
2396172
    }
47
32665304
    bool operator()(const Metric* a, StatName b) const { return a->statName() == b; }
48
  };
49

            
50
private:
51
  StatNameList stat_names_;
52
};
53

            
54
// An unordered set of stat pointers. which keys off Metric::statName().
55
// This necessitates a custom comparator and hasher, using the StatNamePtr's
56
// own StatNamePtrHash and StatNamePtrCompare operators.
57
//
58
// This is used by Allocator for counters, gauges, and text-readouts, and
59
// is also used by thread_local_store.h for histograms.
60
template <class StatType>
61
using StatSet = absl::flat_hash_set<StatType*, MetricHelper::Hash, MetricHelper::Compare>;
62

            
63
/**
64
 * Partial implementation of the Metric interface on behalf of Counters, Gauges,
65
 * and Histograms. It leaves symbolTable() unimplemented so that implementations
66
 * of stats managed by an allocator, specifically Counters and Gauges, can keep
67
 * a reference to the allocator instead, and derive the symbolTable() from that.
68
 *
69
 * We templatize on the base class (Counter, Gauge, or Histogram), rather than
70
 * using multiple virtual inheritance, as this avoids the overhead of an extra
71
 * vptr per instance. This is important for stats because there can be many
72
 * stats in systems with large numbers of clusters and hosts, and a few 8-byte
73
 * pointers per-stat here and there can add up to significant amounts of memory.
74
 *
75
 * Note the delegation of the implementation to a helper class, which is neither
76
 * templatized nor virtual. This avoids having the compiler elaborate complete
77
 * copies of the underlying implementation for each base class during template
78
 * expansion.
79
 */
80
template <class BaseClass> class MetricImpl : public BaseClass {
81
public:
82
  MetricImpl(StatName name, StatName tag_extracted_name, const StatNameTagVector& stat_name_tags,
83
             SymbolTable& symbol_table)
84
39889407
      : helper_(name, tag_extracted_name, stat_name_tags, symbol_table) {}
85

            
86
  // Empty construction of a MetricImpl; used for null stats.
87
  explicit MetricImpl(SymbolTable& symbol_table)
88
7346324
      : MetricImpl(StatName(), StatName(), StatNameTagVector(), symbol_table) {}
89

            
90
6047
  TagVector tags() const override { return helper_.tags(constSymbolTable()); }
91
219926579
  StatName statName() const override { return helper_.statName(); }
92
7554
  StatName tagExtractedStatName() const override { return helper_.tagExtractedStatName(); }
93
4
  void iterateTagStatNames(const Metric::TagStatNameIterFn& fn) const override {
94
4
    helper_.iterateTagStatNames(fn);
95
4
  }
96

            
97
52701189
  const SymbolTable& constSymbolTable() const override {
98
    // Cast our 'this', which is of type `const MetricImpl*` to a non-const
99
    // pointer, so we can use it to call the subclass implementation of
100
    // symbolTable(). That will be returned as a non-const SymbolTable&,
101
    // which will become const on return.
102
    //
103
    // This pattern is used to share a single non-trivial implementation to
104
    // provide const and non-const variants of a method.
105
52701189
    return const_cast<MetricImpl*>(this)->symbolTable();
106
52701189
  }
107
52690176
  std::string name() const override { return constSymbolTable().toString(this->statName()); }
108
3860
  std::string tagExtractedName() const override {
109
3860
    return constSymbolTable().toString(this->tagExtractedStatName());
110
3860
  }
111

            
112
protected:
113
39887829
  void clear(SymbolTable& symbol_table) { helper_.clear(symbol_table); }
114

            
115
private:
116
  MetricHelper helper_;
117
};
118

            
119
} // namespace Stats
120
} // namespace Envoy