-
Notifications
You must be signed in to change notification settings - Fork 21.9k
Store query caches in IsolatedExecutionState to avoid memory bloat #52622
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
Fix: rails#52617 Closes: rails#52618 It isn't per say a leak because the connection reaper eventually prune these, and also it's not expected that new Threads are constantly making entries into that cache. But it's true that with Fiber it's probably a bit more common, and the default reaper frequency isn't adapted to clear this fast enough. So instead of waiting for the reaper to trigger, which may take a long time, we keep the caches in IsolatedExcutionState so that when the owning thread or fiber is garbage collected its cache is too. However since we need to be able to clear all threads caches, we keep a cache version on the pool, and bump it to invalidate all caches of a pool at once.
Also this makes me think we could actually eliminate the reaper thread. |
Store query caches in IsolatedExecutionState to avoid memory bloat
Hum, this seems to have introduced an issue with the PG test suite. It tend to run out of connection, It's not evident why just yet, but I suspect it's because we're now holding onto the pool from the query cache store. |
Followup: #52622 This reference causes connections to linger around longer on Rails CI. Instead we can simply share an atomic integer to bump the version. x
Followup: #52622 This reference causes connections to linger around longer on Rails CI. Instead we can simply share an atomic integer to bump the version. x
b64eadd improves that. Now one worry left however is that memory isn't reclaimed when a ConnectionPool is GCed, so if some users create lots of epehemeral pools, it could cause a leak. I'll see if I can fix that too. |
Followup: #52622 Avoid leaking query caches when a ConnectionPool is gargabe collected.
24ded03 will do. |
Followup: #52622 Avoid leaking query caches when a ConnectionPool is gargabe collected.
Fix: rails#52617 Followup: rails#52622 Previous fixes solved the memory issues, but our fallback implementation of WeakKeyMap actually have terrible performance, and I can't find a way to do it in a performent way. So instead we replace it by a specialized weak map that only accept Thread or Fiber as keys, and simple purge dead threads on insertion. This gives us reasonable performance on Ruby 3.1 and 3.2.
Followup: rails#52622 This reference causes connections to linger around longer on Rails CI. Instead we can simply share an atomic integer to bump the version. x
Followup: rails#52622 Avoid leaking query caches when a ConnectionPool is gargabe collected.
Fix: rails#52617 Followup: rails#52622 Previous fixes solved the memory issues, but our fallback implementation of WeakKeyMap actually have terrible performance, and I can't find a way to do it in a performent way. So instead we replace it by a specialized weak map that only accept Thread or Fiber as keys, and simple purge dead threads on insertion. This gives us reasonable performance on Ruby 3.1 and 3.2.
Fix: #52617
Closes: #52618
It isn't per say a leak because the connection reaper eventually prune these, and also it's not expected that new Threads are constantly making entries into that cache. But it's true that with Fiber it's probably a bit more common, and the default reaper frequency isn't adapted to clear this fast enough.
So instead of waiting for the reaper to trigger, which may take a long time, we keep the caches in
IsolatedExecutionState
so that when the owning thread or fiber is garbage collected its cache is too.However since we need to be able to clear all threads caches, we keep a cache version on the pool, and bump it to invalidate all caches of a pool at once.