fix(helper): don't let the accept deadline bound the whole transfer (#44) - #45
Merged
talmacschen-arch merged 2 commits intoJul 14, 2026
Conversation
…loudberry-contrib#44) ConcurrentServer.serve() ran an unbounded Accept() loop that lives for the entire transfer. After all expected clients (--client-numbers) connect, the loop blocks on Accept() again; the listener's absolute 600s deadline set in ServerBase.Start() then fires mid-transfer, turning "no more inbound connections" (a normal state) into a fatal error. This caps the total transfer time of a single table for ExtDestLtCopy + push, so any table whose data takes longer than ~10 minutes to move is torn down -- surfacing as SQLSTATE 22P04 / "could not write to COPY program: Broken pipe", or, depending on the accept/stream race, an indefinite hang with no error surfaced to either side. Make serve() accept-count aware: stop accepting once numConn connections are in, then close the listener so the in-flight data connections stream to completion with no deadline over them. A timeout/error before all expected clients connect is still treated as fatal, and the error path now returns instead of continuing so a tripped deadline can no longer busy-spin. Only affects ConcurrentServer (ExtDestLtCopy + push). OneTimeServer (CopyOnMaster/CopyOnSegment/ExtDestGeCopy and all pull-mode senders) closes its listener after a single accept and is unchanged.
📝 WalkthroughWalkthrough
ChangesServer acceptance lifecycle
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@helper/server.go`:
- Line 159: Update the cleanup path containing t.listener.Close() to handle its
returned error instead of discarding it. Match the established approach in
helper/one_time_server.go by logging and surfacing listener shutdown failures
while preserving the existing cleanup flow.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 58f05fb0-c7d5-47c5-be1d-d81274c7de4a
📒 Files selected for processing (1)
helper/server.go
…y-contrib#44) Address review feedback: surface a listener Close() failure instead of silently discarding it. Log-only on purpose -- all expected clients are already connected and streaming by this point, so failing the transfer here (as one_time_server.go does on its pre-stream close) would reintroduce the spurious-teardown class of bug that cloudberry-contrib#44 fixes.
leaocx
approved these changes
Jul 14, 2026
leaocx
left a comment
Collaborator
There was a problem hiding this comment.
LGTM. Precise fix with solid validation.
- Bounded accept loop correctly prevents the listener deadline from capping the entire transfer
continue→returnon error path eliminates busy-spin- Closing the listener does not affect already-established data connections
- Log-only (no
setError) on listener-close failure is the right call — avoids reintroducing spurious teardown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix #44
Change logs
ConcurrentServer.serve()runs an unboundedAccept()loop that lives for the whole transfer. The listener's absolute 600 s deadline (set inServerBase.Start()) therefore bounds the total transfer time of a single table, not just the accept phase: once all expected clients (--client-numbers) have connected, the loop blocks onAccept()again, and at start + 600 s that still-blockedAccept()returnsi/o timeout→setError→ the transfer is torn down. This is confined toExtDestLtCopy+ push (destination has fewer segments than source), i.e. any table whose data takes longer than ~10 minutes to move. See #44 for the full root-cause analysis.Fix: make
serve()accept-count aware — stop accepting oncenumConnconnections are in, thenClose()the listener so the in-flight data connections stream to completion with no listener deadline over them. A timeout/error before all expected clients have connected is still fatal (a client genuinely failed to connect), and the error path nowreturns instead ofcontinue-ing, so a tripped deadline can no longer busy-spin flooding the log.Scope: only
ConcurrentServer(ExtDestLtCopy+ push) is affected.OneTimeServer(CopyOnMaster/CopyOnSegment/ExtDestGeCopyand all pull-mode senders) closes its listener after a singleAccept()and is unchanged — so--connection-mode=pullwas, and remains, unaffected.Validation
On a 16 → 8 segment setup (source 16 primaries, destination 8) copying a single large unpartitioned table (TPC-DS
store_sales, 1 TB scale) in default push mode:could not write to COPY program: Broken pipeon the source;22P04/25M01on the destination) and, depending on timing, as an indefinite hang with no error surfaced to either side.successfully copied 1 tables, total elapsed 36m52s), with zeroListener.Accept() ... i/o timeouton the destination helpers.The
helperpackage currently has no unit tests; happy to add a focusedserve()test (acceptnumConn→ listener closed,Err()==nil, no timeout; fewer thannumConnbefore the deadline →Err()!=nil, no busy-spin) if maintainers would like one in this PR.Summary by CodeRabbit