1
0
Fork 0
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:
Aaron Patterson 2012-02-16 14:33:12 -08:00
parent c84e4b5d4b
commit aaff1a4101
3 changed files with 73 additions and 14 deletions

View file

@ -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

View file

@ -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

View file

@ -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)