diff options
author | Matt Jones <al2o3cr@gmail.com> | 2014-12-23 09:54:52 -0500 |
---|---|---|
committer | Matt Jones <al2o3cr@gmail.com> | 2014-12-23 09:54:52 -0500 |
commit | 5e024070ab3766fada222053d1e0f1116aeb50a6 (patch) | |
tree | 2703a44afb53ae337eddd210323d3038ffb5baeb /activerecord/lib | |
parent | d9d865aa40b29b4b5aba71e9f6108eaab7206b1e (diff) | |
download | rails-5e024070ab3766fada222053d1e0f1116aeb50a6.tar.gz rails-5e024070ab3766fada222053d1e0f1116aeb50a6.tar.bz2 rails-5e024070ab3766fada222053d1e0f1116aeb50a6.zip |
Fix connection leak when a thread checks in additional connections.
The code in `ConnectionPool#release` assumed that a single thread only
ever holds a single connection, and thus that releasing a connection
only requires the owning thread_id.
There is a trivial counterexample to this assumption: code that checks
out additional connections from the pool in the same thread. For
instance:
connection_1 = ActiveRecord::Base.connection
connection_2 = ActiveRecord::Base.connection_pool.checkout
ActiveRecord::Base.connection_pool.checkin(connection_2)
connection_3 = ActiveRecord::Base.connection
At this point, connection_1 has been removed from the
`@reserved_connections` hash, causing a NEW connection to be returned as
connection_3 and the loss of any tracking info on connection_1. As long
as the thread in this example lives, connection_1 will be inaccessible
and un-reapable. If this block of code runs more times than the size of
the connection pool in a single thread, every subsequent connection
attempt will timeout, as all of the available connections have been
leaked.
Reverts parts of 9e457a8654fa89fe329719f88ae3679aefb21e56 and
essentially all of 4367d2f05cbeda855820e25a08353d4b7b3457ac
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 0fa00d03a3..3968b90341 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -363,7 +363,7 @@ module ActiveRecord conn.expire end - release owner + release conn, owner @available.add conn end @@ -376,7 +376,7 @@ module ActiveRecord @connections.delete conn @available.delete conn - release conn.owner + release conn, conn.owner @available.add checkout_new_connection if @available.any_waiting? end @@ -424,10 +424,12 @@ module ActiveRecord end end - def release(owner) + def release(conn, owner) thread_id = owner.object_id - @reserved_connections.delete thread_id + if @reserved_connections[thread_id] == conn + @reserved_connections.delete thread_id + end end def new_connection |