Skip to content

Commit 4b10051

Browse files
committed
Moved commit "Use 1-thread pool executor for subsession event handlers" from ydb repo
1 parent 7a70b5c commit 4b10051

File tree

4 files changed

+58
-55
lines changed

4 files changed

+58
-55
lines changed

src/client/federated_topic/impl/federated_topic_impl.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ TFederatedTopicClient::TImpl::CreateWriteSession(const TFederatedWriteSessionSet
3535
splitSettings.EventHandlers_.HandlersExecutor(ClientSettings.DefaultHandlersExecutor_);
3636
}
3737
}
38-
auto session = std::make_shared<TFederatedWriteSession>(splitSettings, Connections, ClientSettings, GetObserver(), ProvidedCodecs);
38+
auto session = std::make_shared<TFederatedWriteSession>(
39+
splitSettings, Connections, ClientSettings, GetObserver(), ProvidedCodecs, GetSubsessionHandlersExecutor());
3940
session->Start();
4041
return std::move(session);
4142
}
@@ -48,4 +49,13 @@ void TFederatedTopicClient::TImpl::InitObserver() {
4849
}
4950
}
5051

52+
auto TFederatedTopicClient::TImpl::GetSubsessionHandlersExecutor() -> NTopic::IExecutor::TPtr {
53+
with_lock (Lock) {
54+
if (!SubsessionHandlersExecutor) {
55+
SubsessionHandlersExecutor = NTopic::CreateThreadPoolExecutor(1);
56+
}
57+
return SubsessionHandlersExecutor;
58+
}
59+
}
60+
5161
}

src/client/federated_topic/impl/federated_topic_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,20 @@ class TFederatedTopicClient::TImpl {
7272

7373
void InitObserver();
7474

75+
private:
76+
77+
// Use single-threaded executor to prevent deadlocks inside subsession event handlers.
78+
NTopic::IExecutor::TPtr GetSubsessionHandlersExecutor();
79+
7580
private:
7681
std::shared_ptr<TGRpcConnectionsImpl> Connections;
7782
const TFederatedTopicClientSettings ClientSettings;
7883
std::shared_ptr<TFederatedDbObserver> Observer;
7984
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> ProvidedCodecs =
8085
std::make_shared<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>>();
86+
87+
NTopic::IExecutor::TPtr SubsessionHandlersExecutor;
88+
8189
TAdaptiveLock Lock;
8290
};
8391

src/client/federated_topic/impl/federated_write_session.cpp

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ TFederatedWriteSessionImpl::TFederatedWriteSessionImpl(
2929
std::shared_ptr<TGRpcConnectionsImpl> connections,
3030
const TFederatedTopicClientSettings& clientSettings,
3131
std::shared_ptr<TFederatedDbObserver> observer,
32-
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> codecs
32+
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> codecs,
33+
NTopic::IExecutor::TPtr subsessionHandlersExecutor
3334
)
3435
: Settings(settings)
3536
, Connections(std::move(connections))
3637
, SubclientSettings(FromFederated(clientSettings))
3738
, ProvidedCodecs(std::move(codecs))
39+
, SubsessionHandlersExecutor(subsessionHandlersExecutor)
3840
, Observer(std::move(observer))
3941
, AsyncInit(Observer->WaitForFirstState())
4042
, FederationState(nullptr)
@@ -70,15 +72,16 @@ void TFederatedWriteSessionImpl::IssueTokenIfAllowed() {
7072
}
7173
}
7274

73-
void TFederatedWriteSessionImpl::UpdateFederationStateImpl() {
75+
std::shared_ptr<NTopic::IWriteSession> TFederatedWriteSessionImpl::UpdateFederationStateImpl() {
7476
Y_ABORT_UNLESS(Lock.IsLocked());
7577
// Even after the user has called the Close method, transitioning the session to the CLOSING state,
7678
// we keep updating the federation state, as the session may still have some messages to send in its queues,
7779
// and for that we need to know the current state of the federation.
7880
if (SessionState < State::CLOSED) {
7981
FederationState = Observer->GetState();
80-
OnFederationStateUpdateImpl();
82+
return OnFederationStateUpdateImpl();
8183
}
84+
return {};
8285
}
8386

8487
void TFederatedWriteSessionImpl::Start() {
@@ -103,15 +106,16 @@ void TFederatedWriteSessionImpl::Start() {
103106
});
104107
}
105108

