Skip to content

Commit 24ded03

Browse files
committed
Hold query caches in a WeakKeyMap
Followup: rails#52622 Avoid leaking query caches when a ConnectionPool is gargabe collected.
1 parent b64eadd commit 24ded03

File tree

2 files changed

+41
-41
lines changed

2 files changed

+41
-41
lines changed

activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,45 @@ def dirties_query_cache
118118
# * private methods that require being called in a +synchronize+ blocks
119119
# are now explicitly documented
120120
class ConnectionPool
121+
if ObjectSpace.const_defined?(:WeakKeyMap) # RUBY_VERSION >= 3.3
122+
WeakKeyMap = ::ObjectSpace::WeakKeyMap # :nodoc:
123+
else
124+
class WeakKeyMap # :nodoc:
125+
def initialize
126+
@map = ObjectSpace::WeakMap.new
127+
@values = nil
128+
@size = 0
129+
end
130+
131+
alias_method :clear, :initialize
132+
133+
def [](key)
134+
prune if @map.size != @size
135+
@map[key]
136+
end
137+
138+
def []=(key, value)
139+
@map[key] = value
140+
prune if @map.size != @size
141+
value
142+
end
143+
144+
def delete(key)
145+
if value = self[key]
146+
self[key] = nil
147+
prune
148+
end
149+
value
150+
end
151+
152+
private
153+
def prune(force = false)
154+
@values = @map.values
155+
@size = @map.size
156+
end
157+
end
158+
end
159+
121160
class Lease # :nodoc:
122161
attr_accessor :connection, :sticky
123162

@@ -145,45 +184,6 @@ def clear(connection)
145184
end
146185

147186
class LeaseRegistry # :nodoc:
148-
if ObjectSpace.const_defined?(:WeakKeyMap) # RUBY_VERSION >= 3.3
149-
WeakKeyMap = ::ObjectSpace::WeakKeyMap # :nodoc:
150-
else
151-
class WeakKeyMap # :nodoc:
152-
def initialize
153-
@map = ObjectSpace::WeakMap.new
154-
@values = nil
155-
@size = 0
156-
end
157-
158-
alias_method :clear, :initialize
159-
160-
def [](key)
161-
prune if @map.size != @size
162-
@map[key]
163-
end
164-
165-
def []=(key, value)
166-
@map[key] = value
167-
prune if @map.size != @size
168-
value
169-
end
170-
171-
def delete(key)
172-
if value = self[key]
173-
self[key] = nil
174-
prune
175-
end
176-
value
177-
end
178-
179-
private
180-
def prune(force = false)
181-
@values = @map.values
182-
@size = @map.size
183-
end
184-
end
185-
end
186-
187187
def initialize
188188
@mutex = Mutex.new
189189
@map = WeakKeyMap.new

activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ def clear_query_cache
166166
end
167167

168168
def query_cache
169-
key = :"active_record_query_cache_#{object_id}"
170-
ActiveSupport::IsolatedExecutionState[key] ||= Store.new(@query_cache_version, @query_cache_max_size)
169+
caches = ActiveSupport::IsolatedExecutionState[:active_record_query_caches] ||= ConnectionPool::WeakKeyMap.new
170+
caches[self] ||= Store.new(@query_cache_version, @query_cache_max_size)
171171
end
172172
end
173173

0 commit comments

Comments
 (0)