From c352cb4fd40e357bcf8c907190c590601a6c7d72 Mon Sep 17 00:00:00 2001 From: Ilia Shakhov <46408420+pixcc@users.noreply.github.com> Date: Tue, 26 Dec 2023 13:06:11 +0300 Subject: [PATCH] Start tablets in object domain KIKIMR-20271 (#705) * Start tablets in object domain KIKIMR-20271 --- ydb/core/base/hive.h | 6 + ydb/core/base/subdomain.h | 3 + ydb/core/mind/hive/domain_info.cpp | 22 ++ ydb/core/mind/hive/domain_info.h | 12 +- ydb/core/mind/hive/follower_group.h | 5 +- ydb/core/mind/hive/hive.cpp | 25 +- ydb/core/mind/hive/hive.h | 7 + ydb/core/mind/hive/hive_domains.cpp | 12 + ydb/core/mind/hive/hive_impl.cpp | 24 +- ydb/core/mind/hive/hive_impl.h | 4 +- ydb/core/mind/hive/hive_schema.h | 3 +- ydb/core/mind/hive/hive_ut.cpp | 226 ++++++++++++++++++ ydb/core/mind/hive/leader_tablet_info.cpp | 5 +- ydb/core/mind/hive/leader_tablet_info.h | 1 + ydb/core/mind/hive/monitoring.cpp | 13 +- ydb/core/mind/hive/node_info.cpp | 5 +- ydb/core/mind/hive/tx__create_tablet.cpp | 3 +- ydb/core/mind/hive/tx__load_everything.cpp | 4 + ydb/core/mind/hive/tx__update_domain.cpp | 50 +++- ydb/core/mind/hive/ya.make | 1 + ydb/core/protos/counters_schemeshard.proto | 1 + ydb/core/protos/hive.proto | 10 + ydb/core/testlib/tablet_helpers.cpp | 21 ++ ydb/core/testlib/tablet_helpers.h | 24 +- ydb/core/tx/schemeshard/schemeshard__init.cpp | 1 + ...emeshard__operation_alter_extsubdomain.cpp | 83 ++++++- .../schemeshard__operation_common_subdomain.h | 8 +- .../schemeshard/schemeshard__operation_part.h | 1 + ydb/core/tx/schemeshard/schemeshard_impl.cpp | 37 ++- ydb/core/tx/schemeshard/schemeshard_impl.h | 1 + .../tx/schemeshard/schemeshard_info_types.h | 2 - ydb/core/tx/schemeshard/schemeshard_schema.h | 4 +- .../tx/schemeshard/schemeshard_tx_infly.h | 2 + .../tx/schemeshard/ut_helpers/test_env.cpp | 16 ++ ydb/core/tx/schemeshard/ut_helpers/test_env.h | 4 + .../ut_serverless/ut_serverless.cpp | 7 + .../ut_serverless_reboots.cpp | 18 +- .../flat_hive.schema | 8 +- .../flat_schemeshard.schema | 6 + 39 files changed, 636 insertions(+), 49 deletions(-) create mode 100644 ydb/core/mind/hive/domain_info.cpp diff --git a/ydb/core/base/hive.h b/ydb/core/base/hive.h index d763d80c41b4..993d38f3bcad 100644 --- a/ydb/core/base/hive.h +++ b/ydb/core/base/hive.h @@ -47,6 +47,7 @@ namespace NKikimr { EvRequestTabletOwners, EvReassignOnDecommitGroup, EvUpdateTabletsObject, + EvUpdateDomain, // replies EvBootTabletReply = EvBootTablet + 512, @@ -80,6 +81,7 @@ namespace NKikimr { EvInvalidateStoragePoolsReply, EvReassignOnDecommitGroupReply, EvUpdateTabletsObjectReply, + EvUpdateDomainReply, EvEnd }; @@ -862,6 +864,10 @@ namespace NKikimr { Record.SetStatus(status); } }; + + struct TEvUpdateDomain : TEventPB {}; + + struct TEvUpdateDomainReply : TEventPB {}; }; IActor* CreateDefaultHive(const TActorId &tablet, TTabletStorageInfo *info); diff --git a/ydb/core/base/subdomain.h b/ydb/core/base/subdomain.h index 0e1101bc781b..3849bd8ca816 100644 --- a/ydb/core/base/subdomain.h +++ b/ydb/core/base/subdomain.h @@ -2,6 +2,7 @@ #include +#include #include #include @@ -29,6 +30,8 @@ struct TSubDomainKey : public std::pair { }; static const TSubDomainKey InvalidSubDomainKey = TSubDomainKey(); + +using TMaybeServerlessComputeResourcesMode = TMaybe; } template <> diff --git a/ydb/core/mind/hive/domain_info.cpp b/ydb/core/mind/hive/domain_info.cpp new file mode 100644 index 000000000000..27f0e6747cc7 --- /dev/null +++ b/ydb/core/mind/hive/domain_info.cpp @@ -0,0 +1,22 @@ +#include "domain_info.h" + +namespace NKikimr { +namespace NHive { + +ENodeSelectionPolicy TDomainInfo::GetNodeSelectionPolicy() const { + if (!ServerlessComputeResourcesMode) { + return ENodeSelectionPolicy::Default; + } + + switch (*ServerlessComputeResourcesMode) { + case NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED: + return ENodeSelectionPolicy::PreferObjectDomain; + case NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_SHARED: + return ENodeSelectionPolicy::Default; + default: + return ENodeSelectionPolicy::Default; + } +} + +} // NHive +} // NKikimr diff --git a/ydb/core/mind/hive/domain_info.h b/ydb/core/mind/hive/domain_info.h index 1a737dbafbf0..a1b61977a872 100644 --- a/ydb/core/mind/hive/domain_info.h +++ b/ydb/core/mind/hive/domain_info.h @@ -5,10 +5,18 @@ namespace NKikimr { namespace NHive { +enum class ENodeSelectionPolicy : ui32 { + Default, + PreferObjectDomain, +}; + struct TDomainInfo { TString Path; TTabletId HiveId = 0; + TMaybeServerlessComputeResourcesMode ServerlessComputeResourcesMode; + + ENodeSelectionPolicy GetNodeSelectionPolicy() const; }; -} -} +} // NHive +} // NKikimr diff --git a/ydb/core/mind/hive/follower_group.h b/ydb/core/mind/hive/follower_group.h index 68f863e7b34a..328cfb4a6e75 100644 --- a/ydb/core/mind/hive/follower_group.h +++ b/ydb/core/mind/hive/follower_group.h @@ -17,7 +17,10 @@ struct TFollowerGroup { bool RequireDifferentNodes = false; // do not run followers on same nodes as another followers of the same leader bool FollowerCountPerDataCenter = false; // PER_AZ KIKIMR-10443 - TFollowerGroup() = default; + explicit TFollowerGroup(const THive& hive) + : NodeFilter(hive) + {} + TFollowerGroup(const TFollowerGroup&) = delete; TFollowerGroup(TFollowerGroup&&) = delete; TFollowerGroup& operator =(const TFollowerGroup&) = delete; diff --git a/ydb/core/mind/hive/hive.cpp b/ydb/core/mind/hive/hive.cpp index 1879c2d0fc51..803704e1627d 100644 --- a/ydb/core/mind/hive/hive.cpp +++ b/ydb/core/mind/hive/hive.cpp @@ -1,4 +1,7 @@ +#include "domain_info.h" #include "hive.h" +#include "hive_impl.h" +#include "leader_tablet_info.h" #include @@ -76,5 +79,25 @@ NMetrics::EResource GetDominantResourceType(const TResourceNormalizedValues& nor } return dominant; } + +TNodeFilter::TNodeFilter(const THive& hive) + : Hive(hive) +{} + +TArrayRef TNodeFilter::GetEffectiveAllowedDomains() const { + const auto* objectDomainInfo = Hive.FindDomain(ObjectDomain); + + if (!objectDomainInfo) { + return {AllowedDomains.begin(), AllowedDomains.end()}; + } + + switch (objectDomainInfo->GetNodeSelectionPolicy()) { + case ENodeSelectionPolicy::Default: + return {AllowedDomains.begin(), AllowedDomains.end()}; + case ENodeSelectionPolicy::PreferObjectDomain: + return {&ObjectDomain, 1}; + } } -} + +} // NHive +} // NKikimr diff --git a/ydb/core/mind/hive/hive.h b/ydb/core/mind/hive/hive.h index f573ff863b40..860f1124f09a 100644 --- a/ydb/core/mind/hive/hive.h +++ b/ydb/core/mind/hive/hive.h @@ -275,6 +275,13 @@ struct TNodeFilter { TVector AllowedDomains; TVector AllowedNodes; TVector AllowedDataCenters; + TSubDomainKey ObjectDomain; + + const THive& Hive; + + explicit TNodeFilter(const THive& hive); + + TArrayRef GetEffectiveAllowedDomains() const; }; } // NHive diff --git a/ydb/core/mind/hive/hive_domains.cpp b/ydb/core/mind/hive/hive_domains.cpp index 2b483eafdf56..0f5536f18a4d 100644 --- a/ydb/core/mind/hive/hive_domains.cpp +++ b/ydb/core/mind/hive/hive_domains.cpp @@ -62,6 +62,18 @@ void THive::Handle(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) { } } +void THive::Handle(TEvHive::TEvUpdateDomain::TPtr& ev) { + BLOG_D("Handle TEvHive::TEvUpdateDomain(" << ev->Get()->Record.ShortDebugString() << ")"); + const TSubDomainKey subdomainKey(ev->Get()->Record.GetDomainKey()); + TDomainInfo& domainInfo = Domains[subdomainKey]; + if (ev->Get()->Record.GetServerlessComputeResourcesMode() != NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_UNSPECIFIED) { + domainInfo.ServerlessComputeResourcesMode = ev->Get()->Record.GetServerlessComputeResourcesMode(); + } else { + domainInfo.ServerlessComputeResourcesMode.Clear(); + } + Execute(CreateUpdateDomain(subdomainKey, std::move(ev))); +} + TString THive::GetDomainName(TSubDomainKey domain) { auto itDomain = Domains.find(domain); if (itDomain != Domains.end()) { diff --git a/ydb/core/mind/hive/hive_impl.cpp b/ydb/core/mind/hive/hive_impl.cpp index 98f031b6ef1e..84657f26e047 100644 --- a/ydb/core/mind/hive/hive_impl.cpp +++ b/ydb/core/mind/hive/hive_impl.cpp @@ -10,8 +10,7 @@ #include #include -template <> -inline IOutputStream& operator <<(IOutputStream& out, const TArrayRef& vec) { +Y_DECLARE_OUT_SPEC(inline, TArrayRef, out, vec) { out << '['; for (auto it = vec.begin(); it != vec.end(); ++it) { if (it != vec.begin()) @@ -19,7 +18,10 @@ inline IOutputStream& operator <<(IOutputStream& out, const TArrayRefShortDebugString(); } out << ']'; - return out; +} + +Y_DECLARE_OUT_SPEC(inline, TArrayRef, out, vec) { + out << '[' << JoinSeq(',', vec) << ']'; } namespace NKikimr { @@ -1268,7 +1270,8 @@ THive::TBestNodeResult THive::FindBestNode(const TTabletInfo& tablet) { << " to run the tablet " << tablet.ToString() << " node domains " << nodeInfo.ServicedDomains << " tablet object domain " << tablet.GetLeader().ObjectDomain - << " tablet allowed domains " << tablet.GetNodeFilter().AllowedDomains); + << " tablet allowed domains " << tablet.GetNodeFilter().AllowedDomains + << " tablet effective allowed domains " << tablet.GetNodeFilter().GetEffectiveAllowedDomains()); } } if (!selectedNodes.empty()) { @@ -1284,6 +1287,7 @@ THive::TBestNodeResult THive::FindBestNode(const TTabletInfo& tablet) { TNodeInfo* selectedNode = nullptr; if (!selectedNodes.empty()) { selectedNodes = SelectMaxPriorityNodes(std::move(selectedNodes), tablet); + BLOG_TRACE("[FBN] Tablet " << tablet.ToString() << " selected max priority nodes count " << selectedNodes.size()); switch (GetNodeSelectStrategy()) { case NKikimrConfig::THiveConfig::HIVE_NODE_SELECT_STRATEGY_WEIGHTED_RANDOM: @@ -1336,7 +1340,7 @@ THive::TBestNodeResult THive::FindBestNode(const TTabletInfo& tablet) { } nodesLeft -= debugState.NodesWithSomeoneFromOurFamily; if (debugState.NodesWithoutDomain == nodesLeft) { - tablet.BootState = TStringBuilder() << "Can't find domain " << tablet.GetNodeFilter().AllowedDomains; + tablet.BootState = TStringBuilder() << "Can't find domain " << tablet.GetNodeFilter().GetEffectiveAllowedDomains(); return TBestNodeResult(true); } nodesLeft -= debugState.NodesWithoutDomain; @@ -1486,6 +1490,14 @@ TDomainInfo* THive::FindDomain(TSubDomainKey key) { return &it->second; } +const TDomainInfo* THive::FindDomain(TSubDomainKey key) const { + auto it = Domains.find(key); + if (it == Domains.end()) { + return nullptr; + } + return &it->second; +} + void THive::DeleteTablet(TTabletId tabletId) { auto it = Tablets.find(tabletId); if (it != Tablets.end()) { @@ -2813,6 +2825,7 @@ void THive::ProcessEvent(std::unique_ptr event) { hFunc(TEvHive::TEvUpdateTabletsObject, Handle); hFunc(TEvPrivate::TEvRefreshStorageInfo, Handle); hFunc(TEvPrivate::TEvLogTabletMoves, Handle); + hFunc(TEvHive::TEvUpdateDomain, Handle); } } @@ -2910,6 +2923,7 @@ STFUNC(THive::StateWork) { fFunc(TEvHive::TEvUpdateTabletsObject::EventType, EnqueueIncomingEvent); fFunc(TEvPrivate::TEvRefreshStorageInfo::EventType, EnqueueIncomingEvent); fFunc(TEvPrivate::TEvLogTabletMoves::EventType, EnqueueIncomingEvent); + fFunc(TEvHive::TEvUpdateDomain::EventType, EnqueueIncomingEvent); hFunc(TEvPrivate::TEvProcessIncomingEvent, Handle); default: if (!HandleDefaultEvents(ev, SelfId())) { diff --git a/ydb/core/mind/hive/hive_impl.h b/ydb/core/mind/hive/hive_impl.h index e3318ad1e42f..48da31fc7617 100644 --- a/ydb/core/mind/hive/hive_impl.h +++ b/ydb/core/mind/hive/hive_impl.h @@ -279,7 +279,6 @@ class THive : public TActor, public TTabletExecutedFlat, public THiveShar ITransaction* CreateDisconnectNode(THolder event); ITransaction* CreateProcessPendingOperations(); ITransaction* CreateProcessBootQueue(); - ITransaction* CreateUpdateDomain(TSubDomainKey subdomainKey); ITransaction* CreateSeizeTablets(TEvHive::TEvSeizeTablets::TPtr event); ITransaction* CreateSeizeTabletsReply(TEvHive::TEvSeizeTabletsReply::TPtr event); ITransaction* CreateReleaseTablets(TEvHive::TEvReleaseTablets::TPtr event); @@ -290,6 +289,7 @@ class THive : public TActor, public TTabletExecutedFlat, public THiveShar ITransaction* CreateTabletOwnersReply(TEvHive::TEvTabletOwnersReply::TPtr event); ITransaction* CreateRequestTabletOwners(TEvHive::TEvRequestTabletOwners::TPtr event); ITransaction* CreateUpdateTabletsObject(TEvHive::TEvUpdateTabletsObject::TPtr event); + ITransaction* CreateUpdateDomain(TSubDomainKey subdomainKey, TEvHive::TEvUpdateDomain::TPtr event = {}); public: TDomainsView DomainsView; @@ -549,6 +549,7 @@ class THive : public TActor, public TTabletExecutedFlat, public THiveShar void Handle(TEvPrivate::TEvRefreshStorageInfo::TPtr& ev); void Handle(TEvPrivate::TEvLogTabletMoves::TPtr& ev); void Handle(TEvPrivate::TEvProcessIncomingEvent::TPtr& ev); + void Handle(TEvHive::TEvUpdateDomain::TPtr& ev); protected: void RestartPipeTx(ui64 tabletId); @@ -618,6 +619,7 @@ class THive : public TActor, public TTabletExecutedFlat, public THiveShar TStoragePoolInfo& GetStoragePool(const TString& name); TStoragePoolInfo* FindStoragePool(const TString& name); TDomainInfo* FindDomain(TSubDomainKey key); + const TDomainInfo* FindDomain(TSubDomainKey key) const; const TNodeLocation& GetNodeLocation(TNodeId nodeId) const; void DeleteTablet(TTabletId tabletId); void DeleteNode(TNodeId nodeId); diff --git a/ydb/core/mind/hive/hive_schema.h b/ydb/core/mind/hive/hive_schema.h index 8fdd9cf6c79c..56437f392639 100644 --- a/ydb/core/mind/hive/hive_schema.h +++ b/ydb/core/mind/hive/hive_schema.h @@ -267,9 +267,10 @@ struct Schema : NIceDb::Schema { struct Path : Column<3, NScheme::NTypeIds::Utf8> {}; struct Primary : Column<4, NScheme::NTypeIds::Bool> {}; struct HiveId : Column<5, NScheme::NTypeIds::Uint64> {}; + struct ServerlessComputeResourcesMode : Column<6, NScheme::NTypeIds::Uint32> { using Type = NKikimrSubDomains::EServerlessComputeResourcesMode; }; using TKey = TableKey; - using TColumns = TableColumns; + using TColumns = TableColumns; }; struct BlockedOwner : Table<18> { diff --git a/ydb/core/mind/hive/hive_ut.cpp b/ydb/core/mind/hive/hive_ut.cpp index 557759d9a392..0bc81799c607 100644 --- a/ydb/core/mind/hive/hive_ut.cpp +++ b/ydb/core/mind/hive/hive_ut.cpp @@ -5903,6 +5903,232 @@ Y_UNIT_TEST_SUITE(THiveTest) { runtime.DispatchEvents(options); UNIT_ASSERT(seenLocalRegistrationInSharedHive); } + + void AssertTabletStartedOnNode(TTestBasicRuntime& runtime, ui64 tabletId, ui32 nodeIndex) { + const ui64 hiveTablet = MakeDefaultHiveID(0); + TActorId sender = runtime.AllocateEdgeActor(0); + runtime.SendToPipe(hiveTablet, sender, new TEvHive::TEvRequestHiveInfo()); + TAutoPtr handle; + TEvHive::TEvResponseHiveInfo* response = runtime.GrabEdgeEventRethrow(handle); + ui32 nodeId = runtime.GetNodeId(nodeIndex); + bool foundTablet = false; + for (const NKikimrHive::TTabletInfo& tablet : response->Record.GetTablets()) { + if (tablet.GetTabletID() == tabletId) { + foundTablet = true; + UNIT_ASSERT_EQUAL_C(tablet.GetNodeID(), nodeId, "tablet started on wrong node"); + } + } + UNIT_ASSERT(foundTablet); + } + + Y_UNIT_TEST(TestServerlessComputeResourcesMode) { + TTestBasicRuntime runtime(2, false); + Setup(runtime, true); + + const ui64 hiveTablet = MakeDefaultHiveID(0); + const ui64 testerTablet = MakeDefaultHiveID(1); + const TActorId hiveActor = CreateTestBootstrapper(runtime, CreateTestTabletInfo(hiveTablet, TTabletTypes::Hive), &CreateDefaultHive); + runtime.EnableScheduleForActor(hiveActor); + CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::SchemeShard, TTabletTypes::SchemeShard), &CreateFlatTxSchemeShard); + MakeSureTabletIsUp(runtime, hiveTablet, 0); // root hive good + MakeSureTabletIsUp(runtime, TTestTxConfig::SchemeShard, 0); // root ss good + + TActorId sender = runtime.AllocateEdgeActor(0); + InitSchemeRoot(runtime, sender); + + // Create subdomain + ui32 txId = 100; + TSubDomainKey subdomainKey; + do { + auto modifyScheme = MakeHolder(); + modifyScheme->Record.SetTxId(++txId); + auto* transaction = modifyScheme->Record.AddTransaction(); + transaction->SetWorkingDir("/dc-1"); + transaction->SetOperationType(NKikimrSchemeOp::ESchemeOpCreateExtSubDomain); + auto* subdomain = transaction->MutableSubDomain(); + subdomain->SetName("tenant1"); + runtime.SendToPipe(TTestTxConfig::SchemeShard, sender, modifyScheme.Release()); + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle, TDuration::MilliSeconds(100)); + if (reply) { + subdomainKey = TSubDomainKey(reply->Record.GetSchemeshardId(), reply->Record.GetPathId()); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrScheme::EStatus::StatusAccepted); + break; + } + } while (true); + + // Start local for subdomain + SendKillLocal(runtime, 1); + CreateLocalForTenant(runtime, 1, "/dc-1/tenant1"); + + THolder createTablet = MakeHolder(testerTablet, 1, TTabletTypes::Dummy, BINDED_CHANNELS); + createTablet->Record.AddAllowedDomains(); + createTablet->Record.MutableAllowedDomains(0)->SetSchemeShard(TTestTxConfig::SchemeShard); + createTablet->Record.MutableAllowedDomains(0)->SetPathId(1); + createTablet->Record.MutableObjectDomain()->SetSchemeShard(subdomainKey.GetSchemeShard()); + createTablet->Record.MutableObjectDomain()->SetPathId(subdomainKey.GetPathId()); + ui64 dummyTabletId = SendCreateTestTablet(runtime, hiveTablet, testerTablet, std::move(createTablet), 0, true); + + MakeSureTabletIsUp(runtime, dummyTabletId, 0); + AssertTabletStartedOnNode(runtime, dummyTabletId, 0); // started in allowed domain + + { + auto ev = MakeHolder(); + ev->Record.SetTxId(++txId); + ev->Record.MutableDomainKey()->SetSchemeShard(subdomainKey.GetSchemeShard()); + ev->Record.MutableDomainKey()->SetPathId(subdomainKey.GetPathId()); + ev->Record.SetServerlessComputeResourcesMode(NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED); + runtime.SendToPipe(hiveTablet, sender, ev.Release()); + TAutoPtr handle; + TEvHive::TEvUpdateDomainReply* response = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetTxId(), txId); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetOrigin(), hiveTablet); + } + + // restart to kick tablet + SendKillLocal(runtime, 0); + { + TDispatchOptions options; + options.FinalEvents.emplace_back(TEvLocal::EvStopTablet); + runtime.DispatchEvents(options); + } + CreateLocal(runtime, 0); + + MakeSureTabletIsUp(runtime, dummyTabletId, 0); + AssertTabletStartedOnNode(runtime, dummyTabletId, 1); // started in object domain + + { + auto ev = MakeHolder(); + ev->Record.SetTxId(++txId); + ev->Record.MutableDomainKey()->SetSchemeShard(subdomainKey.GetSchemeShard()); + ev->Record.MutableDomainKey()->SetPathId(subdomainKey.GetPathId()); + ev->Record.SetServerlessComputeResourcesMode(NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_SHARED); + runtime.SendToPipe(hiveTablet, sender, ev.Release()); + TAutoPtr handle; + TEvHive::TEvUpdateDomainReply* response = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetTxId(), txId); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetOrigin(), hiveTablet); + } + + // restart to kick tablet + SendKillLocal(runtime, 1); + { + TDispatchOptions options; + options.FinalEvents.emplace_back(TEvLocal::EvStopTablet); + runtime.DispatchEvents(options); + } + CreateLocalForTenant(runtime, 1, "/dc-1/tenant1"); + + MakeSureTabletIsUp(runtime, dummyTabletId, 0); + AssertTabletStartedOnNode(runtime, dummyTabletId, 0); // started in allowed domain + + SendKillLocal(runtime, 0); + runtime.SimulateSleep(TDuration::Seconds(1)); + MakeSureTabletIsDown(runtime, dummyTabletId, 0); // can't start because there are no allowed domain nodes + } + + Y_UNIT_TEST(TestResetServerlessComputeResourcesMode) { + TTestBasicRuntime runtime(2, false); + Setup(runtime, true); + + const ui64 hiveTablet = MakeDefaultHiveID(0); + const ui64 testerTablet = MakeDefaultHiveID(1); + const TActorId hiveActor = CreateTestBootstrapper(runtime, CreateTestTabletInfo(hiveTablet, TTabletTypes::Hive), &CreateDefaultHive); + runtime.EnableScheduleForActor(hiveActor); + CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::SchemeShard, TTabletTypes::SchemeShard), &CreateFlatTxSchemeShard); + MakeSureTabletIsUp(runtime, hiveTablet, 0); // root hive good + MakeSureTabletIsUp(runtime, TTestTxConfig::SchemeShard, 0); // root ss good + + TActorId sender = runtime.AllocateEdgeActor(0); + InitSchemeRoot(runtime, sender); + + // Create subdomain + ui32 txId = 100; + TSubDomainKey subdomainKey; + do { + auto modifyScheme = MakeHolder(); + modifyScheme->Record.SetTxId(++txId); + auto* transaction = modifyScheme->Record.AddTransaction(); + transaction->SetWorkingDir("/dc-1"); + transaction->SetOperationType(NKikimrSchemeOp::ESchemeOpCreateExtSubDomain); + auto* subdomain = transaction->MutableSubDomain(); + subdomain->SetName("tenant1"); + runtime.SendToPipe(TTestTxConfig::SchemeShard, sender, modifyScheme.Release()); + TAutoPtr handle; + auto reply = runtime.GrabEdgeEventRethrow(handle, TDuration::MilliSeconds(100)); + if (reply) { + subdomainKey = TSubDomainKey(reply->Record.GetSchemeshardId(), reply->Record.GetPathId()); + UNIT_ASSERT_VALUES_EQUAL(reply->Record.GetStatus(), NKikimrScheme::EStatus::StatusAccepted); + break; + } + } while (true); + + // Start local for subdomain + SendKillLocal(runtime, 1); + CreateLocalForTenant(runtime, 1, "/dc-1/tenant1"); + + THolder createTablet = MakeHolder(testerTablet, 1, TTabletTypes::Dummy, BINDED_CHANNELS); + createTablet->Record.AddAllowedDomains(); + createTablet->Record.MutableAllowedDomains(0)->SetSchemeShard(TTestTxConfig::SchemeShard); + createTablet->Record.MutableAllowedDomains(0)->SetPathId(1); + createTablet->Record.MutableObjectDomain()->SetSchemeShard(subdomainKey.GetSchemeShard()); + createTablet->Record.MutableObjectDomain()->SetPathId(subdomainKey.GetPathId()); + ui64 dummyTabletId = SendCreateTestTablet(runtime, hiveTablet, testerTablet, std::move(createTablet), 0, true); + + MakeSureTabletIsUp(runtime, dummyTabletId, 0); + AssertTabletStartedOnNode(runtime, dummyTabletId, 0); // started in allowed domain + + { + auto ev = MakeHolder(); + ev->Record.SetTxId(++txId); + ev->Record.MutableDomainKey()->SetSchemeShard(subdomainKey.GetSchemeShard()); + ev->Record.MutableDomainKey()->SetPathId(subdomainKey.GetPathId()); + ev->Record.SetServerlessComputeResourcesMode(NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED); + runtime.SendToPipe(hiveTablet, sender, ev.Release()); + TAutoPtr handle; + TEvHive::TEvUpdateDomainReply* response = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetTxId(), txId); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetOrigin(), hiveTablet); + } + + // restart to kick tablet + SendKillLocal(runtime, 0); + { + TDispatchOptions options; + options.FinalEvents.emplace_back(TEvLocal::EvStopTablet); + runtime.DispatchEvents(options); + } + CreateLocal(runtime, 0); + + MakeSureTabletIsUp(runtime, dummyTabletId, 0); + AssertTabletStartedOnNode(runtime, dummyTabletId, 1); // started in object domain + + // reset ServerlessComputeResourcesMode + { + auto ev = MakeHolder(); + ev->Record.SetTxId(++txId); + ev->Record.MutableDomainKey()->SetSchemeShard(subdomainKey.GetSchemeShard()); + ev->Record.MutableDomainKey()->SetPathId(subdomainKey.GetPathId()); + ev->Record.SetServerlessComputeResourcesMode(NKikimrSubDomains::SERVERLESS_COMPUTE_RESOURCES_MODE_UNSPECIFIED); + runtime.SendToPipe(hiveTablet, sender, ev.Release()); + TAutoPtr handle; + TEvHive::TEvUpdateDomainReply* response = runtime.GrabEdgeEventRethrow(handle); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetTxId(), txId); + UNIT_ASSERT_VALUES_EQUAL(response->Record.GetOrigin(), hiveTablet); + } + + // restart to kick tablet + SendKillLocal(runtime, 1); + { + TDispatchOptions options; + options.FinalEvents.emplace_back(TEvLocal::EvStopTablet); + runtime.DispatchEvents(options); + } + CreateLocalForTenant(runtime, 1, "/dc-1/tenant1"); + + MakeSureTabletIsUp(runtime, dummyTabletId, 0); + AssertTabletStartedOnNode(runtime, dummyTabletId, 0); // started in allowed domain + } } } diff --git a/ydb/core/mind/hive/leader_tablet_info.cpp b/ydb/core/mind/hive/leader_tablet_info.cpp index 04a1892eb570..45be79e32ae6 100644 --- a/ydb/core/mind/hive/leader_tablet_info.cpp +++ b/ydb/core/mind/hive/leader_tablet_info.cpp @@ -77,8 +77,10 @@ void TLeaderTabletInfo::AssignDomains(const TSubDomainKey& objectDomain, const T NodeFilter.AllowedDomains = { Hive.GetRootDomainKey() }; ObjectDomain = { Hive.GetRootDomainKey() }; } + NodeFilter.ObjectDomain = ObjectDomain; for (auto& followerGroup : FollowerGroups) { followerGroup.NodeFilter.AllowedDomains = NodeFilter.AllowedDomains; + followerGroup.NodeFilter.ObjectDomain = NodeFilter.ObjectDomain; } } @@ -133,7 +135,7 @@ TFollowerGroupId TLeaderTabletInfo::GenerateFollowerGroupId() const { } TFollowerGroup& TLeaderTabletInfo::AddFollowerGroup(TFollowerGroupId followerGroupId) { - FollowerGroups.emplace_back(); + FollowerGroups.emplace_back(Hive); TFollowerGroup& followerGroup = FollowerGroups.back(); if (followerGroupId == 0) { followerGroup.Id = GenerateFollowerGroupId(); @@ -141,6 +143,7 @@ TFollowerGroup& TLeaderTabletInfo::AddFollowerGroup(TFollowerGroupId followerGro followerGroup.Id = followerGroupId; } followerGroup.NodeFilter.AllowedDomains = NodeFilter.AllowedDomains; + followerGroup.NodeFilter.ObjectDomain = NodeFilter.ObjectDomain; return followerGroup; } diff --git a/ydb/core/mind/hive/leader_tablet_info.h b/ydb/core/mind/hive/leader_tablet_info.h index ca9ce963e185..77a2b1c2a8d4 100644 --- a/ydb/core/mind/hive/leader_tablet_info.h +++ b/ydb/core/mind/hive/leader_tablet_info.h @@ -57,6 +57,7 @@ struct TLeaderTabletInfo : TTabletInfo { , State(ETabletState::Unknown) , Type(TTabletTypes::TypeInvalid) , ObjectId(0, 0) + , NodeFilter(hive) , ChannelProfileReassignReason(NKikimrHive::TEvReassignTablet::HIVE_REASSIGN_REASON_NO) , KnownGeneration(0) , Category(nullptr) diff --git a/ydb/core/mind/hive/monitoring.cpp b/ydb/core/mind/hive/monitoring.cpp index 7eb691103a72..e08f3b4e90b0 100644 --- a/ydb/core/mind/hive/monitoring.cpp +++ b/ydb/core/mind/hive/monitoring.cpp @@ -3264,6 +3264,16 @@ class TTxMonEvent_TabletInfo : public TTransactionBase { return result; } + template + static NJson::TJsonValue MakeFrom(const TArrayRef& arrayRef) { + NJson::TJsonValue result; + result.SetType(NJson::JSON_ARRAY); + for (const auto& item : arrayRef) { + result.AppendValue(MakeFrom(item)); + } + return result; + } + static NJson::TJsonValue MakeFrom(const TIntrusivePtr& info) { NJson::TJsonValue result; if (info == nullptr) { @@ -3372,7 +3382,8 @@ class TTxMonEvent_TabletInfo : public TTransactionBase { result["KnownGeneration"] = tablet.KnownGeneration; result["BootMode"] = NKikimrHive::ETabletBootMode_Name(tablet.BootMode); result["Owner"] = TStringBuilder() << tablet.Owner; - result["EffectiveAllowedDomain"] = MakeFrom(tablet.NodeFilter.AllowedDomains); + result["AllowedDomains"] = MakeFrom(tablet.NodeFilter.AllowedDomains); + result["EffectiveAllowedDomains"] = MakeFrom(tablet.NodeFilter.GetEffectiveAllowedDomains()); result["StorageInfoSubscribers"] = MakeFrom(tablet.StorageInfoSubscribers); result["LockedToActor"] = MakeFrom(tablet.LockedToActor); result["LockedReconnectTimeout"] = tablet.LockedReconnectTimeout.ToString(); diff --git a/ydb/core/mind/hive/node_info.cpp b/ydb/core/mind/hive/node_info.cpp index 77d726eaa3ef..f55276d66b8b 100644 --- a/ydb/core/mind/hive/node_info.cpp +++ b/ydb/core/mind/hive/node_info.cpp @@ -102,10 +102,10 @@ void TNodeInfo::UpdateResourceValues(const TTabletInfo* tablet, const NKikimrTab } bool TNodeInfo::MatchesFilter(const TNodeFilter& filter, TTabletDebugState* debugState) const { - const auto& allowedDomains = filter.AllowedDomains; + const auto& effectiveAllowedDomains = filter.GetEffectiveAllowedDomains(); bool result = false; - for (const auto& candidate : allowedDomains) { + for (const auto& candidate : effectiveAllowedDomains) { if (Hive.DomainHasNodes(candidate)) { result = std::find(ServicedDomains.begin(), ServicedDomains.end(), @@ -115,6 +115,7 @@ bool TNodeInfo::MatchesFilter(const TNodeFilter& filter, TTabletDebugState* debu } } } + if (!result) { if (debugState) { debugState->NodesWithoutDomain++; diff --git a/ydb/core/mind/hive/tx__create_tablet.cpp b/ydb/core/mind/hive/tx__create_tablet.cpp index 27660b5dfd94..1222b375d557 100644 --- a/ydb/core/mind/hive/tx__create_tablet.cpp +++ b/ydb/core/mind/hive/tx__create_tablet.cpp @@ -366,7 +366,8 @@ class TTxCreateTablet : public TTransactionBase { tablet.KnownGeneration = 0; // because we will increase it on start tablet.State = ETabletState::GroupAssignment; tablet.ActorsToNotify.push_back(Sender); - tablet.NodeFilter = {.AllowedNodes = AllowedNodeIds, .AllowedDataCenters = AllowedDataCenterIds}; + tablet.NodeFilter.AllowedNodes = AllowedNodeIds; + tablet.NodeFilter.AllowedDataCenters = AllowedDataCenterIds; tablet.Owner = ownerIdx; tablet.DataCentersPreference = DataCentersPreference; tablet.BootMode = BootMode; diff --git a/ydb/core/mind/hive/tx__load_everything.cpp b/ydb/core/mind/hive/tx__load_everything.cpp index 73525a3752bd..93e9a8d8a80e 100644 --- a/ydb/core/mind/hive/tx__load_everything.cpp +++ b/ydb/core/mind/hive/tx__load_everything.cpp @@ -270,6 +270,10 @@ class TTxLoadEverything : public TTransactionBase { if (domainRowset.GetValueOrDefault()) { Self->PrimaryDomainKey = key; } + if (domainRowset.HaveValue()) { + domain.ServerlessComputeResourcesMode = domainRowset.GetValue(); + } + if (!domainRowset.Next()) return false; } diff --git a/ydb/core/mind/hive/tx__update_domain.cpp b/ydb/core/mind/hive/tx__update_domain.cpp index 65f48a0d0f20..494977e1e87d 100644 --- a/ydb/core/mind/hive/tx__update_domain.cpp +++ b/ydb/core/mind/hive/tx__update_domain.cpp @@ -5,36 +5,62 @@ namespace NKikimr { namespace NHive { class TTxUpdateDomain : public TTransactionBase { - TSubDomainKey SubdomainKey; + const TSubDomainKey SubdomainKey; + const TEvHive::TEvUpdateDomain::TPtr Request; + TSideEffects SideEffects; public: - TTxUpdateDomain(TSubDomainKey subdomainKey, THive* hive) + TTxUpdateDomain(TSubDomainKey subdomainKey, TEvHive::TEvUpdateDomain::TPtr request, THive* hive) : TBase(hive) , SubdomainKey(subdomainKey) + , Request(std::move(request)) {} TTxType GetTxType() const override { return NHive::TXTYPE_UPDATE_DOMAIN; } bool Execute(TTransactionContext& txc, const TActorContext&) override { + SideEffects.Reset(Self->SelfId()); + BLOG_D("THive::TTxUpdateDomain(" << SubdomainKey << ")::Execute"); - TDomainInfo* domain = Self->FindDomain(SubdomainKey); - if (domain != nullptr) { - NIceDb::TNiceDb db(txc.DB); + const TDomainInfo* domain = Self->FindDomain(SubdomainKey); + if (domain == nullptr) { + BLOG_W("THive::TTxUpdateDomain(" << SubdomainKey << ")::Execute - unknown subdomain"); + return true; + } + + NIceDb::TNiceDb db(txc.DB); + db.Table() + .Key(SubdomainKey.first, SubdomainKey.second) + .Update(domain->Path) + .Update(domain->HiveId); + if (domain->ServerlessComputeResourcesMode) { + db.Table() + .Key(SubdomainKey.first, SubdomainKey.second) + .Update(*domain->ServerlessComputeResourcesMode); + } else { db.Table() - .Key(SubdomainKey.first, SubdomainKey.second) - .Update(domain->Path, domain->HiveId); + .Key(SubdomainKey.first, SubdomainKey.second) + .UpdateToNull(); + } + + if (Request) { + auto response = std::make_unique(); + response->Record.SetTxId(Request->Get()->Record.GetTxId()); + response->Record.SetOrigin(Self->TabletID()); + SideEffects.Send(Request->Sender, response.release(), 0, Request->Cookie); } return true; } - void Complete(const TActorContext&) override { + void Complete(const TActorContext& ctx) override { BLOG_D("THive::TTxUpdateDomain(" << SubdomainKey << ")::Complete"); + SideEffects.Complete(ctx); } }; -ITransaction* THive::CreateUpdateDomain(TSubDomainKey subdomainKey) { - return new TTxUpdateDomain(subdomainKey, this); +ITransaction* THive::CreateUpdateDomain(TSubDomainKey subdomainKey, TEvHive::TEvUpdateDomain::TPtr event) { + return new TTxUpdateDomain(subdomainKey, std::move(event), this); } -} -} +} // NHive +} // NKikimr diff --git a/ydb/core/mind/hive/ya.make b/ydb/core/mind/hive/ya.make index cef0b4a5161d..57cc97076816 100644 --- a/ydb/core/mind/hive/ya.make +++ b/ydb/core/mind/hive/ya.make @@ -5,6 +5,7 @@ SRCS( balancer.h boot_queue.cpp boot_queue.h + domain_info.cpp domain_info.h drain.cpp fill.cpp diff --git a/ydb/core/protos/counters_schemeshard.proto b/ydb/core/protos/counters_schemeshard.proto index ffb53502d2e8..ca2a07a1d508 100644 --- a/ydb/core/protos/counters_schemeshard.proto +++ b/ydb/core/protos/counters_schemeshard.proto @@ -535,4 +535,5 @@ enum ETxTypes { TXTYPE_PERSQUEUE_PROPOSE_RESULT = 83 [(TxTypeOpts) = {Name: "TxPersQueueProposeResult"}]; TXTYPE_PERSQUEUE_PROPOSE_ATTACH_RESULT = 84 [(TxTypeOpts) = {Name: "TxProposeTransactionAttachResult"}]; + TXTYPE_UPDATE_DOMAIN_REPLY = 85 [(TxTypeOpts) = {Name: "TxUpdateDomainReply"}]; } diff --git a/ydb/core/protos/hive.proto b/ydb/core/protos/hive.proto index 11e1327e650b..575e0154d4cd 100644 --- a/ydb/core/protos/hive.proto +++ b/ydb/core/protos/hive.proto @@ -556,3 +556,13 @@ message TEvUpdateTabletsObjectReply { optional uint64 TxPartId = 3; } +message TEvUpdateDomain { + optional NKikimrSubDomains.TDomainKey DomainKey = 1; + optional NKikimrSubDomains.EServerlessComputeResourcesMode ServerlessComputeResourcesMode = 2; + optional uint64 TxId = 3; +} + +message TEvUpdateDomainReply { + optional fixed64 Origin = 1; + optional uint64 TxId = 2; +} diff --git a/ydb/core/testlib/tablet_helpers.cpp b/ydb/core/testlib/tablet_helpers.cpp index c43138f127ac..5d62205c0c6f 100644 --- a/ydb/core/testlib/tablet_helpers.cpp +++ b/ydb/core/testlib/tablet_helpers.cpp @@ -1148,6 +1148,8 @@ namespace NKikimr { HFunc(TEvHive::TEvInitiateTabletExternalBoot, Handle); HFunc(TEvHive::TEvUpdateTabletsObject, Handle); HFunc(TEvFakeHive::TEvSubscribeToTabletDeletion, Handle); + HFunc(TEvHive::TEvUpdateDomain, Handle); + HFunc(TEvFakeHive::TEvRequestDomainInfo, Handle); HFunc(TEvents::TEvPoisonPill, Handle); } } @@ -1440,6 +1442,25 @@ namespace NKikimr { ctx.Send(ev->Sender, response.release(), 0, ev->Cookie); } + void Handle(TEvHive::TEvUpdateDomain::TPtr &ev, const TActorContext &ctx) { + LOG_INFO_S(ctx, NKikimrServices::HIVE, "[" << TabletID() << "] TEvUpdateDomain, msg: " << ev->Get()->Record.ShortDebugString()); + + const TSubDomainKey subdomainKey(ev->Get()->Record.GetDomainKey()); + NHive::TDomainInfo& domainInfo = State->Domains[subdomainKey]; + domainInfo.ServerlessComputeResourcesMode = ev->Get()->Record.GetServerlessComputeResourcesMode(); + + auto response = std::make_unique(); + response->Record.SetTxId(ev->Get()->Record.GetTxId()); + response->Record.SetOrigin(TabletID()); + ctx.Send(ev->Sender, response.release(), 0, ev->Cookie); + } + + void Handle(TEvFakeHive::TEvRequestDomainInfo::TPtr &ev, const TActorContext &ctx) { + LOG_INFO_S(ctx, NKikimrServices::HIVE, "[" << TabletID() << "] TEvRequestDomainInfo, " << ev->Get()->DomainKey); + auto response = std::make_unique(State->Domains[ev->Get()->DomainKey]); + ctx.Send(ev->Sender, response.release()); + } + void Handle(TEvFakeHive::TEvSubscribeToTabletDeletion::TPtr &ev, const TActorContext &ctx) { LOG_INFO_S(ctx, NKikimrServices::HIVE, "[" << TabletID() << "] TEvSubscribeToTabletDeletion, " << ev->Get()->TabletId); diff --git a/ydb/core/testlib/tablet_helpers.h b/ydb/core/testlib/tablet_helpers.h index 9e3616148e8d..099d0bd74135 100644 --- a/ydb/core/testlib/tablet_helpers.h +++ b/ydb/core/testlib/tablet_helpers.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -89,7 +90,9 @@ namespace NKikimr { struct TEvFakeHive { enum EEv { EvSubscribeToTabletDeletion = TEvHive::EvEnd + 1, - EvNotifyTabletDeleted + EvNotifyTabletDeleted, + EvRequestDomainInfo, + EvRequestDomainInfoReply }; struct TEvSubscribeToTabletDeletion : public TEventLocal { @@ -107,6 +110,23 @@ namespace NKikimr { : TabletId(tabletId) {} }; + + struct TEvRequestDomainInfo : public TEventLocal { + TSubDomainKey DomainKey; + + explicit TEvRequestDomainInfo(TSubDomainKey domainKey) + : DomainKey(domainKey) + {} + }; + + struct TEvRequestDomainInfoReply: public TEventLocal { + NHive::TDomainInfo DomainInfo; + + explicit TEvRequestDomainInfoReply(const NHive::TDomainInfo& domainInfo) + : DomainInfo(domainInfo) + {} + }; + }; struct TFakeHiveTabletInfo { @@ -134,7 +154,7 @@ namespace NKikimr { TMap TabletIdToHive; ui64 NextTabletId; ui64 NextHiveNextTabletId; - + TMap Domains; static constexpr ui64 TABLETS_PER_CHILD_HIVE = 1000000; // amount of tablet ids we reserve for child hive typedef TIntrusivePtr TPtr; diff --git a/ydb/core/tx/schemeshard/schemeshard__init.cpp b/ydb/core/tx/schemeshard/schemeshard__init.cpp index 10ec3bdf51d1..e1f75bf1b4e6 100644 --- a/ydb/core/tx/schemeshard/schemeshard__init.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__init.cpp @@ -3313,6 +3313,7 @@ struct TSchemeShard::TTxInit : public TTransactionBase { txState.SourcePathId = TPathId(txInFlightRowset.GetValueOrDefault(), txInFlightRowset.GetValueOrDefault()); txState.NeedUpdateObject = txInFlightRowset.GetValueOrDefault(false); + txState.NeedSyncHive = txInFlightRowset.GetValueOrDefault(false); if (txState.TxType == TTxState::TxCopyTable && txState.SourcePathId) { Y_ABORT_UNLESS(txState.SourcePathId); diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_alter_extsubdomain.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_alter_extsubdomain.cpp index 5a4f9c88152c..ef8c34d80c3c 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_alter_extsubdomain.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_alter_extsubdomain.cpp @@ -9,7 +9,7 @@ #define LOG_D(stream) LOG_DEBUG_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[" << context.SS->TabletID() << "] " << stream) #define LOG_I(stream) LOG_INFO_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[" << context.SS->TabletID() << "] " << stream) #define LOG_N(stream) LOG_NOTICE_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[" << context.SS->TabletID() << "] " << stream) - +#define LOG_E(stream) LOG_ERROR_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "[" << context.SS->TabletID() << "] " << stream) namespace NKikimr::NSchemeShard { @@ -40,6 +40,7 @@ struct TParamsDelta { uint8_t AddGraphShard = 0; bool SharedTxSupportAdded = false; TVector StoragePoolsAdded; + bool ServerlessComputeResourcesModeChanged = false; }; std::tuple @@ -263,6 +264,7 @@ VerifyParams(TParamsDelta* delta, const TPathId pathId, const TSubDomainInfo::TP } // ServerlessComputeResourcesMode check + bool serverlessComputeResourcesModeChanged = false; if (input.HasServerlessComputeResourcesMode()) { switch (input.GetServerlessComputeResourcesMode()) { case EServerlessComputeResourcesMode::SERVERLESS_COMPUTE_RESOURCES_MODE_UNSPECIFIED: @@ -278,6 +280,8 @@ VerifyParams(TParamsDelta* delta, const TPathId pathId, const TSubDomainInfo::TP if (!isServerless) { return paramError("ServerlessComputeResourcesMode can be changed only for serverless"); } + + serverlessComputeResourcesModeChanged = current->GetServerlessComputeResourcesMode() != input.GetServerlessComputeResourcesMode(); } delta->CoordinatorsAdded = coordinatorsAdded; @@ -290,6 +294,7 @@ VerifyParams(TParamsDelta* delta, const TPathId pathId, const TSubDomainInfo::TP delta->AddGraphShard = addGraphShard; delta->SharedTxSupportAdded = sharedTxSupportAdded; delta->StoragePoolsAdded = std::move(storagePoolsAdded); + delta->ServerlessComputeResourcesModeChanged = serverlessComputeResourcesModeChanged; return {NKikimrScheme::EStatus::StatusAccepted, {}}; } @@ -344,7 +349,7 @@ class TCreateHive: public TSubOperationState { TOperationId OperationId; TString DebugHint() const override { - return TStringBuilder() << "TCreateHive, operationId# " << OperationId << ", "; + return TStringBuilder() << "TCreateHive, operationId " << OperationId << ", "; } public: @@ -722,6 +727,73 @@ class TWaitHiveCreated: public TSubOperationState { } }; +class TSyncHive: public TSubOperationState { +private: + const TOperationId OperationId; + + TString DebugHint() const override { + return TStringBuilder() << "TSyncHive, operationId " << OperationId << ", "; + } + +public: + TSyncHive(TOperationId id) + : OperationId(id) + { + IgnoreMessages(DebugHint(), { + TEvPrivate::TEvOperationPlan::EventType + }); + } + + bool ProgressState(TOperationContext& context) override { + const TTxState* txState = context.SS->FindTx(OperationId); + Y_ABORT_UNLESS(txState); + + LOG_I(DebugHint() << "ProgressState, NeedSyncHive: " << txState->NeedSyncHive); + + if (txState->NeedSyncHive) { + const TPathId pathId = txState->TargetPathId; + Y_ABORT_UNLESS(context.SS->SubDomains.contains(pathId)); + TSubDomainInfo::TConstPtr subDomain = context.SS->SubDomains.at(pathId); + + const TTabletId hiveToSync = context.SS->ResolveHive(pathId, context.Ctx); + + auto event = MakeHolder(); + event->Record.SetTxId(ui64(OperationId.GetTxId())); + event->Record.MutableDomainKey()->SetSchemeShard(pathId.OwnerId); + event->Record.MutableDomainKey()->SetPathId(pathId.LocalPathId); + const auto& serverlessComputeResourcesMode = subDomain->GetServerlessComputeResourcesMode(); + if (serverlessComputeResourcesMode) { + event->Record.SetServerlessComputeResourcesMode(*serverlessComputeResourcesMode); + } + + LOG_D(DebugHint() << "ProgressState" + << ", Syncing hive: " << hiveToSync + << ", msg: {" << event->Record.ShortDebugString() << "}"); + + context.OnComplete.BindMsgToPipe(OperationId, hiveToSync, pathId, event.Release()); + return false; + } else { + NIceDb::TNiceDb db(context.GetDB()); + context.SS->ChangeTxState(db, OperationId, TTxState::Done); + return true; + } + } + + bool HandleReply(TEvHive::TEvUpdateDomainReply::TPtr& ev, TOperationContext& context) override { + const TTabletId hive = TTabletId(ev->Get()->Record.GetOrigin()); + + LOG_I(DebugHint() << "HandleReply TEvUpdateDomainReply" + << ", from hive: " << hive); + + const TTxState* txState = context.SS->FindTx(OperationId); + Y_ABORT_UNLESS(txState); + context.OnComplete.UnbindMsgFromPipe(OperationId, hive, txState->TargetPathId); + NIceDb::TNiceDb db(context.GetDB()); + context.SS->ChangeTxState(db, OperationId, TTxState::Done); + return true; + } +}; + class TAlterExtSubDomain: public TSubOperation { static TTxState::ETxState NextState() { return TTxState::Waiting; @@ -736,6 +808,8 @@ class TAlterExtSubDomain: public TSubOperation { case TTxState::ConfigureParts: return TTxState::Propose; case TTxState::Propose: + return TTxState::SyncHive; + case TTxState::SyncHive: return TTxState::Done; default: return TTxState::Invalid; @@ -752,7 +826,9 @@ class TAlterExtSubDomain: public TSubOperation { case TTxState::ConfigureParts: return MakeHolder(OperationId); case TTxState::Propose: - return MakeHolder(OperationId); + return MakeHolder(OperationId, TTxState::SyncHive); + case TTxState::SyncHive: + return MakeHolder(OperationId); case TTxState::Done: return MakeHolder(OperationId); default: @@ -920,6 +996,7 @@ class TAlterExtSubDomain: public TSubOperation { { // txState.State = TTxState::CreateParts; txState.State = TTxState::Waiting; + txState.NeedSyncHive = delta.ServerlessComputeResourcesModeChanged; context.DbChanges.PersistTxState(OperationId); } diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_common_subdomain.h b/ydb/core/tx/schemeshard/schemeshard__operation_common_subdomain.h index 1048d07c1040..c4caed85e7dc 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_common_subdomain.h +++ b/ydb/core/tx/schemeshard/schemeshard__operation_common_subdomain.h @@ -280,7 +280,8 @@ class TConfigureParts: public TSubOperationState { class TPropose: public TSubOperationState { private: - TOperationId OperationId; + const TOperationId OperationId; + const TTxState::ETxState NextState; TString DebugHint() const override { return TStringBuilder() @@ -289,8 +290,9 @@ class TPropose: public TSubOperationState { } public: - TPropose(TOperationId id) + TPropose(TOperationId id, TTxState::ETxState nextState = TTxState::Done) : OperationId(id) + , NextState(nextState) { IgnoreMessages(DebugHint(), { TEvHive::TEvCreateTabletReply::EventType, @@ -356,7 +358,7 @@ class TPropose: public TSubOperationState { context.SS->ClearDescribePathCaches(path); context.OnComplete.PublishToSchemeBoard(OperationId, pathId); - context.SS->ChangeTxState(db, OperationId, TTxState::Done); + context.SS->ChangeTxState(db, OperationId, NextState); LOG_DEBUG_S(context.Ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "NSubDomainState::TPropose HandleReply TEvOperationPlan" diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_part.h b/ydb/core/tx/schemeshard/schemeshard__operation_part.h index 3e2fe8895bb6..4c592f579028 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_part.h +++ b/ydb/core/tx/schemeshard/schemeshard__operation_part.h @@ -31,6 +31,7 @@ action(TEvHive::TEvDeleteTabletReply, NSchemeShard::TXTYPE_FREE_TABLET_RESULT) \ action(TEvHive::TEvDeleteOwnerTabletsReply, NSchemeShard::TXTYPE_FREE_OWNER_TABLETS_RESULT)\ action(TEvHive::TEvUpdateTabletsObjectReply, NSchemeShard::TXTYPE_CREATE_TABLET_REPLY) \ + action(TEvHive::TEvUpdateDomainReply, NSchemeShard::TXTYPE_UPDATE_DOMAIN_REPLY) \ \ action(TEvDataShard::TEvProposeTransactionResult, NSchemeShard::TXTYPE_DATASHARD_PROPOSE_RESULT) \ action(TEvDataShard::TEvSchemaChanged, NSchemeShard::TXTYPE_DATASHARD_SCHEMA_CHANGED) \ diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp index 489a0279f16c..afee6bf575a6 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp @@ -2099,7 +2099,7 @@ void TSchemeShard::PersistSubDomainAuditSettingsAlter(NIceDb::TNiceDb& db, const template void PersistSubDomainServerlessComputeResourcesModeImpl(NIceDb::TNiceDb& db, const TPathId& pathId, - const TSubDomainInfo::TMaybeServerlessComputeResourcesMode& value) { + const TMaybeServerlessComputeResourcesMode& value) { using Field = typename Table::ServerlessComputeResourcesMode; if (value) { db.Table().Key(pathId.LocalPathId).Update(NIceDb::TUpdate(*value)); @@ -2228,7 +2228,8 @@ void TSchemeShard::PersistTxState(NIceDb::TNiceDb& db, const TOperationId opId) NIceDb::TUpdate(txState.BuildIndexId), NIceDb::TUpdate(txState.SourcePathId.LocalPathId), NIceDb::TUpdate(txState.SourcePathId.OwnerId), - NIceDb::TUpdate(txState.NeedUpdateObject) + NIceDb::TUpdate(txState.NeedUpdateObject), + NIceDb::TUpdate(txState.NeedSyncHive) ); for (const auto& shardOp : txState.Shards) { @@ -4404,6 +4405,7 @@ void TSchemeShard::StateWork(STFUNC_SIG) { HFuncTraced(TEvHive::TEvDeleteTabletReply, Handle); HFuncTraced(TEvHive::TEvDeleteOwnerTabletsReply, Handle); HFuncTraced(TEvHive::TEvUpdateTabletsObjectReply, Handle); + HFuncTraced(TEvHive::TEvUpdateDomainReply, Handle); HFuncTraced(TEvDataShard::TEvProposeTransactionResult, Handle); HFuncTraced(TEvDataShard::TEvSchemaChanged, Handle); @@ -5436,6 +5438,37 @@ void TSchemeShard::Handle(TEvHive::TEvUpdateTabletsObjectReply::TPtr &ev, const Execute(CreateTxOperationReply(TOperationId(txId, partId), ev), ctx); } +void TSchemeShard::Handle(TEvHive::TEvUpdateDomainReply::TPtr &ev, const TActorContext &ctx) { + const auto& record = ev->Get()->Record; + + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Update domain reply" + << ", message: " << record.ShortDebugString() + << ", at schemeshard: " << TabletID()); + + const auto txId = TTxId(record.GetTxId()); + if (!Operations.contains(txId)) { + LOG_WARN_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Got TEvUpdateDomainReply" + << " for unknown txId " << txId + << " at schemeshard " << TabletID()); + return; + } + + const auto tabletId = TTabletId(record.GetOrigin()); + const auto partId = Operations.at(txId)->FindRelatedPartByTabletId(tabletId, ctx); + if (partId == InvalidSubTxId) { + LOG_WARN_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + "Got TEvHive::TEvUpdateDomainReply but partId is unknown" + << ", for txId: " << txId + << ", tabletId: " << tabletId + << ", at schemeshard: " << TabletID()); + return; + } + + Execute(CreateTxOperationReply(TOperationId(txId, partId), ev), ctx); +} + void TSchemeShard::Handle(TEvPersQueue::TEvDropTabletReply::TPtr &ev, const TActorContext &ctx) { const auto txId = TTxId(ev->Get()->Record.GetTxId()); diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.h b/ydb/core/tx/schemeshard/schemeshard_impl.h index 0bf75f3117d2..1ff3af4394d1 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.h +++ b/ydb/core/tx/schemeshard/schemeshard_impl.h @@ -956,6 +956,7 @@ class TSchemeShard void Handle(TEvPrivate::TEvSubscribeToShardDeletion::TPtr &ev, const TActorContext &ctx); void Handle(TEvHive::TEvDeleteOwnerTabletsReply::TPtr &ev, const TActorContext &ctx); void Handle(TEvHive::TEvUpdateTabletsObjectReply::TPtr &ev, const TActorContext &ctx); + void Handle(TEvHive::TEvUpdateDomainReply::TPtr &ev, const TActorContext &ctx); void Handle(TEvPersQueue::TEvDropTabletReply::TPtr &ev, const TActorContext &ctx); void Handle(TEvColumnShard::TEvProposeTransactionResult::TPtr& ev, const TActorContext& ctx); void Handle(NBackgroundTasks::TEvAddTaskResult::TPtr& ev, const TActorContext& ctx); diff --git a/ydb/core/tx/schemeshard/schemeshard_info_types.h b/ydb/core/tx/schemeshard/schemeshard_info_types.h index e7cd70eddaf9..501b8c68531d 100644 --- a/ydb/core/tx/schemeshard/schemeshard_info_types.h +++ b/ydb/core/tx/schemeshard/schemeshard_info_types.h @@ -2148,8 +2148,6 @@ struct TSubDomainInfo: TSimpleRefCount { void ApplyAuditSettings(const TMaybeAuditSettings& diff); - using TMaybeServerlessComputeResourcesMode = TMaybe; - const TMaybeServerlessComputeResourcesMode& GetServerlessComputeResourcesMode() const { return ServerlessComputeResourcesMode; } diff --git a/ydb/core/tx/schemeshard/schemeshard_schema.h b/ydb/core/tx/schemeshard/schemeshard_schema.h index 02ac5b9ee233..2aade717ba0c 100644 --- a/ydb/core/tx/schemeshard/schemeshard_schema.h +++ b/ydb/core/tx/schemeshard/schemeshard_schema.h @@ -1060,6 +1060,7 @@ struct Schema : NIceDb::Schema { struct SourceLocalPathId : Column<14, NScheme::NTypeIds::Uint64> { using Type = TLocalPathId; static constexpr Type Default = InvalidLocalPathId; }; struct PlanStep : Column<15, NScheme::NTypeIds::Uint64> { using Type = TStepId; }; struct NeedUpdateObject : Column<16, NScheme::NTypeIds::Bool> {}; + struct NeedSyncHive : Column<17, NScheme::NTypeIds::Bool> {}; using TKey = TableKey; using TColumns = TableColumns< @@ -1078,7 +1079,8 @@ struct Schema : NIceDb::Schema { SourceOwnerId, SourceLocalPathId, PlanStep, - NeedUpdateObject + NeedUpdateObject, + NeedSyncHive >; }; diff --git a/ydb/core/tx/schemeshard/schemeshard_tx_infly.h b/ydb/core/tx/schemeshard/schemeshard_tx_infly.h index b58b7cfde6d0..849f91a9dee0 100644 --- a/ydb/core/tx/schemeshard/schemeshard_tx_infly.h +++ b/ydb/core/tx/schemeshard/schemeshard_tx_infly.h @@ -192,6 +192,7 @@ struct TTxState { item(DeletePrivateShards, 135, "") \ item(WaitShadowPathPublication, 136, "") \ item(DeletePathBarrier, 137, "") \ + item(SyncHive, 138, "") \ item(Done, 240, "") \ item(Aborted, 250, "") @@ -259,6 +260,7 @@ struct TTxState { // persist - TxShards: TVector Shards; // shards + operations on them bool NeedUpdateObject = false; + bool NeedSyncHive = false; // not persist: THashSet ShardsInProgress; // indexes of datashards or pqs that operation waits for THashMap> SchemeChangeNotificationReceived; diff --git a/ydb/core/tx/schemeshard/ut_helpers/test_env.cpp b/ydb/core/tx/schemeshard/ut_helpers/test_env.cpp index 7bf426409458..dbc73641066b 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/test_env.cpp +++ b/ydb/core/tx/schemeshard/ut_helpers/test_env.cpp @@ -823,6 +823,22 @@ std::function(subdomainKey); + ForwardToTablet(runtime, hive, sender, ev.Release()); + + const auto event = runtime.GrabEdgeEvent(sender); + UNIT_ASSERT(event); + UNIT_ASSERT_VALUES_EQUAL(event->Get()->DomainInfo.ServerlessComputeResourcesMode, serverlessComputeResourcesMode); +} + TEvSchemeShard::TEvInitRootShardResult::EStatus NSchemeShardUT_Private::TTestEnv::InitRoot(NActors::TTestActorRuntime &runtime, ui64 schemeRoot, const NActors::TActorId &sender, const TString& domainName, const TDomainsInfo::TDomain::TStoragePoolKinds& StoragePoolTypes, const TString& owner) { auto ev = new TEvSchemeShard::TEvInitRootShard(sender, 32, domainName); for (const auto& [kind, pool] : StoragePoolTypes) { diff --git a/ydb/core/tx/schemeshard/ut_helpers/test_env.h b/ydb/core/tx/schemeshard/ut_helpers/test_env.h index 745c0dfef648..50c33be744f2 100644 --- a/ydb/core/tx/schemeshard/ut_helpers/test_env.h +++ b/ydb/core/tx/schemeshard/ut_helpers/test_env.h @@ -114,6 +114,10 @@ namespace NSchemeShardUT_Private { void SimulateSleep(TTestActorRuntime& runtime, TDuration duration); + void TestServerlessComputeResourcesModeInHive(TTestActorRuntime& runtime, const TString& path, + NKikimrSubDomains::EServerlessComputeResourcesMode serverlessComputeResourcesMode, + ui64 hive = TTestTxConfig::Hive); + TEvSchemeShard::TEvInitRootShardResult::EStatus InitRoot(TTestActorRuntime& runtime, ui64 schemeRoot, const TActorId& sender, const TString& domainName, const TDomainsInfo::TDomain::TStoragePoolKinds& StoragePoolTypes = {}, const TString& owner = {}); void InitRootStoragePools(TTestActorRuntime& runtime, ui64 schemeRoot, const TActorId& sender, ui64 domainUid); diff --git a/ydb/core/tx/schemeshard/ut_serverless/ut_serverless.cpp b/ydb/core/tx/schemeshard/ut_serverless/ut_serverless.cpp index 2c9827bfccc4..56d7d26a2e47 100644 --- a/ydb/core/tx/schemeshard/ut_serverless/ut_serverless.cpp +++ b/ydb/core/tx/schemeshard/ut_serverless/ut_serverless.cpp @@ -284,6 +284,12 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLess) { ); env.TestWaitNotification(runtime, txId); + ui64 sharedHive = 0; + TestDescribeResult(DescribePath(runtime, "/MyRoot/SharedDB"), + {NLs::PathExist, + NLs::IsExternalSubDomain("SharedDB"), + NLs::ExtractDomainHive(&sharedHive)}); + TString createData = Sprintf( R"( ResourcesDomainKey { @@ -344,6 +350,7 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLess) { {NLs::ServerlessComputeResourcesMode(serverlessComputeResourcesMode)}); TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLess0"), {NLs::ServerlessComputeResourcesMode(serverlessComputeResourcesMode)}); + env.TestServerlessComputeResourcesModeInHive(runtime, "/MyRoot/ServerLess0", serverlessComputeResourcesMode, sharedHive); }; checkServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED); diff --git a/ydb/core/tx/schemeshard/ut_serverless_reboots/ut_serverless_reboots.cpp b/ydb/core/tx/schemeshard/ut_serverless_reboots/ut_serverless_reboots.cpp index f02e90bb1eaa..ab01c036c44a 100644 --- a/ydb/core/tx/schemeshard/ut_serverless_reboots/ut_serverless_reboots.cpp +++ b/ydb/core/tx/schemeshard/ut_serverless_reboots/ut_serverless_reboots.cpp @@ -41,6 +41,8 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLessReboots) { Y_UNIT_TEST(TestServerlessComputeResourcesModeWithReboots) { TTestWithReboots t; t.Run([&](TTestActorRuntime& runtime, bool& activeZone) { + ui64 sharedHive = 0; + ui64 tenantSchemeShard = 0; { TInactiveZone inactive(activeZone); TestCreateExtSubDomain(runtime, ++t.TxId, "/MyRoot", @@ -69,6 +71,9 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLessReboots) { ); t.TestEnv->TestWaitNotification(runtime, t.TxId); + TestDescribeResult(DescribePath(runtime, "/MyRoot/SharedDB"), + {NLs::ExtractDomainHive(&sharedHive)}); + TString createData = Sprintf( R"( ResourcesDomainKey { @@ -99,7 +104,6 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLessReboots) { ); t.TestEnv->TestWaitNotification(runtime, t.TxId); - ui64 tenantSchemeShard = 0; TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLess0"), {NLs::PathExist, NLs::IsExternalSubDomain("ServerLess0"), @@ -120,10 +124,10 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLessReboots) { { TInactiveZone inactive(activeZone); - ui64 tenantSchemeShard = 0; TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLess0"), - {NLs::ServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED), - NLs::ExtractTenantSchemeshard(&tenantSchemeShard)}); + {NLs::ServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED)}); + t.TestEnv->TestServerlessComputeResourcesModeInHive(runtime, "/MyRoot/ServerLess0", + SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED, sharedHive); TestTenantSchemeShardSync(t, runtime, tenantSchemeShard, "/MyRoot/ServerLess0", ServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_DEDICATED)); } @@ -138,10 +142,10 @@ Y_UNIT_TEST_SUITE(TSchemeShardServerLessReboots) { { TInactiveZone inactive(activeZone); - ui64 tenantSchemeShard = 0; TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLess0"), - {NLs::ServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_SHARED), - NLs::ExtractTenantSchemeshard(&tenantSchemeShard)}); + {NLs::ServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_SHARED)}); + t.TestEnv->TestServerlessComputeResourcesModeInHive(runtime, "/MyRoot/ServerLess0", + SERVERLESS_COMPUTE_RESOURCES_MODE_SHARED, sharedHive); TestTenantSchemeShardSync(t, runtime, tenantSchemeShard, "/MyRoot/ServerLess0", ServerlessComputeResourcesMode(SERVERLESS_COMPUTE_RESOURCES_MODE_SHARED)); } diff --git a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_hive_/flat_hive.schema b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_hive_/flat_hive.schema index 3d579d78f8f3..938e0d6b9dbb 100644 --- a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_hive_/flat_hive.schema +++ b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_hive_/flat_hive.schema @@ -31,6 +31,11 @@ "ColumnId": 5, "ColumnName": "HiveId", "ColumnType": "Uint64" + }, + { + "ColumnId": 6, + "ColumnName": "ServerlessComputeResourcesMode", + "ColumnType": "Uint32" } ], "ColumnsDropped": [], @@ -41,7 +46,8 @@ 2, 3, 4, - 5 + 5, + 6 ], "RoomID": 0, "Codec": 0, diff --git a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema index d6096af10659..05a8b981e54f 100644 --- a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema +++ b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_schemeshard_/flat_schemeshard.schema @@ -2606,6 +2606,11 @@ 2 ], "ColumnsAdded": [ + { + "ColumnId": 17, + "ColumnName": "NeedSyncHive", + "ColumnType": "Bool" + }, { "ColumnId": 1, "ColumnName": "TxId", @@ -2691,6 +2696,7 @@ "ColumnFamilies": { "0": { "Columns": [ + 17, 1, 2, 3,