Skip to content

Commit 8f82577

Browse files
authored
Fix cluster rejoin circuit in IC (ydb-platform#24237)
2 parents 1ef6af1 + e8db0d6 commit 8f82577

File tree

3 files changed

+64
-46
lines changed

3 files changed

+64
-46
lines changed

ydb/core/blobstorage/bridge/proxy/bridge_proxy.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ namespace NKikimr {
639639
TBridgeInfo::TPtr BridgeInfo;
640640

641641
std::deque<std::unique_ptr<IEventHandle>> PendingQ;
642-
std::map<ui32, std::deque<std::unique_ptr<IEventHandle>>> PendingByGeneration;
642+
std::deque<std::tuple<TMonotonic, std::unique_ptr<IEventHandle>>> PendingForNextGeneration;
643643

644644
public:
645645
TBridgedBlobStorageProxyActor(TIntrusivePtr<TBlobStorageGroupInfo> info)
@@ -650,6 +650,32 @@ namespace NKikimr {
650650
void Bootstrap() {
651651
Send(MakeBlobStorageNodeWardenID(SelfId().NodeId()), new TEvNodeWardenQueryStorageConfig(/*subscribe=*/ true));
652652
Become(&TThis::StateWaitBridgeInfo);
653+
HandleWakeup();
654+
}
655+
656+
void HandleWakeup() {
657+
TMonotonic dropBefore = TActivationContext::Monotonic() - TDuration::Seconds(2);
658+
while (!PendingForNextGeneration.empty()) {
659+
if (auto& [timestamp, ev] = PendingForNextGeneration.front(); timestamp < dropBefore) {
660+
switch (ev->GetTypeRewrite()) {
661+
#define MAKE_ERROR(TYPE) \
662+
case TYPE::EventType: \
663+
Send(ev->Sender, static_cast<TYPE*>(ev->GetBase())->MakeErrorResponse(NKikimrProto::ERROR, \
664+
"bridge request timed out", GroupId), 0, ev->Cookie); \
665+
break;
666+
667+
DSPROXY_ENUM_EVENTS(MAKE_ERROR)
668+
#undef MAKE_ERROR
669+
default:
670+
Y_ABORT();
671+
}
672+
PendingForNextGeneration.pop_front();
673+
} else {
674+
break;
675+
}
676+
}
677+
TActivationContext::Schedule(TDuration::Seconds(1), new IEventHandle(TEvents::TSystem::Wakeup, 0, SelfId(),
678+
{}, nullptr, 0));
653679
}
654680

655681
void PassAway() override {
@@ -815,7 +841,7 @@ namespace NKikimr {
815841
const ui32 myGeneration = bridgeGroupState.GetPile(pile.BridgePileId.GetPileIndex()).GetGroupGeneration();
816842

817843
if (myGeneration < msg->RacingGeneration) {
818-
PendingByGeneration[Info->GroupGeneration + 1].push_back(std::move(handle));
844+
PendingForNextGeneration.emplace_back(TActivationContext::Monotonic(), std::move(handle));
819845
} else if (msg->RacingGeneration < myGeneration) {
820846
// our generation is higher than the recipient's; we have to route this message through node warden
821847
// to ensure proxy's configuration gets in place
@@ -879,17 +905,13 @@ namespace NKikimr {
879905
}
880906

881907
void Handle(TEvBlobStorage::TEvConfigureProxy::TPtr ev) {
882-
Info = std::move(ev->Get()->Info);
883-
while (!PendingByGeneration.empty()) {
884-
auto it = PendingByGeneration.begin();
885-
auto& [requiredGeneration, events] = *it;
886-
if (Info->GroupGeneration < requiredGeneration) {
887-
break;
888-
}
889-
for (auto& ev : events) {
908+
auto prevInfo = std::exchange(Info, std::move(ev->Get()->Info));
909+
Y_ABORT_UNLESS(prevInfo);
910+
Y_ABORT_UNLESS(Info);
911+
if (prevInfo->GroupGeneration < Info->GroupGeneration) {
912+
for (auto& [timestamp, ev] : std::exchange(PendingForNextGeneration, {})) {
890913
TActivationContext::Send(ev.release());
891914
}
892-
PendingByGeneration.erase(it);
893915
}
894916
}
895917

@@ -923,6 +945,7 @@ namespace NKikimr {
923945
hFunc(TEvBlobStorage::TEvConfigureProxy, Handle)
924946
hFunc(TEvNodeWardenStorageConfig, Handle)
925947
cFunc(TEvents::TSystem::Poison, PassAway)
948+
cFunc(TEvents::TSystem::Wakeup, HandleWakeup)
926949
)
927950

928951
#undef HANDLE_RESULT

ydb/core/blobstorage/nodewarden/distconf_connectivity.cpp

Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -260,51 +260,46 @@ namespace NKikimr::NStorage {
260260
return TStringBuilder() << "peer storage config invalid: " << *error;
261261
} else if (auto error = ValidateClusterState(*StorageConfig)) {
262262
return TStringBuilder() << "local storage config invalid: " << *error;
263-
}
264-
265-
// local/peer side is returning from DISCONNECTED state, validate cluster histories to ensure there were no
266-
// definite split brain
267-
if (auto error = ValidateClusterStateDetails(config)) {
263+
} else if (auto error = ValidateClusterStateDetails(config)) {
268264
return TStringBuilder() << "peer cluster state history invalid: " << *error;
269265
} else if (auto error = ValidateClusterStateDetails(*StorageConfig)) {
270266
return TStringBuilder() << "local cluster state history invalid: " << *error;
271-
} else if (auto error = CheckHistoryCompatibility(*StorageConfig, config)) {
272-
// histories are incompatible, connection won't ever be possible
273-
return error;
274267
}
275268

276-
const auto *peerPile = BridgeInfo->GetPile(peerBridgePileId);
277-
if (peerPile == BridgeInfo->SelfNodePile) {
278-
// no extra checks when connecting nodes from the same pile
279-
return std::nullopt;
280-
}
269+
std::optional<TString> error;
281270

282-
if (StorageConfig->GetGeneration() == config.GetGeneration() && StorageConfig->GetFingerprint() != config.GetFingerprint()) {
283-
return "config fingerprint mismatch";
284-
}
271+
const auto *peerPile = BridgeInfo->GetPile(peerBridgePileId);
272+
if (peerPile != BridgeInfo->SelfNodePile) { // extra checks when connecting between different piles
273+
if (auto error = CheckHistoryCompatibility(*StorageConfig, config)) {
274+
// histories are incompatible, connection won't ever be possible
275+
return error;
276+
}
285277

286-
const NKikimrBlobStorage::TStorageConfig& newerConfig =
287-
StorageConfig->GetGeneration() < config.GetGeneration()
288-
? config
289-
: *StorageConfig;
278+
if (StorageConfig->GetGeneration() == config.GetGeneration() && StorageConfig->GetFingerprint() != config.GetFingerprint()) {
279+
return "config fingerprint mismatch";
280+
}
290281

291-
const auto& cs = newerConfig.GetClusterState();
282+
const NKikimrBlobStorage::TStorageConfig& newerConfig =
283+
StorageConfig->GetGeneration() < config.GetGeneration()
284+
? config
285+
: *StorageConfig;
292286

293-
std::optional<TString> error;
287+
const auto& cs = newerConfig.GetClusterState();
294288

295-
if (!NBridge::PileStateTraits(cs.GetPerPileState(peerBridgePileId.GetPileIndex())).AllowsConnection) {
296-
error = "peer is not allowed to connect";
297-
} else if (!NBridge::PileStateTraits(cs.GetPerPileState(SelfBridgePileId.GetPileIndex())).AllowsConnection) {
298-
error = "local node is not allowed to accept peer";
299-
}
289+
if (!NBridge::PileStateTraits(cs.GetPerPileState(peerBridgePileId.GetPileIndex())).AllowsConnection) {
290+
error = "peer is not allowed to connect";
291+
} else if (!NBridge::PileStateTraits(cs.GetPerPileState(SelfBridgePileId.GetPileIndex())).AllowsConnection) {
292+
error = "local node is not allowed to accept peer";
293+
}
300294

301-
if (!error) {
302-
const auto& myClusterState = StorageConfig->GetClusterState();
303-
const auto& peerClusterState = config.GetClusterState();
304-
if (myClusterState.GetGeneration() < peerClusterState.GetGeneration()) {
305-
error = "local cluster state is obsolete";
306-
} else if (peerClusterState.GetGeneration() < myClusterState.GetGeneration()) {
307-
error = "peer cluster state is obsolete";
295+
if (!error) {
296+
const auto& myClusterState = StorageConfig->GetClusterState();
297+
const auto& peerClusterState = config.GetClusterState();
298+
if (myClusterState.GetGeneration() < peerClusterState.GetGeneration()) {
299+
error = "local cluster state is obsolete";
300+
} else if (peerClusterState.GetGeneration() < myClusterState.GetGeneration()) {
301+
error = "peer cluster state is obsolete";
302+
}
308303
}
309304
}
310305

ydb/core/blobstorage/nodewarden/node_warden_pdisk.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ namespace NKikimr::NStorage {
576576
Y_ABORT_UNLESS(PDiskKey.NodeId == SelfId().NodeId());
577577
Send(MakeBlobStoragePDiskID(PDiskKey.NodeId, PDiskKey.PDiskId), ConvertedEv.release(),
578578
IEventHandle::FlagTrackDelivery);
579-
Become(&TThis::StateFunc, TDuration::Seconds(10), new TEvents::TEvWakeup);
579+
Become(&TThis::StateFunc, TDuration::Seconds(30), new TEvents::TEvWakeup);
580580
}
581581

582582
void Handle(TEvents::TEvUndelivered::TPtr /*ev*/) {

0 commit comments

Comments
 (0)