aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
diff options
context:
space:
mode:
authorMatthew Draper <matthew@trebex.net>2017-11-17 21:55:39 +1030
committerMatthew Draper <matthew@trebex.net>2017-11-18 13:47:51 +1030
commitf32cff5563f2188e657aa2fd9f8513f0da4a49ca (patch)
treea3ebdf2ba035c8c23e7a67d2e62b78669b471a4d /activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
parentc39ed435eb578c79867552c66da7eeb035fa58ad (diff)
downloadrails-f32cff5563f2188e657aa2fd9f8513f0da4a49ca.tar.gz
rails-f32cff5563f2188e657aa2fd9f8513f0da4a49ca.tar.bz2
rails-f32cff5563f2188e657aa2fd9f8513f0da4a49ca.zip
Improve AR connection fork safety
Use whatever adapter-provided means we have available to ensure forked children don't send quit/shutdown/goodbye messages to the server on connections that belonged to their parent.
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.rb35
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 0759f4d2b3..0f39c077c9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -450,6 +450,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.
#
@@ -866,11 +881,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