diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/monlib/metrics/labels.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/monlib/metrics/labels.h')
-rw-r--r-- | library/cpp/monlib/metrics/labels.h | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/library/cpp/monlib/metrics/labels.h b/library/cpp/monlib/metrics/labels.h new file mode 100644 index 0000000000..63dc997c28 --- /dev/null +++ b/library/cpp/monlib/metrics/labels.h @@ -0,0 +1,483 @@ +#pragma once + +#include <util/digest/multi.h> +#include <util/digest/sequence.h> +#include <util/generic/algorithm.h> +#include <util/generic/maybe.h> +#include <util/generic/string.h> +#include <util/generic/vector.h> +#include <util/stream/output.h> +#include <util/string/builder.h> +#include <util/string/strip.h> + +#include <optional> +#include <type_traits> + +namespace NMonitoring { + struct ILabel { + virtual ~ILabel() = default; + + virtual TStringBuf Name() const noexcept = 0; + virtual TStringBuf Value() const noexcept = 0; + }; + + /////////////////////////////////////////////////////////////////////////// + // TLabel + /////////////////////////////////////////////////////////////////////////// + template <typename TStringBackend> + class TLabelImpl: public ILabel { + public: + using TStringType = TStringBackend; + + TLabelImpl() = default; + + inline TLabelImpl(TStringBuf name, TStringBuf value) + : Name_{name} + , Value_{value} + { + } + + inline bool operator==(const TLabelImpl& rhs) const noexcept { + return Name_ == rhs.Name_ && Value_ == rhs.Value_; + } + + inline bool operator!=(const TLabelImpl& rhs) const noexcept { + return !(*this == rhs); + } + + inline TStringBuf Name() const noexcept { + return Name_; + } + + inline TStringBuf Value() const noexcept { + return Value_; + } + + inline const TStringBackend& NameStr() const { + return Name_; + } + + inline const TStringBackend& ValueStr() const { + return Value_; + } + + inline size_t Hash() const noexcept { + return MultiHash(Name_, Value_); + } + + TStringBackend ToString() const { + TStringBackend buf = Name_; + buf += '='; + buf += Value_; + + return buf; + } + + static TLabelImpl FromString(TStringBuf str) { + TStringBuf name, value; + Y_ENSURE(str.TrySplit('=', name, value), + "invalid label string format: '" << str << '\''); + + TStringBuf nameStripped = StripString(name); + Y_ENSURE(!nameStripped.empty(), "label name cannot be empty"); + + TStringBuf valueStripped = StripString(value); + Y_ENSURE(!valueStripped.empty(), "label value cannot be empty"); + + return {nameStripped, valueStripped}; + } + + static bool TryFromString(TStringBuf str, TLabelImpl& label) { + TStringBuf name, value; + if (!str.TrySplit('=', name, value)) { + return false; + } + + TStringBuf nameStripped = StripString(name); + if (nameStripped.empty()) { + return false; + } + + TStringBuf valueStripped = StripString(value); + if (valueStripped.empty()) { + return false; + } + + label = {nameStripped, valueStripped}; + return true; + } + + private: + TStringBackend Name_; + TStringBackend Value_; + }; + + using TLabel = TLabelImpl<TString>; + + struct ILabels { + struct TIterator { + TIterator() = default; + TIterator(const ILabels* labels, size_t idx = 0) + : Labels_{labels} + , Idx_{idx} + { + } + + TIterator& operator++() noexcept { + Idx_++; + return *this; + } + + void operator+=(size_t i) noexcept { + Idx_ += i; + } + + bool operator==(const TIterator& other) const noexcept { + return Idx_ == other.Idx_; + } + + bool operator!=(const TIterator& other) const noexcept { + return !(*this == other); + } + + const ILabel* operator->() const noexcept { + Y_VERIFY_DEBUG(Labels_); + return Labels_->Get(Idx_); + } + + const ILabel& operator*() const noexcept { + Y_VERIFY_DEBUG(Labels_); + return *Labels_->Get(Idx_); + } + + + private: + const ILabels* Labels_{nullptr}; + size_t Idx_{0}; + }; + + virtual ~ILabels() = default; + + virtual bool Add(TStringBuf name, TStringBuf value) noexcept = 0; + virtual bool Add(const ILabel& label) noexcept { + return Add(label.Name(), label.Value()); + } + + virtual bool Has(TStringBuf name) const noexcept = 0; + + virtual size_t Size() const noexcept = 0; + virtual bool Empty() const noexcept = 0; + virtual void Clear() noexcept = 0; + + virtual size_t Hash() const noexcept = 0; + + virtual std::optional<const ILabel*> Get(TStringBuf name) const = 0; + + // NB: there's no guarantee that indices are preserved after any object modification + virtual const ILabel* Get(size_t idx) const = 0; + + TIterator begin() const { + return TIterator{this}; + } + + TIterator end() const { + return TIterator{this, Size()}; + } + }; + + bool TryLoadLabelsFromString(TStringBuf sb, ILabels& labels); + bool TryLoadLabelsFromString(IInputStream& is, ILabels& labels); + + /////////////////////////////////////////////////////////////////////////// + // TLabels + /////////////////////////////////////////////////////////////////////////// + template <typename TStringBackend> + class TLabelsImpl: public ILabels { + public: + using value_type = TLabelImpl<TStringBackend>; + + TLabelsImpl() = default; + + explicit TLabelsImpl(::NDetail::TReserveTag rt) + : Labels_(std::move(rt)) + {} + + explicit TLabelsImpl(size_t count) + : Labels_(count) + {} + + explicit TLabelsImpl(size_t count, const value_type& label) + : Labels_(count, label) + {} + + TLabelsImpl(std::initializer_list<value_type> il) + : Labels_(std::move(il)) + {} + + TLabelsImpl(const TLabelsImpl&) = default; + TLabelsImpl& operator=(const TLabelsImpl&) = default; + + TLabelsImpl(TLabelsImpl&&) noexcept = default; + TLabelsImpl& operator=(TLabelsImpl&&) noexcept = default; + + inline bool operator==(const TLabelsImpl& rhs) const { + return Labels_ == rhs.Labels_; + } + + inline bool operator!=(const TLabelsImpl& rhs) const { + return Labels_ != rhs.Labels_; + } + + bool Add(TStringBuf name, TStringBuf value) noexcept override { + if (Has(name)) { + return false; + } + + Labels_.emplace_back(name, value); + return true; + } + + using ILabels::Add; + + bool Has(TStringBuf name) const noexcept override { + auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) { + return name == TStringBuf{label.Name()}; + }); + return it != Labels_.end(); + } + + bool Has(const TString& name) const noexcept { + auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) { + return name == TStringBuf{label.Name()}; + }); + return it != Labels_.end(); + } + + // XXX for backward compatibility + TMaybe<TLabelImpl<TStringBackend>> Find(TStringBuf name) const { + auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) { + return name == TStringBuf{label.Name()}; + }); + if (it == Labels_.end()) { + return Nothing(); + } + return *it; + } + + std::optional<const ILabel*> Get(TStringBuf name) const override { + auto it = FindIf(Labels_, [name] (auto&& l) { + return name == l.Name(); + }); + + if (it == Labels_.end()) { + return {}; + } + + return &*it; + } + + const ILabel* Get(size_t idx) const noexcept override { + return &(*this)[idx]; + } + + TMaybe<TLabelImpl<TStringBackend>> Extract(TStringBuf name) { + auto it = FindIf(Labels_, [name](const TLabelImpl<TStringBackend>& label) { + return name == TStringBuf{label.Name()}; + }); + if (it == Labels_.end()) { + return Nothing(); + } + TLabel tmp = *it; + Labels_.erase(it); + return tmp; + } + + void SortByName() { + std::sort(Labels_.begin(), Labels_.end(), [](const auto& lhs, const auto& rhs) { + return lhs.Name() < rhs.Name(); + }); + } + + inline size_t Hash() const noexcept override { + return TSimpleRangeHash()(Labels_); + } + + inline TLabel* Data() const noexcept { + return const_cast<TLabel*>(Labels_.data()); + } + + inline size_t Size() const noexcept override { + return Labels_.size(); + } + + inline bool Empty() const noexcept override { + return Labels_.empty(); + } + + inline void Clear() noexcept override { + Labels_.clear(); + }; + + TLabelImpl<TStringBackend>& front() { + return Labels_.front(); + } + + const TLabelImpl<TStringBackend>& front() const { + return Labels_.front(); + } + + TLabelImpl<TStringBackend>& back() { + return Labels_.back(); + } + + const TLabelImpl<TStringBackend>& back() const { + return Labels_.back(); + } + + TLabelImpl<TStringBackend>& operator[](size_t index) { + return Labels_[index]; + } + + const TLabelImpl<TStringBackend>& operator[](size_t index) const { + return Labels_[index]; + } + + TLabelImpl<TStringBackend>& at(size_t index) { + return Labels_.at(index); + } + + const TLabelImpl<TStringBackend>& at(size_t index) const { + return Labels_.at(index); + } + + size_t capacity() const { + return Labels_.capacity(); + } + + TLabelImpl<TStringBackend>* data() { + return Labels_.data(); + } + + const TLabelImpl<TStringBackend>* data() const { + return Labels_.data(); + } + + size_t size() const { + return Labels_.size(); + } + + bool empty() const { + return Labels_.empty(); + } + + void clear() { + Labels_.clear(); + } + + using ILabels::begin; + using ILabels::end; + + using iterator = ILabels::TIterator; + using const_iterator = iterator; + + protected: + TVector<TLabelImpl<TStringBackend>>& AsVector() { + return Labels_; + } + + const TVector<TLabelImpl<TStringBackend>>& AsVector() const { + return Labels_; + } + + private: + TVector<TLabelImpl<TStringBackend>> Labels_; + }; + + using TLabels = TLabelsImpl<TString>; + using ILabelsPtr = THolder<ILabels>; + + template <typename T> + ILabelsPtr MakeLabels() { + return MakeHolder<TLabelsImpl<T>>(); + } + + template <typename T> + ILabelsPtr MakeLabels(std::initializer_list<TLabelImpl<T>> labels) { + return MakeHolder<TLabelsImpl<T>>(labels); + } + + inline ILabelsPtr MakeLabels(TLabels&& labels) { + return MakeHolder<TLabels>(std::move(labels)); + } +} + +template<> +struct THash<NMonitoring::ILabelsPtr> { + size_t operator()(const NMonitoring::ILabelsPtr& labels) const noexcept { + return labels->Hash(); + } + + size_t operator()(const NMonitoring::ILabels& labels) const noexcept { + return labels.Hash(); + } +}; + +template<typename TStringBackend> +struct THash<NMonitoring::TLabelsImpl<TStringBackend>> { + size_t operator()(const NMonitoring::TLabelsImpl<TStringBackend>& labels) const noexcept { + return labels.Hash(); + } +}; + +template <typename TStringBackend> +struct THash<NMonitoring::TLabelImpl<TStringBackend>> { + inline size_t operator()(const NMonitoring::TLabelImpl<TStringBackend>& label) const noexcept { + return label.Hash(); + } +}; + +inline bool operator==(const NMonitoring::ILabels& lhs, const NMonitoring::ILabels& rhs) { + if (lhs.Size() != rhs.Size()) { + return false; + } + + for (auto&& l : lhs) { + auto rl = rhs.Get(l.Name()); + if (!rl || (*rl)->Value() != l.Value()) { + return false; + } + } + + return true; +} + +bool operator==(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabelsPtr& rhs) = delete; +bool operator==(const NMonitoring::ILabels& lhs, const NMonitoring::ILabelsPtr& rhs) = delete; +bool operator==(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabels& rhs) = delete; + +template<> +struct TEqualTo<NMonitoring::ILabelsPtr> { + bool operator()(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabelsPtr& rhs) { + return *lhs == *rhs; + } + + bool operator()(const NMonitoring::ILabelsPtr& lhs, const NMonitoring::ILabels& rhs) { + return *lhs == rhs; + } + + bool operator()(const NMonitoring::ILabels& lhs, const NMonitoring::ILabelsPtr& rhs) { + return lhs == *rhs; + } +}; + +#define Y_MONLIB_DEFINE_LABELS_OUT(T) \ +template <> \ +void Out<T>(IOutputStream& out, const T& labels) { \ + Out<NMonitoring::ILabels>(out, labels); \ +} + +#define Y_MONLIB_DEFINE_LABEL_OUT(T) \ +template <> \ +void Out<T>(IOutputStream& out, const T& label) { \ + Out<NMonitoring::ILabel>(out, label); \ +} |