diff options
author | Matthew Draper <matthew@trebex.net> | 2017-11-25 17:53:57 +1030 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-25 17:53:57 +1030 |
commit | 3313912de1814ff4698e050c414940f004af93b0 (patch) | |
tree | 0b79a26d9598bab22c4a152ccbe56862d7e2bcfc /activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb | |
parent | 2ec9c532cbbdbe636a17411db3f9de47ca6a81c1 (diff) | |
parent | f32cff5563f2188e657aa2fd9f8513f0da4a49ca (diff) | |
download | rails-3313912de1814ff4698e050c414940f004af93b0.tar.gz rails-3313912de1814ff4698e050c414940f004af93b0.tar.bz2 rails-3313912de1814ff4698e050c414940f004af93b0.zip |
Merge pull request #31173 from matthewd/connection-fork-safety
Improve AR connection fork safety
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb | 35 |
1 files changed, 35 insertions, 0 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 6c06f67239..c5013dc1ee 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -447,6 +447,21 @@ module ActiveRecord disconnect(false) end + # Discards all connections in the pool (even if they're currently + # leased!), along with the pool itself. Any further interaction with the + # pool (except #spec and #schema_cache) is undefined. + # + # See AbstractAdapter#discard! + def discard! # :nodoc: + synchronize do + return if @connections.nil? # already discarded + @connections.each do |conn| + conn.discard! + end + @connections = @available = @thread_cached_conns = nil + end + end + # Clears the cache which maps classes and re-connects connections that # require reloading. # @@ -863,11 +878,31 @@ module ActiveRecord # about the model. The model needs to pass a specification name to the handler, # in order to look up the correct connection pool. class ConnectionHandler + def self.unowned_pool_finalizer(pid_map) # :nodoc: + lambda do |_| + discard_unowned_pools(pid_map) + end + end + + def self.discard_unowned_pools(pid_map) # :nodoc: + pid_map.each do |pid, pools| + pools.values.compact.each(&:discard!) unless pid == Process.pid + end + end + def initialize # These caches are keyed by spec.name (ConnectionSpecification#name). @owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h, k| + # Discard the parent's connection pools immediately; we have no need + # of them + ConnectionHandler.discard_unowned_pools(h) + h[k] = Concurrent::Map.new(initial_capacity: 2) end + + # Backup finalizer: if the forked child never needed a pool, the above + # early discard has not occurred + ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool) end def connection_pool_list |