aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp
diff options
context:
space:
mode:
authorarkady-e1ppa <arkady-e1ppa@yandex-team.com>2024-10-22 18:15:25 +0300
committerarkady-e1ppa <arkady-e1ppa@yandex-team.com>2024-10-22 19:13:37 +0300
commit477bb1cd2d7d44f218454a8a4137a849eb7e64fa (patch)
treea9a2acf38b06ab47ecc6a377c82e5ec494ab588b /library/cpp
parent0bd28574f1df329ac2b07bf9081184f739bcb483 (diff)
downloadydb-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.h72
-rw-r--r--library/cpp/yt/error/error_attributes.cpp62
-rw-r--r--library/cpp/yt/error/error_attributes.h105
-rw-r--r--library/cpp/yt/error/mergeable_dictionary.h57
-rw-r--r--library/cpp/yt/error/public.h17
-rw-r--r--library/cpp/yt/error/ya.make2
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
)