Repository navigation
[fix][broker] Prevent payload leaks when message serialization fails - #27208
Denovo1998 wants to merge 3 commits into
Conversation
merlimat
left a comment
There was a problem hiding this comment.
Thanks. The ownership gap is real: the pair only takes over the payload reference once ByteBufPair.get returns, and the dispatch catch block only releases the entry's own reference. The test reproduces it for the right reason. One optional simplification inline.
codelipenghui
left a comment
There was a problem hiding this comment.
Reviewed 10c49ce. No actionable findings identified within the reviewed scope.
The construction-only cleanup balances the retained payload while preserving Netty's ownership after write handoff. All 6 PulsarCommandSenderImplTest cases and 3 DispatchSmallMessagesCoalescingTest cases passed, with no failures or skips and retries disabled. Temporarily removing the cleanup reproduced the first-message payload leak (refCnt 1 instead of 0); fail-fast skipped the midpoint baseline case. The exact PR code was restored afterward.
Validation used injected allocation failure, not real memory exhaustion or end-to-end reconnect/redelivery.
Motivation
PulsarCommandSenderImplretains a large message's payload before building its command. If serialization fails before aByteBufPairis returned, dispatch cleanup closes the connection and releases the entry, but leaves the extra payload reference behind. The buffer can remain allocated after the dispatch has failed.This ownership gap predates #26926. The header cleanup in #26492 does not release the caller's retained payload reference.
Modifications
PulsarCommandSenderImplTestwith failures on the first large message and midway through a mixed dispatch, plus successful-write and closed-channel controls.Verifying this change
This change added tests and can be verified as follows:
refCnt == 1after the header and entry are released. The other four sender cases pass.PulsarCommandSenderImplTestpasses all 6 cases andDispatchSmallMessagesCoalescingTestpasses all 3 cases, with zero failures or skips and retries disabled.quickCheckpasses across the repository.The failure tests inject an
OutOfMemoryErroronly atByteBufPair.get, since the static allocator/recycler has no local failure hook. The sender,ServerCnx, serializer, entries, buffers, and Netty write handling use their real implementations. The tests do not exhaust JVM memory or validate end-to-end reconnect/redelivery after this failure.Does this pull request potentially affect one of the following parts: