@@ -375,6 +375,67 @@ Y_UNIT_TEST_SUITE(TSentinelBaseTests) {
375
375
GuardianDataCenterRatio (1 , {3 , 4 , 5 }, true );
376
376
}
377
377
378
+ void GuardianBadPDisksByNode (ui32 shelvesPerNode, ui32 disksPerShelf, ui32 badDisks) {
379
+ ui32 disksPerNode = shelvesPerNode * disksPerShelf;
380
+ ui32 maxFaultyDisksPerNode = disksPerShelf - 1 ;
381
+
382
+ auto [state, sentinelState] = MockCmsState (1 , 8 , 1 , disksPerNode, true , false );
383
+ TClusterMap all (sentinelState);
384
+
385
+ TGuardian changed (sentinelState, 100 , 100 , 100 , maxFaultyDisksPerNode);
386
+
387
+ const auto & nodes = state->ClusterInfo ->AllNodes ();
388
+
389
+ for (const auto & node : nodes) {
390
+ const ui64 nodeId = node.second ->NodeId ;
391
+
392
+ for (ui32 i = 0 ; i < disksPerNode; i++) {
393
+ const TPDiskID id (nodeId, i);
394
+
395
+ if (i < badDisks) {
396
+ all.AddPDisk (id, false );
397
+ changed.AddPDisk (id, false );
398
+ } else {
399
+ all.AddPDisk (id);
400
+ }
401
+ }
402
+ }
403
+
404
+ TString issues;
405
+ TClusterMap::TPDiskIgnoredMap disallowed;
406
+
407
+ auto allowed = changed.GetAllowedPDisks (all, issues, disallowed);
408
+
409
+ THashMap<ui64, ui32> allowedDisksByNode;
410
+ THashMap<ui64, ui32> disallowedDisksByNode;
411
+
412
+ for (const auto & id : allowed) {
413
+ allowedDisksByNode[id.NodeId ]++;
414
+ }
415
+
416
+ for (const auto & kv : disallowed) {
417
+ UNIT_ASSERT (kv.second == NKikimrCms::TPDiskInfo::TOO_MANY_FAULTY_PER_NODE);
418
+ disallowedDisksByNode[kv.first .NodeId ]++;
419
+ }
420
+
421
+ for (const auto & node : nodes) {
422
+ const ui64 nodeId = node.second ->NodeId ;
423
+ if (badDisks <= maxFaultyDisksPerNode) {
424
+ UNIT_ASSERT_VALUES_EQUAL (allowedDisksByNode[nodeId], badDisks);
425
+ UNIT_ASSERT_VALUES_EQUAL (disallowedDisksByNode[nodeId], 0 );
426
+ } else {
427
+ UNIT_ASSERT_VALUES_EQUAL (allowedDisksByNode[nodeId], 0 );
428
+ UNIT_ASSERT_VALUES_EQUAL (disallowedDisksByNode[nodeId], badDisks);
429
+ }
430
+ }
431
+ }
432
+
433
+ Y_UNIT_TEST (GuardianFaultyPDisks) {
434
+ for (ui32 i = 0 ; i < 56 ; i++) {
435
+ GuardianBadPDisksByNode (2 , 28 , i);
436
+ }
437
+ }
438
+
378
439
void GuardianRackRatio (ui16 numRacks, const TVector<ui16>& nodesPerRackVariants, ui16 numPDisks, bool anyRack) {
379
440
for (ui16 nodesPerRack : nodesPerRackVariants) {
380
441
auto [state, sentinelState] = MockCmsState (1 , numRacks, nodesPerRack, numPDisks, false , anyRack);
@@ -532,6 +593,107 @@ Y_UNIT_TEST_SUITE(TSentinelTests) {
532
593
}
533
594
}
534
595
596
+ Y_UNIT_TEST (PDiskFaultyGuard) {
597
+ ui32 nodes = 2 ;
598
+ ui32 disksPerShelf = 5 ;
599
+ ui32 disksPerNode = 2 * disksPerShelf;
600
+
601
+ for (auto wholeShelfFailure : {true , false }) {
602
+ NKikimrCms::TCmsConfig config;
603
+
604
+ config.MutableSentinelConfig ()->SetFaultyPDisksThresholdPerNode (disksPerShelf - 1 );
605
+ TTestEnv env (nodes, disksPerNode, config);
606
+ env.SetLogPriority (NKikimrServices::CMS, NLog::PRI_ERROR);
607
+
608
+ for (ui32 nodeIdx = 0 ; nodeIdx < nodes; ++nodeIdx) {
609
+ ui32 badDisks = wholeShelfFailure ? disksPerShelf : disksPerShelf / 2 ;
610
+
611
+ for (ui32 pdiskIdx = 0 ; pdiskIdx < badDisks - 1 ; ++pdiskIdx) {
612
+ const TPDiskID id = env.PDiskId (nodeIdx, pdiskIdx);
613
+
614
+ env.SetPDiskState ({id}, FaultyStates[0 ]);
615
+ }
616
+
617
+ // Next disk (last badDisk)
618
+ const TPDiskID id = env.PDiskId (nodeIdx, badDisks);
619
+
620
+ bool targetSeenFaulty = false ;
621
+
622
+ auto observerHolder = env.AddObserver <TEvBlobStorage::TEvControllerConfigRequest>([&](TEvBlobStorage::TEvControllerConfigRequest::TPtr& event) {
623
+ const auto & request = event->Get ()->Record ;
624
+ for (const auto & command : request.GetRequest ().GetCommand ()) {
625
+ if (command.HasUpdateDriveStatus ()) {
626
+ const auto & update = command.GetUpdateDriveStatus ();
627
+ ui32 nodeId = update.GetHostKey ().GetNodeId ();
628
+ ui32 pdiskId = update.GetPDiskId ();
629
+
630
+ if (id.NodeId == nodeId && id.DiskId == pdiskId) {
631
+ if (update.GetStatus () == NKikimrBlobStorage::EDriveStatus::FAULTY) {
632
+ targetSeenFaulty = true ;
633
+ }
634
+ }
635
+ }
636
+ }
637
+ });
638
+
639
+ for (ui32 i = 1 ; i < DefaultErrorStateLimit + 1 ; ++i) { // More than DefaultErrorStateLimit just to be sure
640
+ env.SetPDiskState ({id}, FaultyStates[0 ]);
641
+ }
642
+
643
+ env.SimulateSleep (TDuration::Minutes (5 ));
644
+
645
+ observerHolder.Remove ();
646
+
647
+ if (wholeShelfFailure) {
648
+ UNIT_ASSERT_C (!targetSeenFaulty, " Faulty state should not have been sent to BS controller because whole shelf failed" );
649
+ } else {
650
+ UNIT_ASSERT_C (targetSeenFaulty, " Faulty state should have been sent to BS controller" );
651
+ }
652
+ }
653
+ }
654
+ }
655
+
656
+ Y_UNIT_TEST (PDiskFaultyGuardWithForced) {
657
+ ui32 nodes = 2 ;
658
+ ui32 disksPerShelf = 5 ;
659
+ ui32 disksPerNode = 2 * disksPerShelf;
660
+
661
+ NKikimrCms::TCmsConfig config;
662
+
663
+ config.MutableSentinelConfig ()->SetFaultyPDisksThresholdPerNode (disksPerShelf - 1 );
664
+ TTestEnv env (nodes, disksPerNode, config);
665
+ env.SetLogPriority (NKikimrServices::CMS, NLog::PRI_ERROR);
666
+
667
+ std::map<ui32, std::set<ui32>> faultyDisks;
668
+
669
+ auto observerHolder = env.AddObserver <TEvBlobStorage::TEvControllerConfigRequest>([&](TEvBlobStorage::TEvControllerConfigRequest::TPtr& event) {
670
+ const auto & request = event->Get ()->Record ;
671
+ for (const auto & command : request.GetRequest ().GetCommand ()) {
672
+ if (command.HasUpdateDriveStatus ()) {
673
+ const auto & update = command.GetUpdateDriveStatus ();
674
+ ui32 nodeId = update.GetHostKey ().GetNodeId ();
675
+ ui32 pdiskId = update.GetPDiskId ();
676
+
677
+ faultyDisks[nodeId].insert (pdiskId);
678
+ }
679
+ }
680
+ });
681
+
682
+ for (ui32 nodeIdx = 0 ; nodeIdx < nodes; ++nodeIdx) {
683
+ env.SetNodeFaulty (env.GetNodeId (nodeIdx), true );
684
+
685
+ env.SimulateSleep (TDuration::Minutes (5 ));
686
+ }
687
+
688
+ observerHolder.Remove ();
689
+
690
+ for (ui32 nodeIdx = 0 ; nodeIdx < nodes; ++nodeIdx) {
691
+ ui32 nodeId = env.GetNodeId (nodeIdx);
692
+
693
+ UNIT_ASSERT_VALUES_EQUAL (faultyDisks[nodeId].size (), disksPerNode);
694
+ }
695
+ }
696
+
535
697
Y_UNIT_TEST (BSControllerUnresponsive) {
536
698
TTestEnv env (8 , 4 );
537
699
env.EnableNoisyBSCPipe ();
0 commit comments