diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.cpp b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.cpp index bf813d2cc686..bb81a47a5307 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.cpp +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.cpp @@ -18,6 +18,14 @@ bool TOptimizerPlannerConstructor::DoApplyToCurrentObject(IOptimizerPlanner& cur bool TOptimizerPlannerConstructor::DoIsEqualTo(const IOptimizerPlannerConstructor& item) const { const auto* itemClass = dynamic_cast(&item); AFL_VERIFY(itemClass); + if (Levels.size() != itemClass->Levels.size()) { + return false; + } + for (ui32 i = 0; i < Levels.size(); ++i) { + if (!Levels[i]->IsEqualTo(*itemClass->Levels[i].GetObjectPtrVerified())) { + return false; + } + } return true; } @@ -61,8 +69,8 @@ NKikimr::TConclusionStatus TOptimizerPlannerConstructor::DoDeserializeFromJson(c if (!level) { return TConclusionStatus::Fail("incorrect level class_name: " + className); } - if (!level->DeserializeFromJson(i["description"])) { - return TConclusionStatus::Fail("cannot parse level: " + className + ": " + i["description"].GetStringRobust()); + if (!level->DeserializeFromJson(i)) { + return TConclusionStatus::Fail("cannot parse level: " + i.GetStringRobust()); } Levels.emplace_back(TLevelConstructorContainer(std::shared_ptr(level.Release()))); } diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.h b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.h index f85249435eac..78a73993c57f 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.h +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/constructor.h @@ -12,6 +12,7 @@ class ILevelConstructor { virtual TConclusionStatus DoDeserializeFromJson(const NJson::TJsonValue& json) = 0; virtual bool DoDeserializeFromProto(const NKikimrSchemeOp::TCompactionLevelConstructorContainer& proto) = 0; virtual void DoSerializeToProto(NKikimrSchemeOp::TCompactionLevelConstructorContainer& proto) const = 0; + virtual bool IsEqualToSameClass(const ILevelConstructor& item) const = 0; public: using TFactory = NObjectFactory::TObjectFactory; @@ -19,6 +20,13 @@ class ILevelConstructor { virtual ~ILevelConstructor() = default; + bool IsEqualTo(const ILevelConstructor& item) const { + if (GetClassName() != item.GetClassName()) { + return false; + } + return IsEqualToSameClass(item); + } + std::shared_ptr BuildLevel( const std::shared_ptr& nextLevel, const ui32 indexLevel, const TLevelCounters& counters) const { return DoBuildLevel(nextLevel, indexLevel, counters); diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.cpp b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.cpp index 6a02746bc447..7b5d8599ec1c 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.cpp +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.cpp @@ -5,6 +5,9 @@ namespace NKikimr::NOlap::NStorageOptimizer::NLCBuckets { TConclusionStatus TZeroLevelConstructor::DoDeserializeFromJson(const NJson::TJsonValue& json) { + if (!json.IsMap()) { + return TConclusionStatus::Fail("incorrect level description"); + } if (json.Has("portions_live_duration")) { const auto& jsonValue = json["portions_live_duration"]; if (!jsonValue.IsString()) { diff --git a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.h b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.h index 531c60f3690d..b80dc88d2a62 100644 --- a/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.h +++ b/ydb/core/tx/columnshard/engines/storage/optimizer/lcbuckets/constructor/zero_level.h @@ -18,6 +18,10 @@ class TZeroLevelConstructor: public ILevelConstructor { virtual TConclusionStatus DoDeserializeFromJson(const NJson::TJsonValue& json) override; virtual bool DoDeserializeFromProto(const NKikimrSchemeOp::TCompactionLevelConstructorContainer& proto) override; virtual void DoSerializeToProto(NKikimrSchemeOp::TCompactionLevelConstructorContainer& proto) const override; + virtual bool IsEqualToSameClass(const ILevelConstructor& item) const override { + const auto& itemCast = dynamic_cast(item); + return PortionsLiveDuration == itemCast.PortionsLiveDuration && ExpectedBlobsSize == itemCast.ExpectedBlobsSize; + } static const inline TFactory::TRegistrator Registrator = TFactory::TRegistrator(GetClassNameStatic());