Skip to content

Commit c92a301

Browse files
ambucmattklein123
authored andcommitted
Refactor Stats::RawStatData into a StatsOptions struct (#3629)
This change allows us to deprecate the statics inside Stats::RawStatData. Some side effects of this change are: a) HeapRawStatDataAllocator no longer performs stat name truncation, b) we now construct BlockMemoryHashSet, HotRestartImpl, C/L/RdsSubscription, and ThreadLocalStoreImpl as functions of this Stats::StatsOptions struct, and c) Stats::RawStatData now looks more like a set of libraries for computing stat padding, as opposed to a source of truth for the maximum allowable name lengths. Finally, a chain of functions starting under server.cc (translateBootstrap, translateClusterManagerBootstrap, translateListener, translateCluster, translateVirtualHost) have had Stats::StatsOptions& added to their interfaces, so that Utility::checkObjNameLength() can be called with the necessary context. Signed-off-by: James Buckland <jbuckland@google.com>
1 parent 230228b commit c92a301

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+553
-367
lines changed

include/envoy/server/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ envoy_cc_library(
111111
hdrs = ["options.h"],
112112
deps = [
113113
"//include/envoy/network:address_interface",
114+
"//include/envoy/stats:stats_interface",
114115
],
115116
)
116117

include/envoy/server/options.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "envoy/common/pure.h"
88
#include "envoy/network/address.h"
9+
#include "envoy/stats/stats.h"
910

1011
#include "spdlog/spdlog.h"
1112

