File tree Expand file tree Collapse file tree 4 files changed +51
-11
lines changed
lib/active_record/connection_adapters Expand file tree Collapse file tree 4 files changed +51
-11
lines changed Original file line number Diff line number Diff line change 1+ * Ensure concurrent invocations of the connection reaper cannot allocate the
2+ same connection to two threads.
3+
4+ Fixes #25585 .
5+
6+ * Matthew Draper*
7+
8+
19## Rails 5.0.0 (June 30, 2016) ##
210
311* Inspecting an object with an associated array of over 10 elements no longer
Original file line number Diff line number Diff line change @@ -415,7 +415,10 @@ def disconnect(raise_on_acquisition_timeout = true)
415415 with_exclusively_acquired_all_connections ( raise_on_acquisition_timeout ) do
416416 synchronize do
417417 @connections . each do |conn |
418- checkin conn
418+ if conn . in_use?
419+ conn . steal!
420+ checkin conn
421+ end
419422 conn . disconnect!
420423 end
421424 @connections = [ ]
@@ -447,7 +450,10 @@ def clear_reloadable_connections(raise_on_acquisition_timeout = true)
447450 with_exclusively_acquired_all_connections ( raise_on_acquisition_timeout ) do
448451 synchronize do
449452 @connections . each do |conn |
450- checkin conn
453+ if conn . in_use?
454+ conn . steal!
455+ checkin conn
456+ end
451457 conn . disconnect! if conn . requires_reloading?
452458 end
453459 @connections . delete_if ( &:requires_reloading? )
@@ -556,17 +562,17 @@ def reap
556562 stale_connections = synchronize do
557563 @connections . select do |conn |
558564 conn . in_use? && !conn . owner . alive?
565+ end . each do |conn |
566+ conn . steal!
559567 end
560568 end
561569
562570 stale_connections . each do |conn |
563- synchronize do
564- if conn . active?
565- conn . reset!
566- checkin conn
567- else
568- remove conn
569- end
571+ if conn . active?
572+ conn . reset!
573+ checkin conn
574+ else
575+ remove conn
570576 end
571577 end
572578 end
Original file line number Diff line number Diff line change @@ -184,7 +184,30 @@ def schema_cache=(cache)
184184
185185 # this method must only be called while holding connection pool's mutex
186186 def expire
187- @owner = nil
187+ if in_use?
188+ if @owner != Thread . current
189+ raise ActiveRecordError , "Cannot expire connection, " <<
190+ "it is owned by a different thread: #{ @owner } . " <<
191+ "Current thread: #{ Thread . current } ."
192+ end
193+
194+ @owner = nil
195+ else
196+ raise ActiveRecordError , 'Cannot expire connection, it is not currently leased.'
197+ end
198+ end
199+
200+ # this method must only be called while holding connection pool's mutex (and a desire for segfaults)
201+ def steal! # :nodoc:
202+ if in_use?
203+ if @owner != Thread . current
204+ pool . send :remove_connection_from_thread_cache , self , @owner
205+
206+ @owner = Thread . current
207+ end
208+ else
209+ raise ActiveRecordError , 'Cannot steal connection, it is not currently leased.'
210+ end
188211 end
189212
190213 def unprepared_statement
Original file line number Diff line number Diff line change @@ -151,7 +151,7 @@ def test_reap_inactive
151151
152152 assert_equal 1 , active_connections ( @pool ) . size
153153 ensure
154- @pool . connections . each ( & : close)
154+ @pool . connections . each { | conn | conn . close if conn . in_use? }
155155 end
156156
157157 def test_remove_connection
@@ -432,6 +432,9 @@ def test_bang_versions_of_disconnect_and_clear_reloadable_connections_if_unable_
432432 Thread . new { @pool . send ( group_action_method ) } . join
433433 # assert connection has been forcefully taken away from us
434434 assert_not @pool . active_connection?
435+
436+ # make a new connection for with_connection to clean up
437+ @pool . connection
435438 end
436439 end
437440 end
You can’t perform that action at this time.
0 commit comments