@@ -3961,6 +3961,7 @@ Y_UNIT_TEST_SUITE(THiveTest) {
39613961 // this value of MaxNodeUsageToKick is selected specifically to make test scenario work
39623962 // in link with number of tablets and values of network usage metrics used below
39633963 app.HiveConfig .SetMaxNodeUsageToKick (0.01 );
3964+ app.HiveConfig .SetNodeUsageRangeToKick (0 );
39643965 app.HiveConfig .SetEmergencyBalancerInflight (1 ); // to ensure fair distribution
39653966 });
39663967
@@ -4855,6 +4856,75 @@ Y_UNIT_TEST_SUITE(THiveTest) {
48554856 UNIT_ASSERT_VALUES_EQUAL (newDistribution[1 ].size (), TABLETS_PER_NODE - 1 );
48564857 }
48574858
4859+ Y_UNIT_TEST (TestHiveBalancerHighUsage) {
4860+ static constexpr ui64 NUM_NODES = 2 ;
4861+ TTestBasicRuntime runtime (2 , false );
4862+ Setup (runtime, true , 1 , [](TAppPrepare& app) {
4863+ app.HiveConfig .SetTabletKickCooldownPeriod (0 );
4864+ app.HiveConfig .SetResourceChangeReactionPeriod (0 );
4865+ });
4866+ const int nodeBase = runtime.GetNodeId (0 );
4867+ TActorId senderA = runtime.AllocateEdgeActor ();
4868+ const ui64 hiveTablet = MakeDefaultHiveID ();
4869+ const ui64 testerTablet = MakeTabletID (false , 1 );
4870+
4871+ auto getDistribution = [hiveTablet, nodeBase, senderA, &runtime]() -> std::array<std::vector<ui64>, NUM_NODES> {
4872+ std::array<std::vector<ui64>, NUM_NODES> nodeTablets = {};
4873+ {
4874+ runtime.SendToPipe (hiveTablet, senderA, new TEvHive::TEvRequestHiveInfo ());
4875+ TAutoPtr<IEventHandle> handle;
4876+ TEvHive::TEvResponseHiveInfo* response = runtime.GrabEdgeEventRethrow <TEvHive::TEvResponseHiveInfo>(handle);
4877+ for (const NKikimrHive::TTabletInfo& tablet : response->Record .GetTablets ()) {
4878+ UNIT_ASSERT_C (((int )tablet.GetNodeID () - nodeBase >= 0 ) && (tablet.GetNodeID () - nodeBase < NUM_NODES),
4879+ " nodeId# " << tablet.GetNodeID () << " nodeBase# " << nodeBase);
4880+ nodeTablets[tablet.GetNodeID () - nodeBase].push_back (tablet.GetTabletID ());
4881+ }
4882+ }
4883+ return nodeTablets;
4884+ };
4885+
4886+ CreateTestBootstrapper (runtime, CreateTestTabletInfo (hiveTablet, TTabletTypes::Hive), &CreateDefaultHive);
4887+
4888+ // wait for creation of nodes
4889+ {
4890+ TDispatchOptions options;
4891+ options.FinalEvents .emplace_back (TEvLocal::EvStatus, NUM_NODES);
4892+ runtime.DispatchEvents (options);
4893+ }
4894+
4895+ TTabletTypes::EType tabletType = TTabletTypes::Dummy;
4896+ for (size_t i = 0 ; i < 2 ; ++i) {
4897+ THolder<TEvHive::TEvCreateTablet> ev (new TEvHive::TEvCreateTablet (testerTablet, 100500 + i, tabletType, BINDED_CHANNELS));
4898+ ev->Record .SetObjectId (i);
4899+ ui64 tabletId = SendCreateTestTablet (runtime, hiveTablet, testerTablet, std::move (ev), 0 , true );
4900+ MakeSureTabletIsUp (runtime, tabletId, 0 );
4901+ }
4902+
4903+ auto initialDistribution = getDistribution ();
4904+
4905+ std::array<double , NUM_NODES> usages = {.89 , .91 };
4906+ for (ui32 i = 0 ; i < 2 ; ++i) {
4907+ for (ui32 node = 0 ; node < NUM_NODES; ++node) {
4908+ TActorId sender = runtime.AllocateEdgeActor (node);
4909+ THolder<TEvHive::TEvTabletMetrics> metrics = MakeHolder<TEvHive::TEvTabletMetrics>();
4910+ metrics->Record .SetTotalNodeUsage (usages[node]);
4911+
4912+ runtime.SendToPipe (hiveTablet, sender, metrics.Release (), node);
4913+ }
4914+ }
4915+
4916+ {
4917+ TDispatchOptions options;
4918+ options.FinalEvents .emplace_back (NHive::TEvPrivate::EvBalancerOut);
4919+ runtime.DispatchEvents (options, TDuration::Seconds (10 ));
4920+ }
4921+
4922+ // Check that balancer moved no tablets
4923+ auto newDistribution = getDistribution ();
4924+
4925+ UNIT_ASSERT_EQUAL (initialDistribution, newDistribution);
4926+ }
4927+
48584928 Y_UNIT_TEST (TestUpdateTabletsObjectUpdatesMetrics) {
48594929 TTestBasicRuntime runtime (1 , false );
48604930 Setup (runtime, true );
0 commit comments