diff --git a/ydb/core/mind/hive/hive_ut.cpp b/ydb/core/mind/hive/hive_ut.cpp index 1d89e73632ee..94da9875c16a 100644 --- a/ydb/core/mind/hive/hive_ut.cpp +++ b/ydb/core/mind/hive/hive_ut.cpp @@ -4776,6 +4776,84 @@ Y_UNIT_TEST_SUITE(THiveTest) { } } + Y_UNIT_TEST(TestHiveBalancerUselessNeighbourMoves) { + // 7 tablets of same object, 3 nodes, one of nodes cannot run them + // distribution should be (4, 3, 0) + // this should trigger balancer, but not lead to any moves + static constexpr ui64 NUM_NODES = 3; + static constexpr ui64 NUM_TABLETS = 7; + TTestBasicRuntime runtime(NUM_NODES, false); + Setup(runtime, true, 1, [](TAppPrepare& app) { + app.HiveConfig.SetTabletKickCooldownPeriod(0); + app.HiveConfig.SetResourceChangeReactionPeriod(0); + app.HiveConfig.SetMetricsWindowSize(1); + }); + const int nodeBase = runtime.GetNodeId(0); + TActorId senderA = runtime.AllocateEdgeActor(); + const ui64 hiveTablet = MakeDefaultHiveID(); + const ui64 testerTablet = MakeTabletID(false, 1); + + auto getDistribution = [hiveTablet, nodeBase, senderA, &runtime]() -> std::array, NUM_NODES> { + std::array, NUM_NODES> nodeTablets = {}; + { + runtime.SendToPipe(hiveTablet, senderA, new TEvHive::TEvRequestHiveInfo()); + TAutoPtr handle; + TEvHive::TEvResponseHiveInfo* response = runtime.GrabEdgeEventRethrow(handle); + for (const NKikimrHive::TTabletInfo& tablet : response->Record.GetTablets()) { + UNIT_ASSERT_C(((int)tablet.GetNodeID() - nodeBase >= 0) && (tablet.GetNodeID() - nodeBase < NUM_NODES), + "nodeId# " << tablet.GetNodeID() << " nodeBase# " << nodeBase); + nodeTablets[tablet.GetNodeID() - nodeBase].push_back(tablet.GetTabletID()); + } + } + return nodeTablets; + }; + + CreateTestBootstrapper(runtime, CreateTestTabletInfo(hiveTablet, TTabletTypes::Hive), &CreateDefaultHive); + + // wait for creation of nodes + { + TDispatchOptions options; + options.FinalEvents.emplace_back(TEvLocal::EvStatus, NUM_NODES); + runtime.DispatchEvents(options); + } + + TTabletTypes::EType tabletType = TTabletTypes::Dummy; + std::vector tablets; + tablets.reserve(NUM_TABLETS); + for (size_t i = 0; i < NUM_TABLETS; ++i) { + THolder ev(new TEvHive::TEvCreateTablet(testerTablet, 100500 + i, tabletType, BINDED_CHANNELS)); + ev->Record.SetObjectId(1); + ev->Record.AddAllowedNodeIDs(nodeBase); + ev->Record.AddAllowedNodeIDs(nodeBase + 1); + ui64 tabletId = SendCreateTestTablet(runtime, hiveTablet, testerTablet, std::move(ev), 0, true); + MakeSureTabletIsUp(runtime, tabletId, 0); + tablets.push_back(tabletId); + } + + auto initialDistribution = getDistribution(); + + for (auto tablet : tablets) { + THolder metrics = MakeHolder(); + NKikimrHive::TTabletMetrics* metric = metrics->Record.AddTabletMetrics(); + metric->SetTabletID(tablet); + metric->MutableResourceUsage()->SetCPU(0); + metric->MutableResourceUsage()->SetMemory(0); + + runtime.SendToPipe(hiveTablet, senderA, metrics.Release()); + } + + { + TDispatchOptions options; + options.FinalEvents.emplace_back(NHive::TEvPrivate::EvBalancerOut); + runtime.DispatchEvents(options, TDuration::Seconds(10)); + } + + // Check that balancer moved no tablets + auto newDistribution = getDistribution(); + + UNIT_ASSERT_EQUAL(initialDistribution, newDistribution); + } + Y_UNIT_TEST(TestHiveBalancerWithImmovableTablets) { static constexpr ui64 TABLETS_PER_NODE = 10; TTestBasicRuntime runtime(3, false); diff --git a/ydb/core/mind/hive/node_info.h b/ydb/core/mind/hive/node_info.h index 961116babce5..afc23ad92318 100644 --- a/ydb/core/mind/hive/node_info.h +++ b/ydb/core/mind/hive/node_info.h @@ -132,7 +132,11 @@ struct TNodeInfo { ui32 GetTabletNeighboursCount(const TTabletInfo& tablet) const { auto it = TabletsOfObject.find(tablet.GetObjectId()); if (it != TabletsOfObject.end()) { - return it->second.size(); + auto count = it->second.size(); + if (tablet.IsAliveOnLocal(Local)) { + --count; + } + return count; } else { return 0; }