@@ -7,6 +7,11 @@ namespace NKikimr::NStorage {
77 void TDistributedConfigKeeper::Handle (TEvInterconnect::TEvNodesInfo::TPtr ev) {
88 STLOG (PRI_DEBUG, BS_NODE, NWDC11, " TEvNodesInfo" );
99
10+ if (SelfManagementEnabled) {
11+ // we obtain node list only from current StorageConfig
12+ return ;
13+ }
14+
1015 std::vector<std::tuple<TNodeIdentifier, TNodeLocation>> newNodeList;
1116 for (const auto & item : ev->Get ()->Nodes ) {
1217 if (item.IsStatic ) {
@@ -18,6 +23,8 @@ namespace NKikimr::NStorage {
1823 }
1924
2025 void TDistributedConfigKeeper::ApplyNewNodeList (std::span<std::tuple<TNodeIdentifier, TNodeLocation>> newNodeList) {
26+ STLOG (PRI_DEBUG, BS_NODE, NWDC13, " ApplyNewNodeList" , (NewNodeList, newNodeList));
27+
2128 // do not start configuration negotiation for dynamic nodes
2229 if (!IsSelfStatic) {
2330 std::optional<TString> expectedBridgePileName;
@@ -49,7 +56,8 @@ namespace NKikimr::NStorage {
4956 break ;
5057 }
5158 }
52- Y_ABORT_UNLESS (found);
59+ auto fn = [](const auto & x) { return TStringBuilder () << std::get<0 >(x); };
60+ Y_VERIFY_S (found, " SelfNodeId# " << selfNodeId << " NewNodeList# " << FormatList (newNodeList | std::views::transform (fn)));
5361
5462 // process all other nodes, find bindable ones (from our current pile) and build list of all nodes
5563 AllNodeIds.clear ();
@@ -61,7 +69,7 @@ namespace NKikimr::NStorage {
6169
6270 for (const auto & [item, location] : newNodeList) {
6371 const ui32 nodeId = item.NodeId ();
64- AllNodeIds.insert (item. NodeId () );
72+ AllNodeIds.insert (nodeId );
6573
6674 // check if node is from the same pile (as this one)
6775 if (location.GetBridgePileName () == SelfNodeBridgePileName) {
@@ -297,6 +305,13 @@ namespace NKikimr::NStorage {
297305 if (Binding && Binding->NodeId == nodeId) {
298306 AbortBinding (" disconnection" , false );
299307 }
308+
309+ // abort scatter tasks issued to newly added nodes
310+ for (auto it = AddedNodesScatterTasks.lower_bound ({nodeId, 0 }); it != AddedNodesScatterTasks.end () &&
311+ std::get<0 >(*it) == nodeId; it = AddedNodesScatterTasks.erase (it)) {
312+ const auto & [nodeId, cookie] = *it;
313+ AbortScatterTask (cookie, nodeId);
314+ }
300315 }
301316
302317 void TDistributedConfigKeeper::UnsubscribeInterconnect (ui32 nodeId) {
@@ -309,6 +324,10 @@ namespace NKikimr::NStorage {
309324 if (ConnectedDynamicNodes.contains (nodeId)) {
310325 return ;
311326 }
327+ if (const auto it = AddedNodesScatterTasks.lower_bound ({nodeId, 0 }); it != AddedNodesScatterTasks.end () &&
328+ std::get<0 >(*it) == nodeId) {
329+ return ;
330+ }
312331 if (const auto it = SubscribedSessions.find (nodeId); it != SubscribedSessions.end ()) {
313332 TSessionSubscription& subs = it->second ;
314333 STLOG (PRI_DEBUG, BS_NODE, NWDC55, " UnsubscribeInterconnect" , (NodeId, nodeId), (Subscription, subs));
@@ -319,11 +338,17 @@ namespace NKikimr::NStorage {
319338 Y_ABORT_UNLESS (jt != SubscriptionCookieMap.end ());
320339 Y_ABORT_UNLESS (jt->second == nodeId);
321340 SubscriptionCookieMap.erase (jt);
341+ if (!AllNodeIds.contains (nodeId)) {
342+ TActivationContext::Send (new IEventHandle (TEvInterconnect::EvDisconnect, 0 ,
343+ TActivationContext::InterconnectProxy (nodeId), {}, nullptr , 0 ));
344+ }
322345 } else {
323346 // we already had TEvNodeConnected, so we have to unsubscribe
324347 Y_ABORT_UNLESS (subs.SessionId );
325- TActivationContext::Send (new IEventHandle (TEvents::TSystem::Unsubscribe, 0 , subs.SessionId , SelfId (),
326- nullptr , 0 ));
348+ ui32 event = AllNodeIds.contains (nodeId)
349+ ? TEvents::TSystem::Unsubscribe
350+ : TEvents::TSystem::Poison;
351+ TActivationContext::Send (new IEventHandle (event, 0 , subs.SessionId , SelfId (), nullptr , 0 ));
327352 }
328353 SubscribedSessions.erase (it);
329354 }
@@ -403,7 +428,8 @@ namespace NKikimr::NStorage {
403428 return ; // possible race with unbinding
404429 }
405430
406- Y_ABORT_UNLESS (Binding->RootNodeId || ScatterTasks.empty ());
431+ auto isTargeted = [](const TScatterTaskOrigin& origin) { return std::holds_alternative<TScatterTaskOriginTargeted>(origin); };
432+ Y_ABORT_UNLESS (Binding->RootNodeId || std::ranges::all_of (ScatterTasks | std::views::values, isTargeted, &TScatterTask::Origin));
407433
408434 // check if this binding was accepted and if it is acceptable from our point of view
409435 bool bindingUpdate = false ;
@@ -546,13 +572,10 @@ namespace NKikimr::NStorage {
546572 Y_ABORT_UNLESS (senderNodeId != SelfId ().NodeId ());
547573 auto & record = ev->Get ()->Record ;
548574
549- STLOG (PRI_DEBUG, BS_NODE, NWDC02, " TEvNodeConfigPush" , (NodeId, senderNodeId), (Cookie, ev->Cookie ),
550- (SessionId, ev->InterconnectSession ), (Binding, Binding), (Record, record),
551- (RootNodeId, GetRootNodeId ()));
552-
553575 // check if we have to send our current config to the peer
554576 const NKikimrBlobStorage::TStorageConfig *configToPeer = nullptr ;
555577 std::optional<ui64> requestStorageConfigGeneration;
578+ const bool knownNode = AllNodeIds.contains (senderNodeId);
556579 if (StorageConfig) {
557580 for (const auto & item : record.GetBoundNodes ()) {
558581 if (item.GetNodeId ().GetNodeId () == senderNodeId) {
@@ -566,9 +589,19 @@ namespace NKikimr::NStorage {
566589 }
567590 }
568591
569- if (!AllNodeIds.contains (senderNodeId)) {
592+ STLOG (PRI_DEBUG, BS_NODE, NWDC02, " TEvNodeConfigPush" ,
593+ (NodeId, senderNodeId),
594+ (Cookie, ev->Cookie ),
595+ (SessionId, ev->InterconnectSession ),
596+ (Binding, Binding),
597+ (Record, record),
598+ (RootNodeId, GetRootNodeId ()),
599+ (StorageConfigGeneration, StorageConfig ? (i64 )StorageConfig->GetGeneration () : -1 ),
600+ (KnownNode, knownNode));
601+
602+ if (!knownNode) {
570603 // node has been already deleted from the config, but new subscription is coming through -- ignoring it
571- SendEvent (*ev, TEvNodeConfigReversePush::MakeRejected (configToPeer ));
604+ SendEvent (*ev, TEvNodeConfigReversePush::MakeRejected (nullptr ));
572605 return ;
573606 }
574607
@@ -577,7 +610,7 @@ namespace NKikimr::NStorage {
577610 STLOG (PRI_DEBUG, BS_NODE, NWDC28, " TEvNodeConfigPush rejected" , (NodeId, senderNodeId),
578611 (Cookie, ev->Cookie ), (SessionId, ev->InterconnectSession ), (Binding, Binding),
579612 (Record, record));
580- SendEvent (*ev, TEvNodeConfigReversePush::MakeRejected (configToPeer ));
613+ SendEvent (*ev, TEvNodeConfigReversePush::MakeRejected (nullptr ));
581614 return ;
582615 }
583616
@@ -589,7 +622,7 @@ namespace NKikimr::NStorage {
589622 // nodes AND this is the root one
590623 } else {
591624 // this is either not the root node, or no quorum for connection
592- auto response = TEvNodeConfigReversePush::MakeRejected (configToPeer );
625+ auto response = TEvNodeConfigReversePush::MakeRejected (nullptr );
593626 if (Binding && Binding->RootNodeId ) {
594627 // command peer to join this specific node
595628 response->Record .SetRootNodeId (Binding->RootNodeId );
0 commit comments