mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
database connections are automatically established after forking.
Connection pools are 1:1 with pids.
This commit is contained in:
parent
c84e4b5d4b
commit
aaff1a4101
3 changed files with 73 additions and 14 deletions
|
@ -328,16 +328,18 @@ module ActiveRecord
|
|||
# ActiveRecord::Base.connection_handler. Active Record models use this to
|
||||
# determine that connection pool that they should use.
|
||||
class ConnectionHandler
|
||||
attr_reader :connection_pools
|
||||
|
||||
def initialize(pools = {})
|
||||
def initialize(pools = Hash.new { |h,k| h[k] = {} })
|
||||
@connection_pools = pools
|
||||
@class_to_pool = {}
|
||||
@class_to_pool = Hash.new { |h,k| h[k] = {} }
|
||||
end
|
||||
|
||||
def connection_pools
|
||||
@connection_pools[$$]
|
||||
end
|
||||
|
||||
def establish_connection(name, spec)
|
||||
@connection_pools[spec] ||= ConnectionAdapters::ConnectionPool.new(spec)
|
||||
@class_to_pool[name] = @connection_pools[spec]
|
||||
set_pool_for_spec spec, ConnectionAdapters::ConnectionPool.new(spec)
|
||||
set_class_to_pool name, connection_pools[spec]
|
||||
end
|
||||
|
||||
# Returns true if there are any active connections among the connection
|
||||
|
@ -350,21 +352,21 @@ module ActiveRecord
|
|||
# and also returns connections to the pool cached by threads that are no
|
||||
# longer alive.
|
||||
def clear_active_connections!
|
||||
@connection_pools.each_value {|pool| pool.release_connection }
|
||||
connection_pools.each_value {|pool| pool.release_connection }
|
||||
end
|
||||
|
||||
# Clears the cache which maps classes.
|
||||
def clear_reloadable_connections!
|
||||
@connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
|
||||
connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
|
||||
end
|
||||
|
||||
def clear_all_connections!
|
||||
@connection_pools.each_value {|pool| pool.disconnect! }
|
||||
connection_pools.each_value {|pool| pool.disconnect! }
|
||||
end
|
||||
|
||||
# Verify active connections.
|
||||
def verify_active_connections! #:nodoc:
|
||||
@connection_pools.each_value {|pool| pool.verify_active_connections! }
|
||||
connection_pools.each_value {|pool| pool.verify_active_connections! }
|
||||
end
|
||||
|
||||
# Locate the connection of the nearest super class. This can be an
|
||||
|
@ -388,21 +390,53 @@ module ActiveRecord
|
|||
# can be used as an argument for establish_connection, for easily
|
||||
# re-establishing the connection.
|
||||
def remove_connection(klass)
|
||||
pool = @class_to_pool.delete(klass.name)
|
||||
pool = class_to_pool.delete(klass.name)
|
||||
return nil unless pool
|
||||
|
||||
@connection_pools.delete pool.spec
|
||||
connection_pools.delete pool.spec
|
||||
pool.automatic_reconnect = false
|
||||
pool.disconnect!
|
||||
pool.spec.config
|
||||
end
|
||||
|
||||
def retrieve_connection_pool(klass)
|
||||
pool = @class_to_pool[klass.name]
|
||||
pool = get_pool_for_class klass.name
|
||||
return pool if pool
|
||||
return nil if ActiveRecord::Model == klass
|
||||
retrieve_connection_pool klass.active_record_super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def class_to_pool
|
||||
@class_to_pool[$$]
|
||||
end
|
||||
|
||||
def set_pool_for_spec(spec, pool)
|
||||
@connection_pools[$$][spec] = pool
|
||||
end
|
||||
|
||||
def set_class_to_pool(name, pool)
|
||||
@class_to_pool[$$][name] = pool
|
||||
pool
|
||||
end
|
||||
|
||||
def get_pool_for_class(klass)
|
||||
@class_to_pool[$$].fetch(klass) {
|
||||
c_to_p = @class_to_pool.values.find { |class_to_pool|
|
||||
class_to_pool[klass]
|
||||
}
|
||||
|
||||
if c_to_p
|
||||
pool = c_to_p[klass]
|
||||
pool = ConnectionAdapters::ConnectionPool.new pool.spec
|
||||
set_pool_for_spec pool.spec, pool
|
||||
set_class_to_pool klass, pool
|
||||
else
|
||||
set_class_to_pool klass, nil
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class ConnectionManagement
|
||||
|
|
|
@ -1238,7 +1238,11 @@ module ActiveRecord
|
|||
# prepared statements whose return value may have changed is
|
||||
# FEATURE_NOT_SUPPORTED. Check here for more details:
|
||||
# http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
||||
code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
|
||||
begin
|
||||
code = e.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
|
||||
rescue
|
||||
raise e
|
||||
end
|
||||
if FEATURE_NOT_SUPPORTED == code
|
||||
@statements.delete sql_key(sql)
|
||||
retry
|
||||
|
|
|
@ -26,6 +26,27 @@ module ActiveRecord
|
|||
assert ActiveRecord::Base.connection_handler.active_connections?
|
||||
end
|
||||
|
||||
def test_connection_pool_per_pid
|
||||
return skip('must support fork') unless Process.respond_to?(:fork)
|
||||
|
||||
object_id = ActiveRecord::Base.connection.object_id
|
||||
|
||||
rd, wr = IO.pipe
|
||||
|
||||
pid = fork {
|
||||
rd.close
|
||||
wr.write Marshal.dump ActiveRecord::Base.connection.object_id
|
||||
wr.close
|
||||
exit!
|
||||
}
|
||||
|
||||
wr.close
|
||||
|
||||
Process.waitpid pid
|
||||
assert_not_equal object_id, Marshal.load(rd.read)
|
||||
rd.close
|
||||
end
|
||||
|
||||
def test_app_delegation
|
||||
manager = ConnectionManagement.new(@app)
|
||||
|
||||
|
|
Loading…
Reference in a new issue