106-
void TFederatedWriteSessionImpl::OpenSubsessionImpl(std::shared_ptr<TDbInfo> db) {
109+
std::shared_ptr<NTopic::IWriteSession> TFederatedWriteSessionImpl::OpenSubsessionImpl(std::shared_ptr<TDbInfo> db) {
107110
Y_ABORT_UNLESS(Lock.IsLocked());
108111

109112
++SubsessionGeneration;
110113

114+
std::shared_ptr<NTopic::IWriteSession> oldSubsession;
115+
111116
if (Subsession) {
112117
PendingToken.reset();
113-
OldSubsession = std::move(Subsession);
114-
OldSubsession->Close(TDuration::Zero());
118+
std::swap(oldSubsession, Subsession);
115119
}
116120

117121
auto clientSettings = SubclientSettings;
@@ -121,22 +125,18 @@ void TFederatedWriteSessionImpl::OpenSubsessionImpl(std::shared_ptr<TDbInfo> db)
121125
auto subclient = std::make_shared<NTopic::TTopicClient::TImpl>(Connections, clientSettings);
122126

123127
auto handlers = NTopic::TWriteSessionSettings::TEventHandlers()
124-
.HandlersExecutor(Settings.EventHandlers_.HandlersExecutor_)
128+
.HandlersExecutor(SubsessionHandlersExecutor)
125129
.ReadyToAcceptHandler([selfCtx = SelfContext, generation = SubsessionGeneration](NTopic::TWriteSessionEvent::TReadyToAcceptEvent& ev) {
126130
if (auto self = selfCtx->LockShared()) {
127-
TDeferredWrite deferred;
128-
129131
with_lock(self->Lock) {
130132
if (generation != self->SubsessionGeneration) {
131133
return;
132134
}
133135

134136
Y_ABORT_UNLESS(!self->PendingToken.has_value());
135137
self->PendingToken = std::move(ev.ContinuationToken);
136-
self->PrepareDeferredWriteImpl(deferred);
138+
self->MaybeWriteImpl();
137139
}
138-
139-
deferred.DoWrite();
140140
}
141141
})
142142
.AcksHandler([selfCtx = SelfContext](NTopic::TWriteSessionEvent::TAcksEvent& ev) {
@@ -181,6 +181,8 @@ void TFederatedWriteSessionImpl::OpenSubsessionImpl(std::shared_ptr<TDbInfo> db)
181181

182182
Subsession = subclient->CreateWriteSession(wsSettings);
183183
CurrentDatabase = db;
184+
185+
return oldSubsession;
184186
}
185187

186188
std::pair<std::shared_ptr<TDbInfo>, EStatus> SelectDatabaseByHashImpl(
@@ -265,13 +267,13 @@ std::pair<std::shared_ptr<TDbInfo>, EStatus> SelectDatabaseImpl(
265267
return SelectDatabaseByHashImpl(settings, dbInfos);
266268
}
267269

268-
void TFederatedWriteSessionImpl::OnFederationStateUpdateImpl() {
270+
std::shared_ptr<NTopic::IWriteSession> TFederatedWriteSessionImpl::OnFederationStateUpdateImpl() {
269271
Y_ABORT_UNLESS(Lock.IsLocked());
270272
if (!FederationState->Status.IsSuccess()) {
271273
// The observer became stale, it won't try to get federation state anymore due to retry policy,
272274
// so there's no reason to keep the write session alive.
273275
CloseImpl(FederationState->Status.GetStatus(), NYql::TIssues(FederationState->Status.GetIssues()));
274-
return;
276+
return {};
275277
}
276278

277279
Y_ABORT_UNLESS(!FederationState->DbInfos.empty());
@@ -290,19 +292,22 @@ void TFederatedWriteSessionImpl::OnFederationStateUpdateImpl() {
290292
LOG_LAZY(Log, TLOG_ERR, GetLogPrefixImpl() << message << ". Status: " << status);
291293
CloseImpl(status, NYql::TIssues{NYql::TIssue(message)});
292294
}
293-
return;
295+
return {};
294296
}
295297
RetryState.reset();
296298

299+
std::shared_ptr<NTopic::IWriteSession> oldSubsession;
297300
if (!DatabasesAreSame(preferrableDb, CurrentDatabase)) {
298301
LOG_LAZY(Log, TLOG_INFO, GetLogPrefixImpl()
299302
<< "Start federated write session to database '" << preferrableDb->name()
300303
<< "' (previous was " << (CurrentDatabase ? CurrentDatabase->name() : "<empty>") << ")"
301304
<< " FederationState: " << *FederationState);
302-
OpenSubsessionImpl(preferrableDb);
305+
oldSubsession = OpenSubsessionImpl(preferrableDb);
303306
}
304307

305308
ScheduleFederationStateUpdateImpl(UPDATE_FEDERATION_STATE_DELAY);
309+
310+
return oldSubsession;
306311
}
307312

308313
void TFederatedWriteSessionImpl::ScheduleFederationStateUpdateImpl(TDuration delay) {
@@ -312,8 +317,10 @@ void TFederatedWriteSessionImpl::ScheduleFederationStateUpdateImpl(TDuration del
312317
if (auto self = selfCtx->LockShared()) {
313318
std::shared_ptr<NTopic::IWriteSession> old;
314319
with_lock(self->Lock) {
315-
self->UpdateFederationStateImpl();
316-
old = std::move(self->OldSubsession);
320+
old = self->UpdateFederationStateImpl();
321+
}
322+
if (old) {
323+
old->Close(TDuration::Zero());
317324
}
318325
}
319326
}
@@ -376,24 +383,20 @@ void TFederatedWriteSessionImpl::WriteEncoded(NTopic::TContinuationToken&& token
376383
}
377384

378385
void TFederatedWriteSessionImpl::WriteInternal(NTopic::TContinuationToken&&, TWrappedWriteMessage&& wrapped) {
379-
TDeferredWrite deferred(Subsession);
380-
381386
with_lock(Lock) {
382387
ClientHasToken = false;
383388
if (!wrapped.Message.CreateTimestamp_.has_value()) {
384389
wrapped.Message.CreateTimestamp_ = TInstant::Now();
385390
}
386391
BufferFreeSpace -= wrapped.Message.Data.size();
387392
OriginalMessagesToPassDown.emplace_back(std::move(wrapped));
388-
PrepareDeferredWriteImpl(deferred);
393+
MaybeWriteImpl();
389394
}
390395

391-
deferred.DoWrite();
392-
393396
IssueTokenIfAllowed();
394397
}
395398

396-
bool TFederatedWriteSessionImpl::PrepareDeferredWriteImpl(TDeferredWrite& deferred) {
399+
bool TFederatedWriteSessionImpl::MaybeWriteImpl() {
397400
Y_ABORT_UNLESS(Lock.IsLocked());
398401
if (!PendingToken.has_value()) {
399402
return false;
@@ -403,9 +406,7 @@ bool TFederatedWriteSessionImpl::PrepareDeferredWriteImpl(TDeferredWrite& deferr
403406
}
404407
OriginalMessagesToGetAck.push_back(std::move(OriginalMessagesToPassDown.front()));
405408
OriginalMessagesToPassDown.pop_front();
406-
deferred.Writer = Subsession;
407-
deferred.Token.emplace(std::move(*PendingToken));
408-
deferred.Message.emplace(std::move(OriginalMessagesToGetAck.back().Message));
409+
Subsession->Write(std::move(*PendingToken), std::move(OriginalMessagesToGetAck.back().Message));
409410
PendingToken.reset();
410411
return true;
411412
}

src/client/federated_topic/impl/federated_write_session.h

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class TFederatedWriteSessionImpl : public NTopic::TContinuationTokenIssuer,
2626
std::shared_ptr<TGRpcConnectionsImpl> connections,
2727
const TFederatedTopicClientSettings& clientSetttings,
2828
std::shared_ptr<TFederatedDbObserver> observer,
29-
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> codecs);
29+
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> codecs,
30+
NTopic::IExecutor::TPtr subsessionHandlersExecutor);
3031

3132
~TFederatedWriteSessionImpl() = default;
3233

@@ -61,40 +62,22 @@ class TFederatedWriteSessionImpl : public NTopic::TContinuationTokenIssuer,
6162
}
6263
};
6364

64-
struct TDeferredWrite {
65-
TDeferredWrite() {}
66-
explicit TDeferredWrite(std::shared_ptr<NTopic::IWriteSession> writer)
67-
: Writer(std::move(writer)) {
68-
}
69-
70-
void DoWrite() {
71-
if (!Token.has_value() && !Message.has_value()) {
72-
return;
73-
}
74-
Y_ABORT_UNLESS(Token.has_value() && Message.has_value());
75-
return Writer->Write(std::move(*Token), std::move(*Message));
76-
}
77-
78-
std::shared_ptr<NTopic::IWriteSession> Writer;
79-
std::optional<NTopic::TContinuationToken> Token;
80-
std::optional<NTopic::TWriteMessage> Message;
81-
};
82-
8365
private:
8466
void Start();
85-
void OpenSubsessionImpl(std::shared_ptr<TDbInfo> db);
8667

87-
void OnFederationStateUpdateImpl();
68+
std::shared_ptr<NTopic::IWriteSession> OpenSubsessionImpl(std::shared_ptr<TDbInfo> db);
69+
std::shared_ptr<NTopic::IWriteSession> UpdateFederationStateImpl();
70+
std::shared_ptr<NTopic::IWriteSession> OnFederationStateUpdateImpl();
71+
8872
void ScheduleFederationStateUpdateImpl(TDuration delay);
8973

9074
void WriteInternal(NTopic::TContinuationToken&&, TWrappedWriteMessage&& message);
91-
bool PrepareDeferredWriteImpl(TDeferredWrite& deferred);
75+
bool MaybeWriteImpl();
9276

9377
void CloseImpl(EStatus statusCode, NYql::TIssues&& issues);
9478
void CloseImpl(NTopic::TSessionClosedEvent const& ev);
9579

9680
bool MessageQueuesAreEmptyImpl() const;
97-
void UpdateFederationStateImpl();
9881

9982
void IssueTokenIfAllowed();
10083

@@ -106,6 +89,7 @@ class TFederatedWriteSessionImpl : public NTopic::TContinuationTokenIssuer,
10689
std::shared_ptr<TGRpcConnectionsImpl> Connections;
10790
const NTopic::TTopicClientSettings SubclientSettings;
10891
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> ProvidedCodecs;
92+
NTopic::IExecutor::TPtr SubsessionHandlersExecutor;
10993

11094
NTopic::IRetryPolicy::IRetryState::TPtr RetryState;
11195
std::shared_ptr<TFederatedDbObserver> Observer;
@@ -124,7 +108,6 @@ class TFederatedWriteSessionImpl : public NTopic::TContinuationTokenIssuer,
124108

125109
size_t SubsessionGeneration = 0;
126110
std::shared_ptr<NTopic::IWriteSession> Subsession;
127-
std::shared_ptr<NTopic::IWriteSession> OldSubsession;
128111

129112
std::shared_ptr<NTopic::TWriteSessionEventsQueue> ClientEventsQueue;
130113

@@ -155,8 +138,9 @@ class TFederatedWriteSession : public NTopic::IWriteSession,
155138
std::shared_ptr<TGRpcConnectionsImpl> connections,
156139
const TFederatedTopicClientSettings& clientSettings,
157140
std::shared_ptr<TFederatedDbObserver> observer,
158-
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> codecs)
159-
: TContextOwner(settings, std::move(connections), clientSettings, std::move(observer), codecs) {}
141+
std::shared_ptr<std::unordered_map<NTopic::ECodec, std::unique_ptr<NTopic::ICodec>>> codecs,
142+
NTopic::IExecutor::TPtr subsessionHandlersExecutor)
143+
: TContextOwner(settings, std::move(connections), clientSettings, std::move(observer), codecs, subsessionHandlersExecutor) {}
160144

161145
NThreading::TFuture<void> WaitEvent() override {
162146
return TryGetImpl()->WaitEvent();

0 commit comments

Comments
 (0)