Repository navigation
Problem: multipart send drops unsent frames - #689
Conversation
Solution: remove each part only after a successful send and test retry behavior after EAGAIN, backpressure and EFSM. Fixes zeromq#659.
|
Note: There is also |
Solution: format the existing static_assert and cover empty sends and caller SNDMORE through both flag overloads. Keep the corrected send loop after peer-close testing exposed an abort in direct helper delegation.
|
Thanks for the suggestion. I tried it, but with libzmq 4.3.5 an inproc PULL peer disconnecting during a large multipart send triggered send_multipart's assertion. The current loop returned false in the same test, so I've kept it for now. I've also added empty-message/SNDMORE coverage and fixed the formatting check. |
Coverage Report for CI Build 37292403362Warning No base build found for commit Coverage: 86.116%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
Fixes #659.
Problem
multipart_t::send()removes a frame before attempting to send it. If the first send returns EAGAIN, the multipart loses that frame and a retry sends an incomplete message. A thrownzmq::error_talso destroys the removed frame.Solution
Send the front frame in place and remove it only after the send succeeds. The failed frame and remaining unsent parts stay available. There is no copying, catch-all handler, or API change.
The follow-up adds coverage for empty multipart messages and caller-supplied SNDMORE through both flag overloads, and formats the existing static_assert block that stopped CI. The production send loop remains unchanged from the initial PR.
I evaluated delegating to
send_multipart, but did not keep that change: with libzmq 4.3.5, closing an inproc PULL peer during a large multipart PUSH send caused the helper'sassert(it == begin(msgs))to abort. In this environment, the current loop instead returned false. The sockets were each used only by their owning thread; no send result or errno was injected. This is an observed disconnect case, not a claim about every libzmq version or transport. After partial progress, the original full message is not automatically reconstructible; retaining the unsent suffix does not promise a transparent full-message retry.Validation
Freshly tested on Linux x86_64, GCC 14.2, libzmq 4.3.5 (DRAFTS enabled, CURVE disabled), and Catch2 3.5.3:
7f0530688804c2b5b6b0d985773405593fd25ca8and pass with both the current PR header and the follow-up: EAGAIN/repeated retry, high-water-mark drain/retry, and EFSM recoverydetect_leaks=0is required because the default LeakSanitizer run fails in this container.cpp/.hppformatting passes clang-format 20.1.8;git diff --checkpasses. CI's exact Ubuntu clang-format 20.1.2 build was not available locallyFull-suite limitations were compared with the same final test source on all three production headers. In C++14, current PR and follow-up have 159/179 passing tests, versus upstream 156/179. In C++20, current PR and follow-up have 160/182, versus upstream 157/182. The only removed failures are the three regressions. The same remaining 20/22 tests abort at libzmq's
getifaddrscall with EPERM. No full-suite green result, remote CI success, old-MSVC validation, other operating-system coverage, or leak-check success is claimed.