From 59b8ff3945ede83a7792ded99efbaf98ab418c98 Mon Sep 17 00:00:00 2001 From: ubyte Date: Fri, 31 Oct 2025 11:54:32 +0300 Subject: [PATCH] speed up the TValue::HasValue method (#27748) LOGBROKER-10046 --- ydb/public/lib/value/ut/value_ut.cpp | 9 ++++++ ydb/public/lib/value/ut/ya.make | 13 +++++++++ ydb/public/lib/value/value.cpp | 42 ++++++++++++++++++++++++++-- ydb/public/lib/value/value.h | 17 ++--------- ydb/public/lib/value/ya.make | 4 +++ 5 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 ydb/public/lib/value/ut/value_ut.cpp create mode 100644 ydb/public/lib/value/ut/ya.make diff --git a/ydb/public/lib/value/ut/value_ut.cpp b/ydb/public/lib/value/ut/value_ut.cpp new file mode 100644 index 000000000000..ba2a371ab95d --- /dev/null +++ b/ydb/public/lib/value/ut/value_ut.cpp @@ -0,0 +1,9 @@ + +#include +#include + +#include + +TEST(TValue, FieldsCount) { + ASSERT_EQ(NKikimrMiniKQL::TValue::GetDescriptor()->field_count(), 18) << "update the NKikimr::NClient::TValue wrapper to support new fields"; +} diff --git a/ydb/public/lib/value/ut/ya.make b/ydb/public/lib/value/ut/ya.make new file mode 100644 index 000000000000..b44e9c967d99 --- /dev/null +++ b/ydb/public/lib/value/ut/ya.make @@ -0,0 +1,13 @@ +GTEST() + +SIZE(SMALL) + +PEERDIR( + ydb/public/lib/value +) + +SRCS( + value_ut.cpp +) + +END() diff --git a/ydb/public/lib/value/value.cpp b/ydb/public/lib/value/value.cpp index 96339970ab90..9ead53467836 100644 --- a/ydb/public/lib/value/value.cpp +++ b/ydb/public/lib/value/value.cpp @@ -4,10 +4,14 @@ #include +#include + #include +#include #include #include #include +#include #include namespace NKikimr { @@ -28,6 +32,24 @@ TValue TValue::Create(const NKikimrMiniKQL::TResult& result) { return TValue::Create(result.GetValue(), result.GetType()); } +static bool ValueProtobufHasEmptyPayload(const NKikimrMiniKQL::TValue& value) { + bool emptyPayload = true; + emptyPayload &= (value.value_value_case() == value.VALUE_VALUE_NOT_SET); + emptyPayload &= value.GetList().empty(); + emptyPayload &= value.GetTuple().empty(); + emptyPayload &= value.GetStruct().empty(); + emptyPayload &= value.GetDict().empty(); + emptyPayload &= !value.HasHi128(); + emptyPayload &= !value.HasVariantIndex(); + // Non-empty unknown fields are a weird case, as they are not accessible through the wrapper and can only be viewed in the debug dump. + // If the value is not considered empty, the wrapper will return a non-empty value, for which no accessor can return a meaningful value. + constexpr bool checkUnknownFields = false; + if (checkUnknownFields) { + emptyPayload = emptyPayload && value.unknown_fields().empty(); + } + return emptyPayload; +} + bool TValue::HaveValue() const { return !IsNull(); } @@ -35,7 +57,8 @@ bool TValue::HaveValue() const { bool TValue::IsNull() const { if (&Value == &Null) return true; - return Value.ByteSize() == 0; + + return ValueProtobufHasEmptyPayload(Value); } TValue TValue::operator [](const char* name) const { @@ -108,6 +131,21 @@ TVector TValue::GetMembersNames() const { return members; } +TString TValue::DumpToString() const { + TStringBuilder dump; + TString res; + ::google::protobuf::TextFormat::PrintToString(Type, &res); + dump << "Type:" << Endl << res << Endl; + ::google::protobuf::TextFormat::PrintToString(Value, &res); + dump << "Value:" << Endl << res << Endl; + return std::move(dump); +} + +void TValue::DumpValue() const { + Cerr << DumpToString(); +} + + TWriteValue TWriteValue::Create(NKikimrMiniKQL::TValue& value, NKikimrMiniKQL::TType& type) { return TWriteValue(value, type); } @@ -453,7 +491,7 @@ TString TValue::GetDataText() const { case NScheme::NTypeIds::Datetime64: case NScheme::NTypeIds::Timestamp64: case NScheme::NTypeIds::Interval64: - return ToString(Value.GetInt64()); + return ToString(Value.GetInt64()); case NScheme::NTypeIds::JsonDocument: return "\"\""; case NScheme::NTypeIds::Uuid: diff --git a/ydb/public/lib/value/value.h b/ydb/public/lib/value/value.h index 4d60789e9431..ff1f93efacc7 100644 --- a/ydb/public/lib/value/value.h +++ b/ydb/public/lib/value/value.h @@ -4,9 +4,6 @@ #include #include -#include - -#include namespace NKikimr { namespace NClient { @@ -106,19 +103,9 @@ class TValue { // returns member index by name int GetMemberIndex(TStringBuf name) const; - TString DumpToString() const { - TStringBuilder dump; - TString res; - ::google::protobuf::TextFormat::PrintToString(Type, &res); - dump << "Type:" << Endl << res << Endl; - ::google::protobuf::TextFormat::PrintToString(Value, &res); - dump << "Value:" << Endl << res << Endl; - return std::move(dump); - } + TString DumpToString() const; - void DumpValue() const { - Cerr << DumpToString(); - } + void DumpValue() const; // dump value to stderr const NKikimrMiniKQL::TType& GetType() const { return Type; }; const NKikimrMiniKQL::TValue& GetValue() const { return Value; }; diff --git a/ydb/public/lib/value/ya.make b/ydb/public/lib/value/ya.make index 11d101454244..481a9c149bf8 100644 --- a/ydb/public/lib/value/ya.make +++ b/ydb/public/lib/value/ya.make @@ -14,3 +14,7 @@ PEERDIR( ) END() + +RECURSE_FOR_TESTS( + ut +)