-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[needs testing] fix Pool
to reduce possibility of "leaking" connections
#84
Conversation
9cec6d7
to
c686eed
Compare
@ianthetechie do you mind trying this branch with your testing setup to see if it still leaks connections? |
c686eed
to
d05a29b
Compare
Pool
to reduce possibility of "leaking" connectionsPool
to reduce possibility of "leaking" connections
252da8c
to
90cc737
Compare
@abonander thanks a bunch! I will test it out this afternoon (KST). |
Unfortunately it doesn't yet pass my own test with |
Can you post your test code? I'm kinda flying blind otherwise. |
I can't post it all of it unfortunately due to licensing, but I'll try to extract an MVP to reproduce the bug for you. |
A minimal reproduction would be very helpful, thank you. |
@ianthetechie any luck with that repro? |
Hey @abonander, sorry it took me a bit to get around to this as Friday was the Lunar New Year holiday here. Here's a repository with instructions for reproducing the issue: https://github.com/ianthetechie/sqlx-leak-repro. I will also add that this PR does improve things. It appears to address at least one of the data race/state issues, but there seem to be more. It's just harder to reproduce now. |
No worries, I just wanted to make sure you didn't forget. |
90cc737
to
8c5082b
Compare
I had a look through the repro project and I'm not sure what it's doing with Are we certain that it's not Hyper leaking the futures for abandoned connections? That might explain why we didn't see the same behaviors with Tide and |
now uses RAII guards to control `SharedPool::size`
add `Pool::is_closed()`
8c5082b
to
ab2ce76
Compare
I was able to repro with your project, and I confirmed it's not Hyper leaking futures by adding an RAII guard to the handler that counts the number of times it's leaked in a |
I think I've nailed down the source of this bug but I'll have to play with some refactors to see if my guess is correct.
The fix, I think, would be to always push connections to the idle queue, and then try to find a waiter to wake up. That way the connection always remains tracked by the pool. Though it would not completely fix this race, neither
Additionally, we don't have a way to wake a waiter if the size drops below the max, which means connections can time out waiting on the queue even though they have the right-of-way to open a new connection. I'll be fixing both of these. |
@ianthetechie I believe I have fixed the problem. At the beginning of the far right terminal window you can see the results of starting and stopping The middle command completes in normal time if I'm not running If you don't mind, give this branch a try again and see if you get the same results. |
Great job @abonander. I played with it myself and I don't see any obvious issues. Merging as its certainly an improvement and I love how we have a couple of good smoke tests in-crate now. In the future I'd love to setup a benchmark to validate some of our assumptions about performance. |
Hey guys! Thanks so much for working through this with me! I admit the repro and description wasn't as clear cut as I would have liked... I've tested it on both my repro project and our "real world" codebase and it looks like it's working as intended. Incidentally it seems to perform a bit better. Also the other issue I noted in my repro project (some sort of incorrect recycling causing bad behavior when connections are dropped and not tested by the pool) seems to be fixed. |
pub(in crate::pool) struct DecrementSizeGuard<'a> { | ||
size: &'a AtomicU32, | ||
waiters: &'a SegQueue<Waker>, | ||
dropped: bool, |
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.
I love this solution :) But is a dropped flag really necessary? I didn't think it was possible to drop something twice in Rust (I don't think you can call the .drop()
method manually, and the prelude drop
function borrows its input, so attempts to reference it further wouldn't compile).
Now uses RAII guards to control
SharedPool::size
so that it cannot fall out-of-sync.Also added smoke tests for
PgPool
andMySqlPool
that try to stress it a little and also dropacquire()
futures to see if they can trigger bugs with cancellation.closes #83