Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/stats/stat_merger.h
Line
Count
Source
1
#pragma once
2
3
#include "envoy/stats/store.h"
4
5
#include "source/common/protobuf/protobuf.h"
6
#include "source/common/stats/symbol_table.h"
7
8
#include "absl/container/flat_hash_map.h"
9
10
namespace Envoy {
11
namespace Stats {
12
13
// Responsible for the sensible merging of two instances of the same stat from two different
14
// (typically hot restart parent+child) Envoy processes.
15
class StatMerger {
16
public:
17
  using DynamicsMap = absl::flat_hash_map<std::string, DynamicSpans>;
18
19
  // Holds state needed to construct StatName with mixed dynamic/symbolic
20
  // components, based on a map.
21
  class DynamicContext {
22
  public:
23
    DynamicContext(SymbolTable& symbol_table)
24
797
        : symbol_table_(symbol_table), symbolic_pool_(symbol_table), dynamic_pool_(symbol_table) {}
25
26
    /**
27
     * Generates a StatName with mixed dynamic/symbolic components based on
28
     * the string and the dynamic_map obtained from encodeSegments.
29
     *
30
     * @param name The string corresponding to the desired StatName.
31
     * @param map a map indicating which spans of tokens in the stat-name are dynamic.
32
     * @return the generated StatName, valid as long as the DynamicContext.
33
     */
34
    StatName makeDynamicStatName(const std::string& name, const DynamicsMap& map);
35
36
  private:
37
    SymbolTable& symbol_table_;
38
    StatNamePool symbolic_pool_;
39
    StatNameDynamicPool dynamic_pool_;
40
    SymbolTable::StoragePtr storage_ptr_;
41
  };
42
43
  StatMerger(Stats::Store& target_store);
44
  ~StatMerger();
45
46
  /**
47
   * Merge the values of stats_proto into stats_store. Counters are always
48
   * straightforward addition, while gauges default to addition but have
49
   * exceptions.
50
   *
51
   * @param counter_deltas map of counter changes from parent
52
   * @param gauges map of gauge changes from parent
53
   * @param dynamics information about which segments of the names are dynamic.
54
   */
55
  void mergeStats(const Protobuf::Map<std::string, uint64_t>& counter_deltas,
56
                  const Protobuf::Map<std::string, uint64_t>& gauges,
57
                  const DynamicsMap& dynamics = DynamicsMap());
58
59
  /**
60
   * Indicates that a gauge's value from the hot-restart parent should be
61
   * retained, combining it with the child data. By default, data is transferred
62
   * from parent gauges only during the hot-restart process, but the parent
63
   * contribution is subtracted from the child when the parent terminates. This
64
   * makes sense for gauges such as active connection counts, but is not
65
   * appropriate for server.hot_restart_generation.
66
   *
67
   * This function must be called immediately prior to destruction of the
68
   * StatMerger instance.
69
   *
70
   * @param gauge_name The gauge to be retained.
71
   */
72
  void retainParentGaugeValue(Stats::StatName gauge_name);
73
74
private:
75
  void mergeCounters(const Protobuf::Map<std::string, uint64_t>& counter_deltas,
76
                     const DynamicsMap& dynamics_map);
77
  void mergeGauges(const Protobuf::Map<std::string, uint64_t>& gauges,
78
                   const DynamicsMap& dynamics_map);
79
80
  StatNameHashSet parent_gauges_;
81
  // A stats Scope for our in-the-merging-process counters to live in. Scopes conceptually hold
82
  // shared_ptrs to the stats that live in them, with the question of which stats are living in a
83
  // given scope determined by which stat names have been accessed via that scope. E.g., if you
84
  // access a stat named "some.shared" directly through the ordinary store, and then access a
85
  // stat named "shared" in a scope configured with the prefix "some.", there is now a single
86
  // stat named some.shared pointed to by both. As another example, if you access the stat
87
  // "single" in the "some" scope, there will be a stat named "some.single" pointed to by just
88
  // that scope. Now, if you delete the scope, some.shared will stick around, but some.single
89
  // will be destroyed.
90
  //
91
  // All of that is relevant here because it is used to get a certain desired behavior.
92
  // Specifically, stats must be kept up to date with values from the parent throughout hot
93
  // restart, but once the restart completes, they must be dropped without a trace if the child has
94
  // not taken action (independent of the hot restart stat merging) that would lead to them getting
95
  // created in the store. By storing these stats in a scope (with an empty prefix), we can
96
  // preserve all stats throughout the hot restart. Then, when the restart completes, dropping
97
  // the scope will drop exactly those stats whose names have not already been accessed through
98
  // another store/scope.
99
  ScopeSharedPtr temp_scope_;
100
};
101
102
} // namespace Stats
103
} // namespace Envoy