Line data Source code
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 247 : : 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