-
Notifications
You must be signed in to change notification settings - Fork 2.5k
fix(pool): correct turn management in putIdleConn to prevent connection leaks #3626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit fixes a critical race condition where freeTurn() could be
called twice in the connection pool's queuedNewConn flow, causing turn
counter inconsistency.
Problem:
- When a new connection creation failed in queuedNewConn, both the
defer handler and the dialing goroutine could call freeTurn()
- This led to turn counter underflow and queue length inconsistency
Solution:
- Modified putIdleConn to return a boolean indicating whether the
caller needs to call freeTurn()
- Returns true: connection was put back to pool, caller must free turn
- Returns false: connection was delivered to a waiting request,
turn will be freed by the receiving goroutine
- Updated queuedNewConn to only call freeTurn() when putIdleConn
returns true
- Improved error handling flow in the dialing goroutine
Changes:
- putIdleConn now returns bool instead of void
- Added comprehensive documentation for putIdleConn behavior
- Refactored error handling in queuedNewConn goroutine
- Updated test cases to reflect correct turn state expectations
This ensures each turn is freed exactly once, preventing resource
leaks and maintaining correct queue state.
|
Hi, I’m Jit, a friendly security platform designed to help developers build secure applications from day zero with an MVS (Minimal viable security) mindset. In case there are security findings, they will be communicated to you as a comment inside the PR. Hope you’ll enjoy using Jit. Questions? Comments? Want to learn more? Get in touch with us. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes a critical bug in the connection pool's turn management system that could cause turn leaks and incorrect semaphore accounting. The fix ensures proper transfer of turn ownership when connections are delivered to waiting goroutines.
Key changes:
- Modified
putIdleConnto return a boolean indicating whether the caller should free the turn - Updated
queuedNewConnlogic to conditionally free turns based onputIdleConn's return value - Corrected test assertions to reflect the proper turn ownership semantics
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| internal/pool/pool.go | Modified putIdleConn to return boolean for turn management, refactored queuedNewConn error handling to properly free turns only when connections are added to idle pool rather than delivered to waiting goroutines |
| internal/pool/pool_test.go | Updated test expectations to correctly validate that turns are held during connection delivery and only freed after the receiving goroutine completes its own dial or returns the connection via Put() |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
I do personally like this approach better, it is easier to follow and read. Thank you @cyningsun. Will let @ofekshenawa decide which one to include. Could you please sync the rest of the changes (the context calculation and the tests). |
e6b0ac5 to
8e24b4a
Compare
Synced from https://github.com/redis/go-redis/tree/ndyakov/freeturn-fix Changes include: - Add comprehensive tests for double freeTurn bug detection - Improve context timeout calculation using min(remaining time, DialTimeout) - Prevent goroutines from waiting longer than necessary Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
8e24b4a to
be8071f
Compare
…on leaks (#3626) * fix(pool): prevent double freeTurn in queuedNewConn This commit fixes a critical race condition where freeTurn() could be called twice in the connection pool's queuedNewConn flow, causing turn counter inconsistency. Problem: - When a new connection creation failed in queuedNewConn, both the defer handler and the dialing goroutine could call freeTurn() - This led to turn counter underflow and queue length inconsistency Solution: - Modified putIdleConn to return a boolean indicating whether the caller needs to call freeTurn() - Returns true: connection was put back to pool, caller must free turn - Returns false: connection was delivered to a waiting request, turn will be freed by the receiving goroutine - Updated queuedNewConn to only call freeTurn() when putIdleConn returns true - Improved error handling flow in the dialing goroutine Changes: - putIdleConn now returns bool instead of void - Added comprehensive documentation for putIdleConn behavior - Refactored error handling in queuedNewConn goroutine - Updated test cases to reflect correct turn state expectations This ensures each turn is freed exactly once, preventing resource leaks and maintaining correct queue state. * fix: sync double freeturn bug fix and context calculation from upstream Synced from https://github.com/redis/go-redis/tree/ndyakov/freeturn-fix Changes include: - Add comprehensive tests for double freeTurn bug detection - Improve context timeout calculation using min(remaining time, DialTimeout) - Prevent goroutines from waiting longer than necessary Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Nedyalko Dyakov <nedyalko.dyakov@gmail.com> Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Bug Description
A critical defect was identified in the connection pool's turn management mechanism within the
putIdleConnmethod, breaking the fundamental 1:1 correspondence between turns and connections. ( Introduced by #3518)Root Cause Analysis
Turn Release Scenarios (Expected Behavior):
The Defect: In
putIdleConn, when delivering connections to waiting goroutines, the turn was incorrectly released immediately instead of being transferred to the receiving goroutine for proper release viaPut.Test Gap: The test case "should not leak turn when delivering connection via putIdleConn" contained flawed assertions due to misunderstanding of turn ownership mechanism in the context of connection delivery, failing to detect the leakage.
Relationship to #3625:
This PR addresses the same turn management issue identified in #3625. I want to acknowledge and thank @ndyakov for:
This PR offers an additional perspective on the solution, focusing specifically on turn ownership semantics. It's intended to provide more options for review and discussion as we work towards the best resolution for this issue.
Note to Reviewers:
This PR is optional and can be closed if #3625 covers all needs. It's just here to offer another perspective.