Skip to content

Commit 034c143

Browse files
MONGOID-5417 Fix memory leak when call 'with' (#5409)
1 parent 4ab8851 commit 034c143

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

lib/mongoid/persistence_context.rb

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ class << self
172172
#
173173
# @return [ Mongoid::PersistenceContext ] The persistence context for the object.
174174
def set(object, options_or_context)
175-
key = "[mongoid][#{object.object_id}]:context"
176-
existing_context = Thread.current[key]
175+
existing_context = get_context(object)
177176
existing_options = if existing_context
178177
existing_context.options
179178
else
@@ -184,7 +183,7 @@ def set(object, options_or_context)
184183
end
185184
new_options = existing_options.merge(options_or_context)
186185
context = PersistenceContext.new(object, new_options)
187-
Thread.current[key] = context
186+
store_context(object, context)
188187
end
189188

190189
# Get the persistence context for a particular class or model instance.
@@ -196,7 +195,7 @@ def set(object, options_or_context)
196195
#
197196
# @return [ Mongoid::PersistenceContext ] The persistence context for the object.
198197
def get(object)
199-
Thread.current["[mongoid][#{object.object_id}]:context"]
198+
get_context(object)
200199
end
201200

202201
# Clear the persistence context for a particular class or model instance.
@@ -215,7 +214,44 @@ def clear(object, cluster = nil, original_context = nil)
215214
end
216215
end
217216
ensure
218-
Thread.current["[mongoid][#{object.object_id}]:context"] = original_context
217+
store_context(object, original_context)
218+
end
219+
220+
private
221+
222+
# Key to store persistence contexts in the thread local storage.
223+
#
224+
# @api private
225+
PERSISTENCE_CONTEXT_KEY = :"[mongoid]:persistence_context"
226+
227+
# Get the persistence context for a given object from the thread local
228+
# storage.
229+
#
230+
# @param [ Object ] object Object to get the persistance context for.
231+
#
232+
# @return [ Mongoid::PersistenceContext | nil ] The persistence context
233+
# for the object if previously stored, otherwise nil.
234+
#
235+
# @api private
236+
def get_context(object)
237+
Thread.current[PERSISTENCE_CONTEXT_KEY] ||= {}
238+
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id]
239+
end
240+
241+
# Store persistence context for a given object in the thread local
242+
# storage.
243+
#
244+
# @param [ Object ] object Object to store the persistance context for.
245+
# @param [ Mongoid::PersistenceContext ] context Context to store
246+
#
247+
# @api private
248+
def store_context(object, context)
249+
if context.nil?
250+
Thread.current[PERSISTENCE_CONTEXT_KEY]&.delete(object.object_id)
251+
else
252+
Thread.current[PERSISTENCE_CONTEXT_KEY] ||= {}
253+
Thread.current[PERSISTENCE_CONTEXT_KEY][object.object_id] = context
254+
end
219255
end
220256
end
221257
end

0 commit comments

Comments
 (0)