mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #25707 from matthewd/double-reap
Don't reap connections that have already been reassigned
This commit is contained in:
commit
aeba05d389
4 changed files with 50 additions and 11 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
* Ensure concurrent invocations of the connection reaper cannot allocate the
|
||||||
|
same connection to two threads.
|
||||||
|
|
||||||
|
Fixes #25585.
|
||||||
|
|
||||||
|
*Matthew Draper*
|
||||||
|
|
||||||
* Inspecting an object with an associated array of over 10 elements no longer
|
* Inspecting an object with an associated array of over 10 elements no longer
|
||||||
truncates the array, preventing `inspect` from looping infinitely in some
|
truncates the array, preventing `inspect` from looping infinitely in some
|
||||||
cases.
|
cases.
|
||||||
|
|
|
@ -415,7 +415,10 @@ module ActiveRecord
|
||||||
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
||||||
synchronize do
|
synchronize do
|
||||||
@connections.each do |conn|
|
@connections.each do |conn|
|
||||||
|
if conn.in_use?
|
||||||
|
conn.steal!
|
||||||
checkin conn
|
checkin conn
|
||||||
|
end
|
||||||
conn.disconnect!
|
conn.disconnect!
|
||||||
end
|
end
|
||||||
@connections = []
|
@connections = []
|
||||||
|
@ -447,7 +450,10 @@ module ActiveRecord
|
||||||
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
||||||
synchronize do
|
synchronize do
|
||||||
@connections.each do |conn|
|
@connections.each do |conn|
|
||||||
|
if conn.in_use?
|
||||||
|
conn.steal!
|
||||||
checkin conn
|
checkin conn
|
||||||
|
end
|
||||||
conn.disconnect! if conn.requires_reloading?
|
conn.disconnect! if conn.requires_reloading?
|
||||||
end
|
end
|
||||||
@connections.delete_if(&:requires_reloading?)
|
@connections.delete_if(&:requires_reloading?)
|
||||||
|
@ -556,11 +562,12 @@ module ActiveRecord
|
||||||
stale_connections = synchronize do
|
stale_connections = synchronize do
|
||||||
@connections.select do |conn|
|
@connections.select do |conn|
|
||||||
conn.in_use? && !conn.owner.alive?
|
conn.in_use? && !conn.owner.alive?
|
||||||
|
end.each do |conn|
|
||||||
|
conn.steal!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
stale_connections.each do |conn|
|
stale_connections.each do |conn|
|
||||||
synchronize do
|
|
||||||
if conn.active?
|
if conn.active?
|
||||||
conn.reset!
|
conn.reset!
|
||||||
checkin conn
|
checkin conn
|
||||||
|
@ -569,7 +576,6 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def num_waiting_in_queue # :nodoc:
|
def num_waiting_in_queue # :nodoc:
|
||||||
@available.num_waiting
|
@available.num_waiting
|
||||||
|
|
|
@ -184,7 +184,30 @@ module ActiveRecord
|
||||||
|
|
||||||
# this method must only be called while holding connection pool's mutex
|
# this method must only be called while holding connection pool's mutex
|
||||||
def expire
|
def expire
|
||||||
|
if in_use?
|
||||||
|
if @owner != Thread.current
|
||||||
|
raise ActiveRecordError, "Cannot expire connection, " <<
|
||||||
|
"it is owned by a different thread: #{@owner}. " <<
|
||||||
|
"Current thread: #{Thread.current}."
|
||||||
|
end
|
||||||
|
|
||||||
@owner = nil
|
@owner = nil
|
||||||
|
else
|
||||||
|
raise ActiveRecordError, 'Cannot expire connection, it is not currently leased.'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# this method must only be called while holding connection pool's mutex (and a desire for segfaults)
|
||||||
|
def steal! # :nodoc:
|
||||||
|
if in_use?
|
||||||
|
if @owner != Thread.current
|
||||||
|
pool.send :remove_connection_from_thread_cache, self, @owner
|
||||||
|
|
||||||
|
@owner = Thread.current
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise ActiveRecordError, 'Cannot steal connection, it is not currently leased.'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unprepared_statement
|
def unprepared_statement
|
||||||
|
|
|
@ -151,7 +151,7 @@ module ActiveRecord
|
||||||
|
|
||||||
assert_equal 1, active_connections(@pool).size
|
assert_equal 1, active_connections(@pool).size
|
||||||
ensure
|
ensure
|
||||||
@pool.connections.each(&:close)
|
@pool.connections.each { |conn| conn.close if conn.in_use? }
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_remove_connection
|
def test_remove_connection
|
||||||
|
@ -432,6 +432,9 @@ module ActiveRecord
|
||||||
Thread.new { @pool.send(group_action_method) }.join
|
Thread.new { @pool.send(group_action_method) }.join
|
||||||
# assert connection has been forcefully taken away from us
|
# assert connection has been forcefully taken away from us
|
||||||
assert_not @pool.active_connection?
|
assert_not @pool.active_connection?
|
||||||
|
|
||||||
|
# make a new connection for with_connection to clean up
|
||||||
|
@pool.connection
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue