Skip to content

Commit be2302d

Browse files
Memory leak in Topic SDK (#6249)
1 parent 0bf777f commit be2302d

File tree

3 files changed

+105
-14
lines changed

3 files changed

+105
-14
lines changed

ydb/public/sdk/cpp/client/ydb_topic/impl/read_session_impl.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class TDeferredActions {
143143
}
144144

145145
void DeferReadFromProcessor(const typename IProcessor<UseMigrationProtocol>::TPtr& processor, TServerMessage<UseMigrationProtocol>* dst, typename IProcessor<UseMigrationProtocol>::TReadCallback callback);
146-
void DeferStartExecutorTask(const typename IAExecutor<UseMigrationProtocol>::TPtr& executor, typename IAExecutor<UseMigrationProtocol>::TFunction task);
146+
void DeferStartExecutorTask(const typename IAExecutor<UseMigrationProtocol>::TPtr& executor, typename IAExecutor<UseMigrationProtocol>::TFunction&& task);
147147
void DeferAbortSession(TCallbackContextPtr<UseMigrationProtocol> cbContext, TASessionClosedEvent<UseMigrationProtocol>&& closeEvent);
148148
void DeferAbortSession(TCallbackContextPtr<UseMigrationProtocol> cbContext, EStatus statusCode, NYql::TIssues&& issues);
149149
void DeferAbortSession(TCallbackContextPtr<UseMigrationProtocol> cbContext, EStatus statusCode, const TString& message);
@@ -209,6 +209,8 @@ class TDataDecompressionInfo : public std::enable_shared_from_this<TDataDecompre
209209
void PlanDecompressionTasks(double averageCompressionRatio,
210210
TIntrusivePtr<TPartitionStreamImpl<UseMigrationProtocol>> partitionStream);
211211

212+
void OnDestroyReadSession();
213+
212214
bool IsReady() const {
213215
return SourceDataNotProcessed == 0;
214216
}
@@ -306,6 +308,8 @@ class TDataDecompressionInfo : public std::enable_shared_from_this<TDataDecompre
306308
return EstimatedDecompressedSize;
307309
}
308310

311+
void ClearParent();
312+
309313
private:
310314
TDataDecompressionInfo::TPtr Parent;
311315
TIntrusivePtr<TPartitionStreamImpl<UseMigrationProtocol>> PartitionStream;
@@ -1098,6 +1102,11 @@ class TSingleClusterReadSessionImpl : public TEnableSelfContext<TSingleClusterRe
10981102

10991103
void OnCreateNewDecompressionTask();
11001104
void OnDecompressionInfoDestroy(i64 compressedSize, i64 decompressedSize, i64 messagesCount, i64 serverBytesSize);
1105+
void OnDecompressionInfoDestroyImpl(i64 compressedSize,
1106+
i64 decompressedSize,
1107+
i64 messagesCount,
1108+
i64 serverBytesSize,
1109+
TDeferredActions<UseMigrationProtocol>& deferred);
11011110

11021111
void OnDataDecompressed(i64 sourceSize, i64 estimatedDecompressedSize, i64 decompressedSize, size_t messagesCount, i64 serverBytesSize = 0);
11031112

@@ -1287,6 +1296,8 @@ class TSingleClusterReadSessionImpl : public TEnableSelfContext<TSingleClusterRe
12871296
{
12881297
}
12891298

1299+
void OnDestroyReadSession();
1300+
12901301
TDataDecompressionInfoPtr<UseMigrationProtocol> BatchInfo;
12911302
TIntrusivePtr<TPartitionStreamImpl<UseMigrationProtocol>> PartitionStream;
12921303
};

ydb/public/sdk/cpp/client/ydb_topic/impl/read_session_impl.ipp

+45-13
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ void TRawPartitionStreamEventQueue<UseMigrationProtocol>::DeleteNotReadyTail(TDe
216216
swap(ready, NotReady);
217217
}
218218

219+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
220+
// TDecompressionQueueItem
221+
222+
template <bool UseMigrationProtocol>
223+
void TSingleClusterReadSessionImpl<UseMigrationProtocol>::TDecompressionQueueItem::OnDestroyReadSession()
224+
{
225+
BatchInfo->OnDestroyReadSession();
226+
}
227+
219228
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
220229
// TSingleClusterReadSessionImpl
221230

@@ -224,6 +233,10 @@ TSingleClusterReadSessionImpl<UseMigrationProtocol>::~TSingleClusterReadSessionI
224233
for (auto&& [_, partitionStream] : PartitionStreams) {
225234
partitionStream->ClearQueue();
226235
}
236+
237+
for (auto& e : DecompressionQueue) {
238+
e.OnDestroyReadSession();
239+
}
227240
}
228241

229242

@@ -1565,6 +1578,7 @@ void TSingleClusterReadSessionImpl<UseMigrationProtocol>::OnDecompressionInfoDes
15651578

