diff --git a/core/include/prometheus/family.h b/core/include/prometheus/family.h index aa946832..f36e3ec6 100644 --- a/core/include/prometheus/family.h +++ b/core/include/prometheus/family.h @@ -109,7 +109,9 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable { /// labels already exists - the already existing dimensional data. template T& Add(const std::map& labels, Args&&... args) { - return Add(labels, detail::make_unique(args...)); + metrics_iterator iter = FindMetric(labels); + if (iter->second) return *(iter->second); + return Add(iter, detail::make_unique(args...)); } /// \brief Remove the given dimensional data. @@ -145,9 +147,11 @@ class PROMETHEUS_CPP_CORE_EXPORT Family : public Collectable { const std::map constant_labels_; mutable std::mutex mutex_; + using metrics_iterator = typename std::unordered_map>::iterator; + ClientMetric CollectMetric(std::size_t hash, T* metric) const; - T& Add(const std::map& labels, - std::unique_ptr object); + T& Add(metrics_iterator hint, std::unique_ptr object); + metrics_iterator FindMetric(const std::map& labels); }; } // namespace prometheus diff --git a/core/src/family.cc b/core/src/family.cc index 83631abc..969dc737 100644 --- a/core/src/family.cc +++ b/core/src/family.cc @@ -15,8 +15,8 @@ Family::Family(const std::string& name, const std::string& help, } template -T& Family::Add(const std::map& labels, - std::unique_ptr object) { +typename Family::metrics_iterator +Family::FindMetric(const std::map& labels) { auto hash = detail::hash_labels(labels); std::lock_guard lock{mutex_}; auto metrics_iter = metrics_.find(hash); @@ -28,7 +28,7 @@ T& Family::Add(const std::map& labels, const auto& old_labels = labels_iter->second; assert(labels == old_labels); #endif - return *metrics_iter->second; + return metrics_iter; } else { #ifndef NDEBUG for (auto& label_pair : labels) { @@ -37,14 +37,25 @@ T& Family::Add(const std::map& labels, } #endif - auto metric = metrics_.insert(std::make_pair(hash, std::move(object))); + auto metric = metrics_.insert(std::make_pair(hash, nullptr)); assert(metric.second); labels_.insert({hash, labels}); - labels_reverse_lookup_.insert({metric.first->second.get(), hash}); - return *(metric.first->second); + return metric.first; } } +template +T& Family::Add(metrics_iterator hint, std::unique_ptr object) { + std::lock_guard lock{mutex_}; + auto hash = hint->first; + assert(metrics_.find(hash) == hint); + if (! hint->second) { + labels_reverse_lookup_.insert({object.get(), hash}); + hint->second.swap(object); + } + return *(hint->second); +} + template void Family::Remove(T* metric) { std::lock_guard lock{mutex_};