diff options
author | arkady-e1ppa <arkady-e1ppa@yandex-team.com> | 2024-10-22 18:15:25 +0300 |
---|---|---|
committer | arkady-e1ppa <arkady-e1ppa@yandex-team.com> | 2024-10-22 19:13:37 +0300 |
commit | 477bb1cd2d7d44f218454a8a4137a849eb7e64fa (patch) | |
tree | a9a2acf38b06ab47ecc6a377c82e5ec494ab588b /library/cpp | |
parent | 0bd28574f1df329ac2b07bf9081184f739bcb483 (diff) | |
download | ydb-477bb1cd2d7d44f218454a8a4137a849eb7e64fa.tar.gz |
YT-21233: Introduce TErrorAttributes as an opaque type for attributes to hide dependencies on IAttributeDictionary's API
Plan:
1) Remove `IAttributedDictionary` type from the public API. \+
2) Remove `Set` method from public API in favor of `operator<<=`. \+
3) Adopt `ConvertTo<T>` (or other name) CPO with proper extension into `NYT::NYson::ConvertTo` from `yt/core`.
4) Use CPO from (3) to eliminate direct dependency on `yt/core` of `Get/Find` methods from attributes API.
5) Adopt `ConvertToYsonString` (or other name) CPO with proper extension into `yt/core` customisations.
6) Use CPO from (5) to eliminate direct dependency on `yt/core` of `TErrorAttribute` ctor.
7) Swap attributes implementation to the one which doesn’t use `IAttributeDictionary`.
8) At this point `stripped_error*` can be moved to library/cpp/yt and so can recursively dependant on THROW macro methods `Get/Find/…`.
9) Adjust CPO’s to work with `std::string` instead of `TYsonString` assuming text format to be used (maybe `TString` for now).
10) Remove dep of `library/cpp/yt/error` on `yson` entirely.
This pull request covers steps 1 and 2 laying foundation to 3-4 being implemented in the next one
commit_hash:e899bccdef4ebed321ea2eb93215282694c261ac
Diffstat (limited to 'library/cpp')
-rw-r--r-- | library/cpp/yt/error/error_attributes-inl.h | 72 | ||||
-rw-r--r-- | library/cpp/yt/error/error_attributes.cpp | 62 | ||||
-rw-r--r-- | library/cpp/yt/error/error_attributes.h | 105 | ||||
-rw-r--r-- | library/cpp/yt/error/mergeable_dictionary.h | 57 | ||||
-rw-r--r-- | library/cpp/yt/error/public.h | 17 | ||||
-rw-r--r-- | library/cpp/yt/error/ya.make | 2 |
6 files changed, 315 insertions, 0 deletions
diff --git a/library/cpp/yt/error/error_attributes-inl.h b/library/cpp/yt/error/error_attributes-inl.h new file mode 100644 index 0000000000..a05e62d0e9 --- /dev/null +++ b/library/cpp/yt/error/error_attributes-inl.h @@ -0,0 +1,72 @@ +#ifndef ERROR_ATTRIBUTES_INL_H_ +#error "Direct inclusion of this file is not allowed, include error_attributes.h" +// For the sake of sane code completion. +#include "error_attributes.h" +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +T TErrorAttributes::GetAndRemove(const TString& key) +{ + auto result = Get<T>(key); + Remove(key); + return result; +} + +template <class T> +T TErrorAttributes::Get(TStringBuf key, const T& defaultValue) const +{ + return Find<T>(key).value_or(defaultValue); +} + +template <class T> +T TErrorAttributes::GetAndRemove(const TString& key, const T& defaultValue) +{ + auto result = Find<T>(key); + if (result) { + Remove(key); + return *result; + } else { + return defaultValue; + } +} + +template <class T> +typename TOptionalTraits<T>::TOptional TErrorAttributes::FindAndRemove(const TString& key) +{ + auto result = Find<T>(key); + if (result) { + Remove(key); + } + return result; +} + +template <CMergeableDictionary TDictionary> +void TErrorAttributes::MergeFrom(const TDictionary& dict) +{ + using TTraits = TMergeDictionariesTraits<TDictionary>; + + for (const auto& [key, value] : TTraits::MakeIterableView(dict)) { + SetYson(key, value); + } +} + +//////////////////////////////////////////////////////////////////////////////// + +template <> +struct TMergeDictionariesTraits<TErrorAttributes> +{ + static auto MakeIterableView(const TErrorAttributes& attributes) + { + return attributes.ListPairs(); + } +}; + +static_assert(CMergeableDictionary<TErrorAttributes>); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/error/error_attributes.cpp b/library/cpp/yt/error/error_attributes.cpp new file mode 100644 index 0000000000..2c1b542314 --- /dev/null +++ b/library/cpp/yt/error/error_attributes.cpp @@ -0,0 +1,62 @@ +#include "error_attributes.h" + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +TErrorAttributes::TErrorAttributes(void* attributes) + : Attributes_(attributes) +{ } + +void TErrorAttributes::Clear() +{ + for (const auto& key : ListKeys()) { + Remove(key); + } +} + +NYson::TYsonString TErrorAttributes::GetYsonAndRemove(const TString& key) +{ + auto result = GetYson(key); + Remove(key); + return result; +} + +bool TErrorAttributes::Contains(TStringBuf key) const +{ + return FindYson(key).operator bool(); +} + +bool operator == (const TErrorAttributes& lhs, const TErrorAttributes& rhs) +{ + auto lhsPairs = lhs.ListPairs(); + auto rhsPairs = rhs.ListPairs(); + if (lhsPairs.size() != rhsPairs.size()) { + return false; + } + + std::sort(lhsPairs.begin(), lhsPairs.end(), [] (const auto& lhs, const auto& rhs) { + return lhs.first < rhs.first; + }); + std::sort(rhsPairs.begin(), rhsPairs.end(), [] (const auto& lhs, const auto& rhs) { + return lhs.first < rhs.first; + }); + + for (auto index = 0; index < std::ssize(lhsPairs); ++index) { + if (lhsPairs[index].first != rhsPairs[index].first) { + return false; + } + } + + for (auto index = 0; index < std::ssize(lhsPairs); ++index) { + if (lhsPairs[index].second != rhsPairs[index].second) { + return false; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/error/error_attributes.h b/library/cpp/yt/error/error_attributes.h new file mode 100644 index 0000000000..88771f8360 --- /dev/null +++ b/library/cpp/yt/error/error_attributes.h @@ -0,0 +1,105 @@ +#pragma once + +#include "mergeable_dictionary.h" + +#include <library/cpp/yt/misc/optional.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +// For now this is just an opaque handle to error attributes +// used to remove dependency on IAttributeDictionary in public API. +// Eventually it would be a simple hash map. +// NB(arkady-e1ppa): For now most methods are defined in yt/yt/core/misc/stripped_error.cpp +// eventually they will be moved here. +class TErrorAttributes +{ +public: + using TKey = TString; + using TValue = NYson::TYsonString; + using TKeyValuePair = std::pair<TKey, TValue>; + + //! Returns the list of all keys in the dictionary. + std::vector<TString> ListKeys() const; + + //! Returns the list of all key-value pairs in the dictionary. + std::vector<TKeyValuePair> ListPairs() const; + + //! Returns the value of the attribute (null indicates that the attribute is not found). + NYson::TYsonString FindYson(TStringBuf key) const; + + //! Sets the value of the attribute. + void SetYson(const TString& key, const NYson::TYsonString& value); + + //! Removes the attribute. + //! Returns |true| if the attribute was removed or |false| if there is no attribute with this key. + bool Remove(const TString& key); + + //! Removes all attributes. + void Clear(); + + //! Returns the value of the attribute (throws an exception if the attribute is not found). + NYson::TYsonString GetYson(TStringBuf key) const; + + //! Same as #GetYson but removes the value. + NYson::TYsonString GetYsonAndRemove(const TString& key); + + //! Returns |true| iff the given key is present. + bool Contains(TStringBuf key) const; + + // TODO(arkady-e1ppa): By default deserialization is located at yt/core + // consider using deserialization of some default types (guid, string, int, double) + // to be supported and everything else not supported without inclusion of yt/core. + //! Finds the attribute and deserializes its value. + //! Throws if no such value is found. + template <class T> + T Get(TStringBuf key) const; + + //! Same as #Get but removes the value. + template <class T> + T GetAndRemove(const TString& key); + + //! Finds the attribute and deserializes its value. + //! Uses default value if no such attribute is found. + template <class T> + T Get(TStringBuf key, const T& defaultValue) const; + + //! Same as #Get but removes the value if it exists. + template <class T> + T GetAndRemove(const TString& key, const T& defaultValue); + + //! Finds the attribute and deserializes its value. + //! Returns null if no such attribute is found. + template <class T> + typename TOptionalTraits<T>::TOptional Find(TStringBuf key) const; + + //! Same as #Find but removes the value if it exists. + template <class T> + typename TOptionalTraits<T>::TOptional FindAndRemove(const TString& key); + + template <CMergeableDictionary TDictionary> + void MergeFrom(const TDictionary& dict); + +private: + void* Attributes_; // IAttributesDictionary* + + friend class TErrorOr<void>; + explicit TErrorAttributes(void* attributes); + + TErrorAttributes(const TErrorAttributes& other) = default; + TErrorAttributes& operator= (const TErrorAttributes& other) = default; + + TErrorAttributes(TErrorAttributes&& other) = default; + TErrorAttributes& operator= (TErrorAttributes&& other) = default; +}; + +bool operator == (const TErrorAttributes& lhs, const TErrorAttributes& rhs); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define ERROR_ATTRIBUTES_INL_H_ +#include "error_attributes-inl.h" +#undef ERROR_ATTRIBUTES_INL_H_ diff --git a/library/cpp/yt/error/mergeable_dictionary.h b/library/cpp/yt/error/mergeable_dictionary.h new file mode 100644 index 0000000000..90597059e4 --- /dev/null +++ b/library/cpp/yt/error/mergeable_dictionary.h @@ -0,0 +1,57 @@ +#pragma once + +#include "public.h" + +#include <ranges> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +// Can be specialized to make your dictionary satisfy CMergeableDictionary. +template <class TDictionary> +struct TMergeDictionariesTraits +{ + static auto MakeIterableView(const TDictionary& dict) + requires false; +}; + +//////////////////////////////////////////////////////////////////////////////// + +namespace NDetail { + +template <class T> +struct TMergeableDictionaryImpl +{ + using TView = std::invoke_result_t<decltype(&TMergeDictionariesTraits<T>::MakeIterableView), const T&>; + using TIterator = std::ranges::iterator_t<TView>; + using TValue = typename std::iterator_traits<TIterator>::value_type; + + static constexpr bool ValidSize = requires { + { std::tuple_size<TValue>::value } -> std::same_as<const size_t&>; + } && (std::tuple_size<TValue>::value == 2); + + static constexpr bool CorrectTupleElements = requires { + typename std::tuple_element<0, TValue>::type; + std::same_as<typename std::tuple_element<0, TValue>::type, TString>; + + typename std::tuple_element<1, TValue>::type; + std::same_as<typename std::tuple_element<1, TValue>::type, NYson::TYsonString>; + }; +}; + +} // namespace NDetail + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +concept CMergeableDictionary = + requires (const T& dict) { + TMergeDictionariesTraits<T>::MakeIterableView(dict); + } && + NDetail::TMergeableDictionaryImpl<T>::ValidSize && + NDetail::TMergeableDictionaryImpl<T>::CorrectTupleElements; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/error/public.h b/library/cpp/yt/error/public.h new file mode 100644 index 0000000000..63b95497c7 --- /dev/null +++ b/library/cpp/yt/error/public.h @@ -0,0 +1,17 @@ +#pragma once + +#include <library/cpp/yt/yson_string/string.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +class TErrorOr; + +class TErrorAttributes; +struct TOriginAttributes; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/error/ya.make b/library/cpp/yt/error/ya.make index f5bd946199..60d3e9a92f 100644 --- a/library/cpp/yt/error/ya.make +++ b/library/cpp/yt/error/ya.make @@ -9,9 +9,11 @@ PEERDIR( library/cpp/yt/misc library/cpp/yt/threading library/cpp/yt/string + library/cpp/yt/yson_string # TODO(arkady-e1ppa): eliminate ) SRCS( + error_attributes.cpp origin_attributes.cpp ) |