15661579
template<bool UseMigrationProtocol>
15671580
void TSingleClusterReadSessionImpl<UseMigrationProtocol>::OnDataDecompressed(i64 sourceSize, i64 estimatedDecompressedSize, i64 decompressedSize, size_t messagesCount, i64 serverBytesSize) {
1581+
15681582
TDeferredActions<UseMigrationProtocol> deferred;
15691583

15701584
Y_ABORT_UNLESS(DecompressionTasksInflight > 0);
@@ -2524,6 +2538,14 @@ void TDataDecompressionInfo<UseMigrationProtocol>::PlanDecompressionTasks(double
25242538
}
25252539
}
25262540

2541+
template <bool UseMigrationProtocol>
2542+
void TDataDecompressionInfo<UseMigrationProtocol>::OnDestroyReadSession()
2543+
{
2544+
for (auto& task : Tasks) {
2545+
task.ClearParent();
2546+
}
2547+
}
2548+
25272549
template<bool UseMigrationProtocol>
25282550
void TDataDecompressionEvent<UseMigrationProtocol>::TakeData(TIntrusivePtr<TPartitionStreamImpl<UseMigrationProtocol>> partitionStream,
25292551
TVector<typename TADataReceivedEvent<UseMigrationProtocol>::TMessage>& messages,
@@ -2673,19 +2695,23 @@ TDataDecompressionInfo<UseMigrationProtocol>::TDecompressionTask::TDecompression
26732695

26742696
template<bool UseMigrationProtocol>
26752697
void TDataDecompressionInfo<UseMigrationProtocol>::TDecompressionTask::operator()() {
2698+
auto parent = Parent;
2699+
if (!parent) {
2700+
return;
2701+
}
26762702
i64 minOffset = Max<i64>();
26772703
i64 maxOffset = 0;
2678-
const i64 partition_id = [this](){
2704+
const i64 partition_id = [parent](){
26792705
if constexpr (UseMigrationProtocol) {
2680-
return Parent->ServerMessage.partition();
2706+
return parent->ServerMessage.partition();
26812707
} else {
2682-
return Parent->ServerMessage.partition_session_id();
2708+
return parent->ServerMessage.partition_session_id();
26832709
}
26842710
}();
26852711
i64 dataProcessed = 0;
26862712
size_t messagesProcessed = 0;
26872713
for (const TMessageRange& messages : Messages) {
2688-
auto& batch = *Parent->ServerMessage.mutable_batches(messages.Batch);
2714+
auto& batch = *parent->ServerMessage.mutable_batches(messages.Batch);
26892715
for (size_t i = messages.MessageRange.first; i < messages.MessageRange.second; ++i) {
26902716
auto& data = *batch.mutable_message_data(i);
26912717

@@ -2696,7 +2722,7 @@ void TDataDecompressionInfo<UseMigrationProtocol>::TDecompressionTask::operator(
26962722

26972723
try {
26982724
if constexpr (UseMigrationProtocol) {
2699-
if (Parent->DoDecompress
2725+
if (parent->DoDecompress
27002726
&& data.codec() != Ydb::PersQueue::V1::CODEC_RAW
27012727
&& data.codec() != Ydb::PersQueue::V1::CODEC_UNSPECIFIED
27022728
) {
@@ -2706,7 +2732,7 @@ void TDataDecompressionInfo<UseMigrationProtocol>::TDecompressionTask::operator(
27062732
data.set_codec(Ydb::PersQueue::V1::CODEC_RAW);
27072733
}
27082734
} else {
2709-
if (Parent->DoDecompress
2735+
if (parent->DoDecompress
27102736
&& static_cast<Ydb::Topic::Codec>(batch.codec()) != Ydb::Topic::CODEC_RAW
27112737
&& static_cast<Ydb::Topic::Codec>(batch.codec()) != Ydb::Topic::CODEC_UNSPECIFIED
27122738
) {
@@ -2718,32 +2744,38 @@ void TDataDecompressionInfo<UseMigrationProtocol>::TDecompressionTask::operator(
27182744

27192745
DecompressedSize += data.data().size();
27202746
} catch (...) {
2721-
Parent->PutDecompressionError(std::current_exception(), messages.Batch, i);
2747+
parent->PutDecompressionError(std::current_exception(), messages.Batch, i);
27222748
data.clear_data(); // Free memory, because we don't count it.
27232749

2724-
if (auto session = Parent->CbContext->LockShared()) {
2750+
if (auto session = parent->CbContext->LockShared()) {
27252751
session->GetLog() << TLOG_INFO << "Error decompressing data: " << CurrentExceptionMessage();
27262752
}
27272753
}
27282754
}
27292755
}
2730-
if (auto session = Parent->CbContext->LockShared()) {
2756+
if (auto session = parent->CbContext->LockShared()) {
27312757
LOG_LAZY(session->GetLog(), TLOG_DEBUG, TStringBuilder() << "Decompression task done. Partition/PartitionSessionId: "
27322758
<< partition_id << " (" << minOffset << "-"
27332759
<< maxOffset << ")");
27342760
}
27352761
Y_ASSERT(dataProcessed == SourceDataSize);
27362762

2737-
Parent->OnDataDecompressed(SourceDataSize, EstimatedDecompressedSize, DecompressedSize, messagesProcessed);
2763+
parent->OnDataDecompressed(SourceDataSize, EstimatedDecompressedSize, DecompressedSize, messagesProcessed);
27382764

2739-
Parent->SourceDataNotProcessed -= dataProcessed;
2765+
parent->SourceDataNotProcessed -= dataProcessed;
27402766
Ready->Ready = true;
27412767

2742-
if (auto session = Parent->CbContext->LockShared()) {
2768+
if (auto session = parent->CbContext->LockShared()) {
27432769
session->GetEventsQueue()->SignalReadyEvents(PartitionStream);
27442770
}
27452771
}
27462772

2773+
template<bool UseMigrationProtocol>
2774+
void TDataDecompressionInfo<UseMigrationProtocol>::TDecompressionTask::ClearParent()
2775+
{
2776+
Parent = nullptr;
2777+
}
2778+
27472779
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
27482780
// TUserRetrievedEventsInfoAccumulator
27492781

@@ -2781,7 +2813,7 @@ void TDeferredActions<UseMigrationProtocol>::DeferReadFromProcessor(const typena
27812813
}
27822814

27832815
template<bool UseMigrationProtocol>
2784-
void TDeferredActions<UseMigrationProtocol>::DeferStartExecutorTask(const typename IAExecutor<UseMigrationProtocol>::TPtr& executor, typename IAExecutor<UseMigrationProtocol>::TFunction task) {
2816+
void TDeferredActions<UseMigrationProtocol>::DeferStartExecutorTask(const typename IAExecutor<UseMigrationProtocol>::TPtr& executor, typename IAExecutor<UseMigrationProtocol>::TFunction&& task) {
27852817
ExecutorsTasks.emplace_back(executor, std::move(task));
27862818
}
27872819

ydb/services/persqueue_v1/persqueue_ut.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -3376,6 +3376,54 @@ TPersQueueV1TestServer server{{.CheckACL=true, .NodeCount=1}};
33763376
DumpCounters("End");
33773377
}
33783378

3379+
Y_UNIT_TEST(NoDecompressionMemoryLeaks) {
3380+
3381+
NPersQueue::TTestServer server;
3382+
server.EnableLogs({ NKikimrServices::PQ_WRITE_PROXY, NKikimrServices::PQ_READ_PROXY});
3383+
server.AnnoyingClient->CreateTopic(DEFAULT_TOPIC_NAME, 1);
3384+
3385+
auto driver = server.AnnoyingClient->GetDriver();
3386+
auto decompressor = CreateThreadPoolExecutorWrapper(2);
3387+
3388+
NYdb::NPersQueue::TReadSessionSettings settings;
3389+
settings.ConsumerName("shared/user").AppendTopics(SHORT_TOPIC_NAME).ReadOriginal({"dc1"});
3390+
settings.DecompressionExecutor(decompressor);
3391+
settings.MaxMemoryUsageBytes(5_MB);
3392+
settings.Decompress(true);
3393+
3394+
auto reader = CreateReader(*driver, settings);
3395+
3396+
//
3397+
// there should be 1 TCreatePartitionStreamEvent events in the queue
3398+
//
3399+
{
3400+
auto msg = reader->GetEvent(true, 1);
3401+
UNIT_ASSERT(msg);
3402+
3403+
Cerr << ">>>> message: " << NYdb::NPersQueue::DebugString(*msg) << Endl;
3404+
3405+
auto ev = std::get_if<NYdb::NPersQueue::TReadSessionEvent::TCreatePartitionStreamEvent>(&*msg);
3406+
UNIT_ASSERT(ev);
3407+
3408+
ev->Confirm();
3409+
}
3410+
3411+
for (ui32 i = 0; i < 10; ++i) {
3412+
auto writer = CreateSimpleWriter(*driver, SHORT_TOPIC_NAME, TStringBuilder() << "source" << i);
3413+
3414+
std::string message(1_MB - 1_KB, 'x');
3415+
3416+
bool res = writer->Write(message, 1);
3417+
UNIT_ASSERT(res);
3418+
3419+
res = writer->Close(TDuration::Seconds(10));
3420+
UNIT_ASSERT(res);
3421+
}
3422+
3423+
decompressor->StartFuncs({0, 1, 2});
3424+
Sleep(TDuration::Seconds(1));
3425+
}
3426+
33793427
enum WhenTheTopicIsDeletedMode {
33803428
AFTER_WRITES,
33813429
AFTER_START_TASKS,

0 commit comments

Comments
 (0)