diff --git a/source/common/stats/stats_impl.cc b/source/common/stats/stats_impl.cc index 6d3dace509568..7387b7064832c 100644 --- a/source/common/stats/stats_impl.cc +++ b/source/common/stats/stats_impl.cc @@ -150,9 +150,24 @@ bool TagExtractorImpl::extractTag(const std::string& stat_name, std::vector } RawStatData* HeapRawStatDataAllocator::alloc(const std::string& name) { - // This must be zero-initialized - RawStatData* data = static_cast(::calloc(RawStatData::size(), 1)); - data->initialize(name); + absl::string_view key = name; + + if (key.size() > Stats::RawStatData::maxNameLength()) { + key.remove_suffix(key.size() - Stats::RawStatData::maxNameLength()); + ENVOY_LOG_MISC( + warn, + "Statistic '{}' is too long with {} characters, it will be truncated to {} characters", key, + key.size(), Stats::RawStatData::maxNameLength()); + } + + auto ret = stats_set_.insert(std::pair(std::string(key), nullptr)); + RawStatData*& data = ret.first->second; + if (ret.second) { + data = static_cast(::calloc(RawStatData::size(), 1)); + data->initialize(key); + } else { + ++data->ref_count_; + } return data; } @@ -256,18 +271,26 @@ TagProducerImpl::addDefaultExtractors(const envoy::config::metrics::v2::StatsCon } void HeapRawStatDataAllocator::free(RawStatData& data) { - // This allocator does not ever have concurrent access to the raw data. - ASSERT(data.ref_count_ == 1); + ASSERT(data.ref_count_ > 0); + if (--data.ref_count_ > 0) { + return; + } + + std::cout << data.key() << "\n"; + size_t key_removed = stats_set_.erase(std::string(data.key())); + std::cout << key_removed << "\n"; + ASSERT(key_removed >= 1); ::free(&data); } void RawStatData::initialize(absl::string_view key) { ASSERT(!initialized()); - if (key.size() > maxNameLength()) { + std::cout << key << "\n"; + if (key.size() > Stats::RawStatData::maxNameLength()) { ENVOY_LOG_MISC( warn, "Statistic '{}' is too long with {} characters, it will be truncated to {} characters", key, - key.size(), maxNameLength()); + key.size(), Stats::RawStatData::maxNameLength()); } ref_count_ = 1; diff --git a/source/common/stats/stats_impl.h b/source/common/stats/stats_impl.h index 7168e00ba7b51..a8d2daa964671 100644 --- a/source/common/stats/stats_impl.h +++ b/source/common/stats/stats_impl.h @@ -414,6 +414,9 @@ class HeapRawStatDataAllocator : public RawStatDataAllocator { // RawStatDataAllocator RawStatData* alloc(const std::string& name) override; void free(RawStatData& data) override; + +private: + std::unordered_map stats_set_; }; /** diff --git a/test/common/stats/stats_impl_test.cc b/test/common/stats/stats_impl_test.cc index b01bff0a776a1..148a63172e4c0 100644 --- a/test/common/stats/stats_impl_test.cc +++ b/test/common/stats/stats_impl_test.cc @@ -478,5 +478,14 @@ TEST(RawStatDataTest, Truncate) { alloc.free(*stat); } +TEST(RawStatDataTest, HeapAlloc) { + HeapRawStatDataAllocator alloc; + RawStatData* stat_1 = alloc.alloc("ref_name"); + RawStatData* stat_2 = alloc.alloc("ref_name"); + EXPECT_EQ(stat_1, stat_2); + ::free(stat_1); + ::free(stat_2); +} + } // namespace Stats } // namespace Envoy