Skip to content

Commit d0f10fa

Browse files
jmarantzmattklein123
authored andcommitted
HeapStatData with a distinct allocation mechanism for RawStatData (envoyproxy#3710)
Signed-off-by: Joshua Marantz <jmarantz@google.com>
1 parent 2012c3e commit d0f10fa

File tree

20 files changed

+422
-280
lines changed

20 files changed

+422
-280
lines changed

include/envoy/stats/stats.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ class StatDataAllocator {
467467
* @return CounterSharedPtr a counter, or nullptr if allocation failed, in which case
468468
* tag_extracted_name and tags are not moved.
469469
*/
470-
virtual CounterSharedPtr makeCounter(const std::string& name, std::string&& tag_extracted_name,
470+
virtual CounterSharedPtr makeCounter(absl::string_view name, std::string&& tag_extracted_name,
471471
std::vector<Tag>&& tags) PURE;
472472

473473
/**
@@ -477,9 +477,14 @@ class StatDataAllocator {
477477
* @return GaugeSharedPtr a gauge, or nullptr if allocation failed, in which case
478478
* tag_extracted_name and tags are not moved.
479479
*/
480-
virtual GaugeSharedPtr makeGauge(const std::string& name, std::string&& tag_extracted_name,
480+
virtual GaugeSharedPtr makeGauge(absl::string_view name, std::string&& tag_extracted_name,
481481
std::vector<Tag>&& tags) PURE;
482482

483+
/**
484+
* Determines whether this stats allocator requires bounded stat-name size.
485+
*/
486+
virtual bool requiresBoundedStatNameSize() const PURE;
487+
483488
// TODO(jmarantz): create a parallel mechanism to instantiate histograms. At
484489
// the moment, histograms don't fit the same pattern of counters and gaugaes
485490
// as they are not actually created in the context of a stats allocator.

source/common/common/block_memory_hash_set.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ template <class Value> class BlockMemoryHashSet : public Logger::Loggable<Logger
165165
cell.next_cell_index = slots_[slot];
166166
slots_[slot] = cell_index;
167167
value = &cell.value;
168-
value->truncateAndInit(key, stats_options_);
168+
value->initialize(key, stats_options_);
169169
++control_->size;
170170
return ValueCreatedPair(value, true);
171171
}

source/common/stats/stats_impl.cc

Lines changed: 53 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -135,35 +135,35 @@ bool TagExtractorImpl::extractTag(const std::string& stat_name, std::vector<Tag>
135135
return false;
136136
}
137137

138-
RawStatData* HeapRawStatDataAllocator::alloc(const std::string& name) {
139-
uint64_t num_bytes_to_allocate = RawStatData::structSize(name.size());
140-
RawStatData* data = static_cast<RawStatData*>(::calloc(num_bytes_to_allocate, 1));
141-
if (data == nullptr) {
142-
throw std::bad_alloc();
143-
}
144-
data->checkAndInit(name, num_bytes_to_allocate);
138+
HeapStatData::HeapStatData(absl::string_view key) : name_(key.data(), key.size()) {}
145139

140+
HeapStatData* HeapStatDataAllocator::alloc(absl::string_view name) {
141+
// Any expected truncation of name is done at the callsite. No truncation is
142+
// required to use this allocator.
143+
auto data = std::make_unique<HeapStatData>(name);
146144
Thread::ReleasableLockGuard lock(mutex_);
147-
auto ret = stats_.insert(data);
148-
RawStatData* existing_data = *ret.first;
145+
auto ret = stats_.insert(data.get());
146+
HeapStatData* existing_data = *ret.first;
149147
lock.release();
150148

151-
if (!ret.second) {
152-
::free(data);
153-
++existing_data->ref_count_;
154-
return existing_data;
155-
} else {
156-
return data;
149+
if (ret.second) {
150+
return data.release();
157151
}
152+
++existing_data->ref_count_;
153+
return existing_data;
158154
}
159155

160156
/**
161-
* Counter implementation that wraps a RawStatData.
157+
* Counter implementation that wraps a StatData. StatData must have data members:
158+
* std::atomic<int64_t> value_;
159+
* std::atomic<int64_t> pending_increment_;
160+
* std::atomic<int16_t> flags_;
161+
* std::atomic<int16_t> ref_count_;
162162
*/
163-
class CounterImpl : public Counter, public MetricImpl {
163+
template <class StatData> class CounterImpl : public Counter, public MetricImpl {
164164
public:
165-
CounterImpl(RawStatData& data, RawStatDataAllocator& alloc, std::string&& tag_extracted_name,
166-
std::vector<Tag>&& tags)
165+
CounterImpl(StatData& data, StatDataAllocatorImpl<StatData>& alloc,
166+
std::string&& tag_extracted_name, std::vector<Tag>&& tags)
167167
: MetricImpl(data.name_, std::move(tag_extracted_name), std::move(tags)), data_(data),
168168
alloc_(alloc) {}
169169
~CounterImpl() { alloc_.free(data_); }
@@ -182,17 +182,17 @@ class CounterImpl : public Counter, public MetricImpl {
182182
uint64_t value() const override { return data_.value_; }
183183

184184
private:
185-
RawStatData& data_;
186-
RawStatDataAllocator& alloc_;
185+
StatData& data_;
186+
StatDataAllocatorImpl<StatData>& alloc_;
187187
};
188188

189189
/**
190-
* Gauge implementation that wraps a RawStatData.
190+
* Gauge implementation that wraps a StatData.
191191
*/
192-
class GaugeImpl : public Gauge, public MetricImpl {
192+
template <class StatData> class GaugeImpl : public Gauge, public MetricImpl {
193193
public:
194-
GaugeImpl(RawStatData& data, RawStatDataAllocator& alloc, std::string&& tag_extracted_name,
195-
std::vector<Tag>&& tags)
194+
GaugeImpl(StatData& data, StatDataAllocatorImpl<StatData>& alloc,
195+
std::string&& tag_extracted_name, std::vector<Tag>&& tags)
196196
: MetricImpl(data.name_, std::move(tag_extracted_name), std::move(tags)), data_(data),
197197
alloc_(alloc) {}
198198
~GaugeImpl() { alloc_.free(data_); }
@@ -217,8 +217,8 @@ class GaugeImpl : public Gauge, public MetricImpl {
217217
bool used() const override { return data_.flags_ & Flags::Used; }
218218

219219
private:
220-
RawStatData& data_;
221-
RawStatDataAllocator& alloc_;
220+
StatData& data_;
221+
StatDataAllocatorImpl<StatData>& alloc_;
222222
};
223223

224224
TagProducerImpl::TagProducerImpl(const envoy::config::metrics::v2::StatsConfig& config) {
@@ -319,47 +319,28 @@ TagProducerImpl::addDefaultExtractors(const envoy::config::metrics::v2::StatsCon
319319
return names;
320320
}
321321

322-
void HeapRawStatDataAllocator::free(RawStatData& data) {
322+
// TODO(jmarantz): move this below HeapStatDataAllocator::alloc.
323+
void HeapStatDataAllocator::free(HeapStatData& data) {
323324
ASSERT(data.ref_count_ > 0);
324325
if (--data.ref_count_ > 0) {
325326
return;
326327
}
327328

328-
size_t key_removed;
329329
{
330330
Thread::LockGuard lock(mutex_);
331-
key_removed = stats_.erase(&data);
331+
size_t key_removed = stats_.erase(&data);
332+
ASSERT(key_removed == 1);
332333
}
333334

334-
ASSERT(key_removed == 1);
335-
::free(&data);
335+
delete &data;
336336
}
337337

338-
void RawStatData::initialize(absl::string_view key, uint64_t xfer_size) {
338+
void RawStatData::initialize(absl::string_view key, const StatsOptions& stats_options) {
339339
ASSERT(!initialized());
340+
ASSERT(key.size() <= stats_options.maxNameLength());
340341
ref_count_ = 1;
341-
memcpy(name_, key.data(), xfer_size);
342-
name_[xfer_size] = '\0';
343-
}
344-
345-
void RawStatData::checkAndInit(absl::string_view key, uint64_t num_bytes_allocated) {
346-
uint64_t xfer_size = key.size();
347-
ASSERT(structSize(xfer_size) <= num_bytes_allocated);
348-
349-
initialize(key, xfer_size);
350-
}
351-
352-
void RawStatData::truncateAndInit(absl::string_view key, const StatsOptions& stats_options) {
353-
if (key.size() > stats_options.maxNameLength()) {
354-
ENVOY_LOG_MISC(
355-
warn,
356-
"Statistic '{}' is too long with {} characters, it will be truncated to {} characters", key,
357-
key.size(), stats_options.maxNameLength());
358-
}
359-
360-
// key is not necessarily nul-terminated, but we want to make sure name_ is.
361-
uint64_t xfer_size = std::min(stats_options.maxNameLength(), key.size());
362-
initialize(key, xfer_size);
342+
memcpy(name_, key.data(), key.size());
343+
name_[key.size()] = '\0';
363344
}
364345

365346
HistogramStatisticsImpl::HistogramStatisticsImpl(const histogram_t* histogram_ptr)
@@ -420,26 +401,32 @@ void SourceImpl::clearCache() {
420401
histograms_.reset();
421402
}
422403

423-
CounterSharedPtr RawStatDataAllocator::makeCounter(const std::string& name,
424-
std::string&& tag_extracted_name,
425-
std::vector<Tag>&& tags) {
426-
RawStatData* data = alloc(name);
404+
template <class StatData>
405+
CounterSharedPtr StatDataAllocatorImpl<StatData>::makeCounter(absl::string_view name,
406+
std::string&& tag_extracted_name,
407+
std::vector<Tag>&& tags) {
408+
StatData* data = alloc(name);
427409
if (data == nullptr) {
428410
return nullptr;
429411
}
430-
return std::make_shared<CounterImpl>(*data, *this, std::move(tag_extracted_name),
431-
std::move(tags));
412+
return std::make_shared<CounterImpl<StatData>>(*data, *this, std::move(tag_extracted_name),
413+
std::move(tags));
432414
}
433415

434-
GaugeSharedPtr RawStatDataAllocator::makeGauge(const std::string& name,
435-
std::string&& tag_extracted_name,
436-
std::vector<Tag>&& tags) {
437-
RawStatData* data = alloc(name);
416+
template <class StatData>
417+
GaugeSharedPtr StatDataAllocatorImpl<StatData>::makeGauge(absl::string_view name,
418+
std::string&& tag_extracted_name,
419+
std::vector<Tag>&& tags) {
420+
StatData* data = alloc(name);
438421
if (data == nullptr) {
439422
return nullptr;
440423
}
441-
return std::make_shared<GaugeImpl>(*data, *this, std::move(tag_extracted_name), std::move(tags));
424+
return std::make_shared<GaugeImpl<StatData>>(*data, *this, std::move(tag_extracted_name),
425+
std::move(tags));
442426
}
443427

428+
template class StatDataAllocatorImpl<HeapStatData>;
429+
template class StatDataAllocatorImpl<RawStatData>;
430+
444431
} // namespace Stats
445432
} // namespace Envoy

0 commit comments

Comments
 (0)