Skip to content

Conversation

byroot
Copy link
Member

@byroot byroot commented Aug 16, 2024

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.

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.
@byroot
Copy link
Member Author

byroot commented Aug 16, 2024

Also this makes me think we could actually eliminate the reaper thread.

@byroot byroot merged commit ffc580a into rails:main Aug 16, 2024
2 of 3 checks passed
@byroot byroot deleted the query-cache-isolated-context branch August 16, 2024 10:50
byroot added a commit that referenced this pull request Aug 16, 2024
Store query caches in IsolatedExecutionState to avoid memory bloat
@byroot
Copy link
Member Author

byroot commented Aug 16, 2024

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.

byroot added a commit that referenced this pull request Aug 16, 2024
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
byroot added a commit that referenced this pull request Aug 16, 2024
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
@byroot
Copy link
Member Author

byroot commented Aug 16, 2024

I suspect it's because we're now holding onto the pool from the query cache store.

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.

byroot added a commit that referenced this pull request Aug 16, 2024
Followup: #52622

Avoid leaking query caches when a ConnectionPool is gargabe collected.
@byroot
Copy link
Member Author

byroot commented Aug 16, 2024

24ded03 will do.

byroot added a commit that referenced this pull request Aug 16, 2024
Followup: #52622

Avoid leaking query caches when a ConnectionPool is gargabe collected.
byroot added a commit to byroot/rails that referenced this pull request Aug 16, 2024
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.
DanielaVelasquez pushed a commit to DanielaVelasquez/rails that referenced this pull request Oct 3, 2024
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
DanielaVelasquez pushed a commit to DanielaVelasquez/rails that referenced this pull request Oct 3, 2024
Followup: rails#52622

Avoid leaking query caches when a ConnectionPool is gargabe collected.
DanielaVelasquez pushed a commit to DanielaVelasquez/rails that referenced this pull request Oct 3, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Memory leak and performance degradation with IsolatedExecutionState == :fiber
1 participant