@@ -149,10 +150,10 @@ class Options {
149150
virtual uint64_t maxStats() const PURE;
150151

151152
/**
152-
* @return uint64_t the maximum name length of the name field in
153+
* @return StatsOptions& the max stat name / suffix lengths for stats.
153154
* router/cluster/listener.
154155
*/
155-
virtual uint64_t maxObjNameLength() const PURE;
156+
virtual const Stats::StatsOptions& statsOptions() const PURE;
156157

157158
/**
158159
* @return bool indicating whether the hot restart functionality has been disabled via cli flags.

include/envoy/stats/stats.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,43 @@ class Instance;
2424

2525
namespace Stats {
2626

27+
/**
28+
* Struct stored under Server::Options to hold information about the maximum object name length and
29+
* maximum stat suffix length of a stat. These have defaults in StatsOptionsImpl, and the maximum
30+
* object name length can be overridden. The default initialization is used in IsolatedStatImpl, and
31+
* the user-overridden struct is stored in Options.
32+
*
33+
* As noted in the comment above StatsOptionsImpl in source/common/stats/stats_impl.h, a stat name
34+
* often contains both a string whose length is user-defined (cluster_name in the below example),
35+
* and a specific statistic name generated by Envoy. To make room for growth on both fronts, we
36+
* limit the max allowed length of each separately.
37+
*
38+
* name / stat name
39+
* |----------------------------------------------------------------|
40+
* cluster.<cluster_name>.outlier_detection.ejections_consecutive_5xx
41+
* |--------------------------------------| |-----------------------|
42+
* object name suffix
43+
*/
44+
class StatsOptions {
45+
public:
46+
virtual ~StatsOptions() {}
47+
48+
/**
49+
* The max allowed length of a complete stat name, including suffix.
50+
*/
51+
virtual size_t maxNameLength() const PURE;
52+
53+
/**
54+
* The max allowed length of the object part of a stat name.
55+
*/
56+
virtual size_t maxObjNameLength() const PURE;
57+
58+
/**
59+
* The max allowed length of a stat suffix.
60+
*/
61+
virtual size_t maxStatSuffixLength() const PURE;
62+
};
63+
2764
/**
2865
* General representation of a tag.
2966
*/
@@ -329,6 +366,12 @@ class Scope {
329366
* @return a histogram within the scope's namespace with a particular value type.
330367
*/
331368
virtual Histogram& histogram(const std::string& name) PURE;
369+
370+
/**
371+
* @return a reference to the top-level StatsOptions struct, containing information about the
372+
* maximum allowable object name length and stat suffix length.
373+
*/
374+
virtual const Stats::StatsOptions& statsOptions() const PURE;
332375
};
333376

334377
/**

source/common/common/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ envoy_cc_library(
235235
deps = [
236236
":assert_lib",
237237
":logger_lib",
238+
"//include/envoy/stats:stats_interface",
239+
"//source/common/stats:stats_lib",
238240
],
239241
)
240242

source/common/common/block_memory_hash_set.h

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
#include <utility>
66

77
#include "envoy/common/exception.h"
8+
#include "envoy/stats/stats.h"
89

910
#include "common/common/assert.h"
1011
#include "common/common/fmt.h"
1112
#include "common/common/logger.h"
13+
#include "common/stats/stats_impl.h"
1214

1315
#include "absl/strings/string_view.h"
1416

@@ -57,21 +59,24 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
5759

5860
/**
5961
* Constructs a map control structure given a set of options, which cannot be changed.
60-
* @param options describes the parameters comtrolling set layout.
62+
* @param hash_set_options describes the parameters comtrolling set layout.
6163
* @param init true if the memory should be initialized on construction. If false,
6264
* the data in the table will be sanity checked, and an exception thrown if
6365
* it is incoherent or mismatches the passed-in options.
6466
* @param memory the memory buffer for the set data.
67+
* @param stats_options a reference to the top-level StatsOptions struct containing
68+
* information about max allowable stat name lengths.
6569
*
6670
* Note that no locking of any kind is done by this class; this must be done at the
6771
* call-site to support concurrent access.
6872
*/
69-
BlockMemoryHashSet(const BlockMemoryHashSetOptions& options, bool init, uint8_t* memory)
70-
: cells_(nullptr), control_(nullptr), slots_(nullptr) {
71-
mapMemorySegments(options, memory);
73+
BlockMemoryHashSet(const BlockMemoryHashSetOptions& hash_set_options, bool init, uint8_t* memory,
74+
const Stats::StatsOptions& stats_options)
75+
: cells_(nullptr), control_(nullptr), slots_(nullptr), stats_options_(stats_options) {
76+
mapMemorySegments(hash_set_options, memory);
7277
if (init) {
73-
initialize(options);
74-
} else if (!attach(options)) {
78+
initialize(hash_set_options);
79+
} else if (!attach(hash_set_options)) {
7580
throw EnvoyException("BlockMemoryHashSet: Incompatible memory block");
7681
}
7782
}
@@ -82,22 +87,20 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
8287
* backing-store (eg) in memory, which we do after
8388
* constructing the object with the desired sizing.
8489
*/
85-
static uint64_t numBytes(const BlockMemoryHashSetOptions& options) {
86-
uint64_t size =
87-
cellOffset(options.capacity) + sizeof(Control) + options.num_slots * sizeof(uint32_t);
90+
static uint64_t numBytes(const BlockMemoryHashSetOptions& hash_set_options,
91+
const Stats::StatsOptions& stats_options) {
92+
uint64_t size = cellOffset(hash_set_options.capacity, stats_options) + sizeof(Control) +
93+
hash_set_options.num_slots * sizeof(uint32_t);
8894
return align(size);
8995
}
9096

91-
uint64_t numBytes() const { return numBytes(control_->options); }
92-
93-
/**
94-
* Returns the options structure that was used to construct the set.
95-
*/
96-
const BlockMemoryHashSetOptions& options() const { return control_->options; }
97+
uint64_t numBytes(const Stats::StatsOptions& stats_options) const {
98+
return numBytes(control_->hash_set_options, stats_options);
99+
}
97100

98101
/** Examines the data structures to see if they are sane, assert-failing on any trouble. */
99102
void sanityCheck() {
100-
RELEASE_ASSERT(control_->size <= control_->options.capacity, "");
103+
RELEASE_ASSERT(control_->size <= control_->hash_set_options.capacity, "");
101104

102105
// As a sanity check, make sure there are control_->size values
103106
// reachable from the slots, each of which has a valid
@@ -107,11 +110,11 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
107110
// slot. Note that the num_values message will be emitted outside
108111
// the loop.
109112
uint32_t num_values = 0;
110-
for (uint32_t slot = 0; slot < control_->options.num_slots; ++slot) {
113+
for (uint32_t slot = 0; slot < control_->hash_set_options.num_slots; ++slot) {
111114
uint32_t next = 0; // initialized to silence compilers.
112115
for (uint32_t cell_index = slots_[slot];
113116
(cell_index != Sentinal) && (num_values <= control_->size); cell_index = next) {
114-
RELEASE_ASSERT(cell_index < control_->options.capacity, "");
117+
RELEASE_ASSERT(cell_index < control_->hash_set_options.capacity, "");
115118
Cell& cell = getCell(cell_index);
116119
absl::string_view key = cell.value.key();
117120
RELEASE_ASSERT(computeSlot(key) == slot, "");
@@ -122,7 +125,7 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
122125
RELEASE_ASSERT(num_values == control_->size, "");
123126

124127
uint32_t num_free_entries = 0;
125-
uint32_t expected_free_entries = control_->options.capacity - control_->size;
128+
uint32_t expected_free_entries = control_->hash_set_options.capacity - control_->size;
126129

127130
// Don't infinite-loop with a corruption; break when we see there's a problem.
128131
for (uint32_t cell_index = control_->free_cell_index;
@@ -152,7 +155,7 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
152155
if (value != nullptr) {
153156
return ValueCreatedPair(value, false);
154157
}
155-
if (control_->size >= control_->options.capacity) {
158+
if (control_->size >= control_->hash_set_options.capacity) {
156159
return ValueCreatedPair(nullptr, false);
157160
}
158161
const uint32_t slot = computeSlot(key);
@@ -162,7 +165,7 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
162165
cell.next_cell_index = slots_[slot];
163166
slots_[slot] = cell_index;
164167
value = &cell.value;
165-
value->initialize(key);
168+
value->truncateAndInit(key, stats_options_);
166169
++control_->size;
167170
return ValueCreatedPair(value, true);
168171
}
@@ -215,9 +218,9 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
215218
/**
216219
* Computes a version signature based on the options and the hash function.
217220
*/
218-
std::string version() {
219-
return fmt::format("options={} hash={} size={}", control_->options.toString(),
220-
control_->hash_signature, numBytes());
221+
std::string version(const Stats::StatsOptions& stats_options) {
222+
return fmt::format("options={} hash={} size={}", control_->hash_set_options.toString(),
223+
control_->hash_signature, numBytes(stats_options));
221224
}
222225

223226
private:
@@ -228,20 +231,20 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
228231
* coming in.
229232
* @param memory
230233
*/
231-
void initialize(const BlockMemoryHashSetOptions& options) {
234+
void initialize(const BlockMemoryHashSetOptions& hash_set_options) {
232235
control_->hash_signature = Value::hash(signatureStringToHash());
233-
control_->num_bytes = numBytes(options);
234-
control_->options = options;
236+
control_->num_bytes = numBytes(hash_set_options, stats_options_);
237+
control_->hash_set_options = hash_set_options;
235238
control_->size = 0;
236239
control_->free_cell_index = 0;
237240

238241
// Initialize all the slots;
239-
for (uint32_t slot = 0; slot < options.num_slots; ++slot) {
242+
for (uint32_t slot = 0; slot < hash_set_options.num_slots; ++slot) {
240243
slots_[slot] = Sentinal;
241244
}
242245

243246
// Initialize the free-cell list.
244-
const uint32_t last_cell = options.capacity - 1;
247+
const uint32_t last_cell = hash_set_options.capacity - 1;
245248
for (uint32_t cell_index = 0; cell_index < last_cell; ++cell_index) {
246249
Cell& cell = getCell(cell_index);
247250
cell.next_cell_index = cell_index + 1;
@@ -254,10 +257,10 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
254257
* sanity check to make sure the options copied to the provided memory match, and also
255258
* that the slot, cell, and key-string structures look sane.
256259
*/
257-
bool attach(const BlockMemoryHashSetOptions& options) {
258-
if (numBytes(options) != control_->num_bytes) {
259-
ENVOY_LOG(error, "BlockMemoryHashSet unexpected memory size {} != {}", numBytes(options),
260-
control_->num_bytes);
260+
bool attach(const BlockMemoryHashSetOptions& hash_set_options) {
261+
if (numBytes(hash_set_options, stats_options_) != control_->num_bytes) {
262+
ENVOY_LOG(error, "BlockMemoryHashSet unexpected memory size {} != {}",
263+
numBytes(hash_set_options, stats_options_), control_->num_bytes);
261264
return false;
262265
}
263266
if (Value::hash(signatureStringToHash()) != control_->hash_signature) {
@@ -269,7 +272,7 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
269272
}
270273

271274
uint32_t computeSlot(absl::string_view key) {
272-
return Value::hash(key) % control_->options.num_slots;
275+
return Value::hash(key) % control_->hash_set_options.num_slots;
273276
}
274277

275278
/**
@@ -290,11 +293,11 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
290293
* Represents control-values for the hash-table.
291294
*/
292295
struct Control {
293-
BlockMemoryHashSetOptions options; // Options established at map construction time.
294-
uint64_t hash_signature; // Hash of a constant signature string.
295-
uint64_t num_bytes; // Bytes allocated on behalf of the map.
296-
uint32_t size; // Number of values currently stored.
297-
uint32_t free_cell_index; // Offset of first free cell.
296+
BlockMemoryHashSetOptions hash_set_options; // Options established at map construction time.
297+
uint64_t hash_signature; // Hash of a constant signature string.
298+
uint64_t num_bytes; // Bytes allocated on behalf of the map.
299+
uint32_t size; // Number of values currently stored.
300+
uint32_t free_cell_index; // Offset of first free cell.
298301
};
299302

300303
/**
@@ -323,10 +326,11 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
323326
* simply an array index because we don't know the size of a key at
324327
* compile-time.
325328
*/
326-
static uint64_t cellOffset(uint32_t cell_index) {
329+
static uint64_t cellOffset(uint32_t cell_index, const Stats::StatsOptions& stats_options) {
327330
// sizeof(Cell) includes 'sizeof Value' which may not be accurate. So we need to
328331
// subtract that off, and add the template method's view of the actual value-size.
329-
uint64_t cell_size = align(sizeof(Cell) + Value::size() - sizeof(Value));
332+
uint64_t cell_size =
333+
align(sizeof(Cell) + Value::structSizeWithOptions(stats_options) - sizeof(Value));
330334
return cell_index * cell_size;
331335
}
332336

@@ -335,17 +339,17 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
335339
*/
336340
Cell& getCell(uint32_t cell_index) {
337341
// Because the key-size is parameteriziable, an array-lookup on sizeof(Cell) does not work.
338-
char* ptr = reinterpret_cast<char*>(cells_) + cellOffset(cell_index);
342+
char* ptr = reinterpret_cast<char*>(cells_) + cellOffset(cell_index, stats_options_);
339343
RELEASE_ASSERT((reinterpret_cast<uint64_t>(ptr) & (calculateAlignment() - 1)) == 0, "");
340344
return *reinterpret_cast<Cell*>(ptr);
341345
}
342346

343347
/** Maps out the segments of memory for us to work with. */
344-
void mapMemorySegments(const BlockMemoryHashSetOptions& options, uint8_t* memory) {
348+
void mapMemorySegments(const BlockMemoryHashSetOptions& hash_set_options, uint8_t* memory) {
345349
// Note that we are not examining or mutating memory here, just looking at the pointer,
346350
// so we don't need to hold any locks.
347351
cells_ = reinterpret_cast<Cell*>(memory); // First because Value may need to be aligned.
348-
memory += cellOffset(options.capacity);
352+
memory += cellOffset(hash_set_options.capacity, stats_options_);
349353
control_ = reinterpret_cast<Control*>(memory);
350354
memory += sizeof(Control);
351355
slots_ = reinterpret_cast<uint32_t*>(memory);
@@ -356,6 +360,7 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
356360
Cell* cells_;
357361
Control* control_;
358362
uint32_t* slots_;
363+
const Stats::StatsOptions& stats_options_;
359364
};
360365

361366
} // namespace Envoy

source/common/config/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ envoy_cc_library(
3535
"//source/common/common:assert_lib",
3636
"//source/common/json:config_schemas_lib",
3737
"//source/common/protobuf:utility_lib",
38+
"//source/common/stats:stats_lib",
3839
"//source/extensions/stat_sinks:well_known_names",
3940
"@envoy_api//envoy/config/bootstrap/v2:bootstrap_cc",
4041
],
@@ -66,6 +67,7 @@ envoy_cc_library(
6667
"//source/common/common:assert_lib",
6768
"//source/common/json:config_schemas_lib",
6869
"//source/common/network:utility_lib",
70+
"//source/common/stats:stats_lib",
6971
"@envoy_api//envoy/api/v2:cds_cc",
7072
"@envoy_api//envoy/api/v2/cluster:circuit_breaker_cc",
7173
],
@@ -106,6 +108,7 @@ envoy_cc_library(
106108
":rds_json_lib",
107109
":utility_lib",
108110
"//include/envoy/json:json_object_interface",
111+
"//include/envoy/stats:stats_interface",
109112
"//source/common/common:assert_lib",
110113
"//source/common/common:utility_lib",
111114
"//source/common/json:config_schemas_lib",
@@ -218,6 +221,7 @@ envoy_cc_library(
218221
"//source/common/common:assert_lib",
219222
"//source/common/json:config_schemas_lib",
220223
"//source/common/network:utility_lib",
224+
"//source/common/stats:stats_lib",
221225
"//source/extensions/filters/network:well_known_names",
222226
"@envoy_api//envoy/api/v2:lds_cc",
223227
],
@@ -271,6 +275,7 @@ envoy_cc_library(
271275
"//source/common/common:assert_lib",
272276
"//source/common/config:utility_lib",
273277
"//source/common/json:config_schemas_lib",
278+
"//source/common/stats:stats_lib",
274279
"//source/extensions/filters/http:well_known_names",
275280
"@envoy_api//envoy/api/v2:rds_cc",
276281
],

0 commit comments

Comments
 (0)