Rename the classes

This commit renames `RoleManager` -> `PoolManager` and `Role` ->
`PoolConfig`.

Once we introduced the previous commit, and looking at the existing
code, it's clearer that `Role` and `RoleManager` are not the right names
for these.

Since this PR moves away from swapping the connection handler concepts
around and the role concept will continue existing on the handler level,
we need to rename this.

A `PoolConfig` holds a `connection_specification_name` (we may rename
this down the road), a `db_config`, a `schema_cache`, and a `pool`. It
does feel like `pool` could eventually hold all of these things instead
of having a `PoolConfig` object. This would remove one level of the
object graph and reduce complexity. For now I'm leaving this object to
keep the change churn low and will revisit later.

Co-authored-by: John Crepezzi <seejohnrun@github.com>
This commit is contained in:
eileencodes 2019-11-05 17:05:54 -05:00
parent a2a525bbb6
commit 6d81eab13d
16 changed files with 166 additions and 165 deletions

View File

@ -9,8 +9,8 @@ module ActiveRecord
end end
autoload :Column autoload :Column
autoload :Role autoload :PoolConfig
autoload :RoleManager autoload :PoolManager
autoload :Resolver autoload :Resolver
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do autoload_at "active_record/connection_adapters/abstract/schema_definitions" do

View File

@ -370,21 +370,21 @@ module ActiveRecord
include ConnectionAdapters::AbstractPool include ConnectionAdapters::AbstractPool
attr_accessor :automatic_reconnect, :checkout_timeout attr_accessor :automatic_reconnect, :checkout_timeout
attr_reader :db_config, :size, :reaper, :role attr_reader :db_config, :size, :reaper, :pool_config
delegate :schema_cache, :schema_cache=, to: :role delegate :schema_cache, :schema_cache=, to: :pool_config
# Creates a new ConnectionPool object. +role+ is a Role # Creates a new ConnectionPool object. +pool_config+ is a PoolConfig
# object which describes database connection information (e.g. adapter, # object which describes database connection information (e.g. adapter,
# host name, username, password, etc), as well as the maximum size for # host name, username, password, etc), as well as the maximum size for
# this ConnectionPool. # this ConnectionPool.
# #
# The default ConnectionPool maximum size is 5. # The default ConnectionPool maximum size is 5.
def initialize(role) def initialize(pool_config)
super() super()
@role = role @pool_config = pool_config
@db_config = role.db_config @db_config = pool_config.db_config
@checkout_timeout = db_config.checkout_timeout @checkout_timeout = db_config.checkout_timeout
@idle_timeout = db_config.idle_timeout @idle_timeout = db_config.idle_timeout
@ -1003,8 +1003,8 @@ module ActiveRecord
private_constant :FINALIZER private_constant :FINALIZER
def initialize def initialize
# These caches are keyed by role.connection_specification_name (Role#connection_specification_name). # These caches are keyed by pool_config.connection_specification_name (PoolConfig#connection_specification_name).
@owner_to_role_manager = Concurrent::Map.new(initial_capacity: 2) @owner_to_pool_manager = Concurrent::Map.new(initial_capacity: 2)
# Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred # Backup finalizer: if the forked child skipped Kernel#fork the early discard has not occurred
ObjectSpace.define_finalizer self, FINALIZER ObjectSpace.define_finalizer self, FINALIZER
@ -1031,36 +1031,36 @@ module ActiveRecord
end end
def connection_pool_names # :nodoc: def connection_pool_names # :nodoc:
owner_to_role_manager.keys owner_to_pool_manager.keys
end end
def connection_pool_list def connection_pool_list
owner_to_role_manager.values.compact.flat_map { |rc| rc.roles.map(&:pool) } owner_to_pool_manager.values.compact.flat_map { |m| m.pool_configs.map(&:pool) }
end end
alias :connection_pools :connection_pool_list alias :connection_pools :connection_pool_list
def establish_connection(config, role_name = :default) def establish_connection(config, pool_key = :default)
resolver = Resolver.new(Base.configurations) resolver = Resolver.new(Base.configurations)
role = resolver.resolve_role(config) pool_config = resolver.resolve_pool_config(config)
db_config = role.db_config db_config = pool_config.db_config
remove_connection(role.connection_specification_name, role_name) remove_connection(pool_config.connection_specification_name, pool_key)
message_bus = ActiveSupport::Notifications.instrumenter message_bus = ActiveSupport::Notifications.instrumenter
payload = { payload = {
connection_id: object_id connection_id: object_id
} }
if role if pool_config
payload[:spec_name] = role.connection_specification_name payload[:spec_name] = pool_config.connection_specification_name
payload[:config] = db_config.configuration_hash payload[:config] = db_config.configuration_hash
end end
owner_to_role_manager[role.connection_specification_name] ||= RoleManager.new owner_to_pool_manager[pool_config.connection_specification_name] ||= PoolManager.new
role_manager = owner_to_role_manager[role.connection_specification_name] pool_manager = owner_to_pool_manager[pool_config.connection_specification_name]
role_manager.set_role(role_name, role) pool_manager.set_pool_config(pool_key, pool_config)
message_bus.instrument("!connection.active_record", payload) do message_bus.instrument("!connection.active_record", payload) do
role.pool pool_config.pool
end end
end end
@ -1116,8 +1116,8 @@ module ActiveRecord
# Returns true if a connection that's accessible to this class has # Returns true if a connection that's accessible to this class has
# already been opened. # already been opened.
def connected?(spec_name, role_name = :default) def connected?(spec_name, pool_key = :default)
pool = retrieve_connection_pool(spec_name, role_name) pool = retrieve_connection_pool(spec_name, pool_key)
pool && pool.connected? pool && pool.connected?
end end
@ -1125,27 +1125,27 @@ module ActiveRecord
# connection and the defined connection (if they exist). The result # connection and the defined connection (if they exist). The result
# can be used as an argument for #establish_connection, for easily # can be used as an argument for #establish_connection, for easily
# re-establishing the connection. # re-establishing the connection.
def remove_connection(spec_name, role_name = :default) def remove_connection(spec_name, pool_key = :default)
if role_manager = owner_to_role_manager[spec_name] if pool_manager = owner_to_pool_manager[spec_name]
role = role_manager.remove_role(role_name) pool_config = pool_manager.remove_pool_config(pool_key)
if role if pool_config
role.disconnect! pool_config.disconnect!
role.db_config.configuration_hash pool_config.db_config.configuration_hash
end end
end end
end end
# Retrieving the connection pool happens a lot, so we cache it in @owner_to_role_manager. # Retrieving the connection pool happens a lot, so we cache it in @owner_to_pool_manager.
# This makes retrieving the connection pool O(1) once the process is warm. # This makes retrieving the connection pool O(1) once the process is warm.
# When a connection is established or removed, we invalidate the cache. # When a connection is established or removed, we invalidate the cache.
def retrieve_connection_pool(spec_name, role_name = :default) def retrieve_connection_pool(spec_name, pool_key = :default)
role = owner_to_role_manager[spec_name]&.get_role(role_name) pool_config = owner_to_pool_manager[spec_name]&.get_pool_config(pool_key)
role&.pool pool_config&.pool
end end
private private
attr_reader :owner_to_role_manager attr_reader :owner_to_pool_manager
end end
end end
end end

View File

@ -2,7 +2,7 @@
module ActiveRecord module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
class Role # :nodoc: class PoolConfig # :nodoc:
include Mutex_m include Mutex_m
attr_reader :db_config, :connection_specification_name attr_reader :db_config, :connection_specification_name
@ -60,4 +60,4 @@ module ActiveRecord
end end
end end
ActiveSupport::ForkTracker.after_fork { ActiveRecord::ConnectionAdapters::Role.discard_pools! } ActiveSupport::ForkTracker.after_fork { ActiveRecord::ConnectionAdapters::PoolConfig.discard_pools! }

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
module ActiveRecord
module ConnectionAdapters
class PoolManager # :nodoc:
def initialize
@name_to_pool_config = {}
end
def pool_configs
@name_to_pool_config.values
end
def remove_pool_config(key)
@name_to_pool_config.delete(key)
end
def get_pool_config(key)
@name_to_pool_config[key]
end
def set_pool_config(key, pool_config)
@name_to_pool_config[key] = pool_config
end
end
end
end

View File

@ -2,7 +2,7 @@
module ActiveRecord module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
# Builds a Role from user input. # Builds a PoolConfig from user input.
class Resolver # :nodoc: class Resolver # :nodoc:
attr_reader :configurations attr_reader :configurations
@ -11,17 +11,17 @@ module ActiveRecord
@configurations = configurations @configurations = configurations
end end
# Returns an instance of Role for a given adapter. # Returns an instance of PoolConfig for a given adapter.
# Accepts a hash one layer deep that contains all connection information. # Accepts a hash one layer deep that contains all connection information.
# #
# == Example # == Example
# #
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } } # config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
# role = Resolver.new(config).resolve_role(:production) # pool_config = Resolver.new(config).resolve_pool_config(:production)
# role.db_config.configuration_hash # pool_config.db_config.configuration_hash
# # => { host: "localhost", database: "foo", adapter: "sqlite3" } # # => { host: "localhost", database: "foo", adapter: "sqlite3" }
# #
def resolve_role(config) def resolve_pool_config(config)
pool_name = config if config.is_a?(Symbol) pool_name = config if config.is_a?(Symbol)
db_config = resolve(config, pool_name) db_config = resolve(config, pool_name)
@ -53,7 +53,7 @@ module ActiveRecord
raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter" raise AdapterNotFound, "database configuration specifies nonexistent #{db_config.adapter} adapter"
end end
Role.new(db_config.configuration_hash.delete(:name) || "primary", db_config) PoolConfig.new(db_config.configuration_hash.delete(:name) || "primary", db_config)
end end
# Returns fully resolved connection, accepts hash, string or symbol. # Returns fully resolved connection, accepts hash, string or symbol.

View File

@ -1,27 +0,0 @@
# frozen_string_literal: true
module ActiveRecord
module ConnectionAdapters
class RoleManager # :nodoc:
def initialize
@name_to_role = {}
end
def roles
@name_to_role.values
end
def remove_role(name)
@name_to_role.delete(name)
end
def get_role(name)
@name_to_role[name]
end
def set_role(name, role)
@name_to_role[name] = role
end
end
end
end

View File

@ -192,11 +192,11 @@ module ActiveRecord
ActiveRecord::Base.connection_handlers.values.each do |handler| ActiveRecord::Base.connection_handlers.values.each do |handler|
if handler != writing_handler if handler != writing_handler
handler.connection_pool_names.each do |name| handler.connection_pool_names.each do |name|
writing_role_manager = writing_handler.send(:owner_to_role_manager)[name] writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
writing_role = writing_role_manager.get_role(:default) writing_pool_config = writing_pool_manager.get_pool_config(:default)
role_manager = handler.send(:owner_to_role_manager)[name] pool_manager = handler.send(:owner_to_pool_manager)[name]
role_manager.set_role(:default, writing_role) pool_manager.set_pool_config(:default, writing_pool_config)
end end
end end
end end

View File

@ -40,8 +40,8 @@ module ActiveRecord
def test_close def test_close
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "primary", {}) db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "primary", {})
role = ActiveRecord::ConnectionAdapters::Role.new("primary", db_config) pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new("primary", db_config)
pool = Pool.new(role) pool = Pool.new(pool_config)
pool.insert_connection_for_test! @adapter pool.insert_connection_for_test! @adapter
@adapter.pool = pool @adapter.pool = pool

View File

@ -5,7 +5,7 @@ require "models/person"
module ActiveRecord module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
class ConnectionHandlersMultiRoleTest < ActiveRecord::TestCase class ConnectionHandlersMultiPoolConfigTest < ActiveRecord::TestCase
self.use_transactional_tests = false self.use_transactional_tests = false
fixtures :people fixtures :people
@ -22,7 +22,7 @@ module ActiveRecord
end end
unless in_memory_db? unless in_memory_db?
def test_establish_connection_with_roles def test_establish_connection_with_pool_configs
previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env" previous_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "default_env"
config = { config = {
@ -34,10 +34,10 @@ module ActiveRecord
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
@writing_handler.establish_connection(:primary) @writing_handler.establish_connection(:primary)
@writing_handler.establish_connection(:primary, :role_two) @writing_handler.establish_connection(:primary, :pool_config_two)
default_pool = @writing_handler.retrieve_connection_pool("primary", :default) default_pool = @writing_handler.retrieve_connection_pool("primary", :default)
other_pool = @writing_handler.retrieve_connection_pool("primary", :role_two) other_pool = @writing_handler.retrieve_connection_pool("primary", :pool_config_two)
assert_not_nil default_pool assert_not_nil default_pool
assert_not_equal default_pool, other_pool assert_not_equal default_pool, other_pool
@ -62,13 +62,13 @@ module ActiveRecord
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
@writing_handler.establish_connection(:primary) @writing_handler.establish_connection(:primary)
@writing_handler.establish_connection(:primary, :role_two) @writing_handler.establish_connection(:primary, :pool_config_two)
# remove default # remove default
@writing_handler.remove_connection("primary") @writing_handler.remove_connection("primary")
assert_nil @writing_handler.retrieve_connection_pool("primary") assert_nil @writing_handler.retrieve_connection_pool("primary")
assert_not_nil @writing_handler.retrieve_connection_pool("primary", :role_two) assert_not_nil @writing_handler.retrieve_connection_pool("primary", :pool_config_two)
ensure ensure
ActiveRecord::Base.configurations = @prev_configs ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit) ActiveRecord::Base.establish_connection(:arunit)
@ -87,18 +87,19 @@ module ActiveRecord
@prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config @prev_configs, ActiveRecord::Base.configurations = ActiveRecord::Base.configurations, config
@writing_handler.establish_connection(:primary) @writing_handler.establish_connection(:primary)
@writing_handler.establish_connection(:primary, :role_two) @writing_handler.establish_connection(:primary, :pool_config_two)
# connect to default # connect to default
@writing_handler.connection_pool_list.first.checkout @writing_handler.connection_pool_list.first.checkout
assert @writing_handler.connected?("primary") assert @writing_handler.connected?("primary")
assert @writing_handler.connected?("primary", :default) assert @writing_handler.connected?("primary", :default)
assert_not @writing_handler.connected?("primary", :role_two) assert_not @writing_handler.connected?("primary", :pool_config_two)
ensure ensure
ActiveRecord::Base.configurations = @prev_configs ActiveRecord::Base.configurations = @prev_configs
ActiveRecord::Base.establish_connection(:arunit) ActiveRecord::Base.establish_connection(:arunit)
ENV["RAILS_ENV"] = previous_env ENV["RAILS_ENV"] = previous_env
FileUtils.rm_rf "db"
end end
end end
end end

View File

@ -13,8 +13,8 @@ module ActiveRecord
# Keep a duplicate pool so we do not bother others # Keep a duplicate pool so we do not bother others
@db_config = ActiveRecord::Base.connection_pool.db_config @db_config = ActiveRecord::Base.connection_pool.db_config
@role = ActiveRecord::ConnectionAdapters::Role.new("primary", @db_config) @pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new("primary", @db_config)
@pool = ConnectionPool.new(@role) @pool = ConnectionPool.new(@pool_config)
if in_memory_db? if in_memory_db?
# Separate connections to an in-memory database create an entirely new database, # Separate connections to an in-memory database create an entirely new database,
@ -201,8 +201,8 @@ module ActiveRecord
def test_idle_timeout_configuration def test_idle_timeout_configuration
@pool.disconnect! @pool.disconnect!
@db_config.configuration_hash.merge!(idle_timeout: "0.02") @db_config.configuration_hash.merge!(idle_timeout: "0.02")
role = ActiveRecord::ConnectionAdapters::Role.new("primary", @db_config) pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new("primary", @db_config)
@pool = ConnectionPool.new(role) @pool = ConnectionPool.new(pool_config)
idle_conn = @pool.checkout idle_conn = @pool.checkout
@pool.checkin(idle_conn) @pool.checkin(idle_conn)
@ -226,8 +226,8 @@ module ActiveRecord
def test_disable_flush def test_disable_flush
@pool.disconnect! @pool.disconnect!
@db_config.configuration_hash.merge!(idle_timeout: -5) @db_config.configuration_hash.merge!(idle_timeout: -5)
role = ActiveRecord::ConnectionAdapters::Role.new("primary", @db_config) pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new("primary", @db_config)
@pool = ConnectionPool.new(role) @pool = ConnectionPool.new(pool_config)
idle_conn = @pool.checkout idle_conn = @pool.checkout
@pool.checkin(idle_conn) @pool.checkin(idle_conn)
@ -317,7 +317,7 @@ module ActiveRecord
end end
def test_checkout_behaviour def test_checkout_behaviour
pool = ConnectionPool.new(@role) pool = ConnectionPool.new(@pool_config)
main_connection = pool.connection main_connection = pool.connection
assert_not_nil main_connection assert_not_nil main_connection
threads = [] threads = []
@ -450,7 +450,7 @@ module ActiveRecord
end end
def test_automatic_reconnect_restores_after_disconnect def test_automatic_reconnect_restores_after_disconnect
pool = ConnectionPool.new(@role) pool = ConnectionPool.new(@pool_config)
assert pool.automatic_reconnect assert pool.automatic_reconnect
assert pool.connection assert pool.connection
@ -459,7 +459,7 @@ module ActiveRecord
end end
def test_automatic_reconnect_can_be_disabled def test_automatic_reconnect_can_be_disabled
pool = ConnectionPool.new(@role) pool = ConnectionPool.new(@pool_config)
pool.disconnect! pool.disconnect!
pool.automatic_reconnect = false pool.automatic_reconnect = false
@ -723,10 +723,10 @@ module ActiveRecord
old_config = @db_config.configuration_hash old_config = @db_config.configuration_hash
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", old_config.dup) db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", old_config.dup)
db_config.configuration_hash[:pool] = 1 # this is safe to do, because .dupped Role also auto-dups its config db_config.configuration_hash[:pool] = 1 # this is safe to do, because .dupped PoolConfig also auto-dups its config
role = ActiveRecord::ConnectionAdapters::Role.new("primary", db_config) pool_config = ActiveRecord::ConnectionAdapters::PoolConfig.new("primary", db_config)
yield(pool = ConnectionPool.new(role)) yield(pool = ConnectionPool.new(pool_config))
ensure ensure
pool.disconnect! if pool pool.disconnect! if pool
end end

View File

@ -14,8 +14,8 @@ class TestDisconnectedAdapter < ActiveRecord::TestCase
teardown do teardown do
return if in_memory_db? return if in_memory_db?
role = ActiveRecord::Base.connection_config config = ActiveRecord::Base.connection_config
ActiveRecord::Base.establish_connection(role) ActiveRecord::Base.establish_connection(config)
end end
unless in_memory_db? unless in_memory_db?

View File

@ -1414,10 +1414,10 @@ class MultipleDatabaseFixturesTest < ActiveRecord::TestCase
private private
def with_temporary_connection_pool def with_temporary_connection_pool
role = ActiveRecord::Base.connection_handler.send(:owner_to_role_manager).fetch("primary").get_role(:default) pool_config = ActiveRecord::Base.connection_handler.send(:owner_to_pool_manager).fetch("primary").get_pool_config(:default)
new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new(role) new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new(pool_config)
role.stub(:pool, new_pool) do pool_config.stub(:pool, new_pool) do
yield yield
end end
end end

View File

@ -4,23 +4,23 @@ require "cases/helper"
module ActiveRecord module ActiveRecord
module ConnectionAdapters module ConnectionAdapters
class Role class PoolConfig
class ResolverTest < ActiveRecord::TestCase class ResolverTest < ActiveRecord::TestCase
def resolve(role, config = {}) def resolve(pool_config, config = {})
configs = ActiveRecord::DatabaseConfigurations.new(config) configs = ActiveRecord::DatabaseConfigurations.new(config)
resolver = ConnectionAdapters::Resolver.new(configs) resolver = ConnectionAdapters::Resolver.new(configs)
resolver.resolve(role, role).configuration_hash resolver.resolve(pool_config, pool_config).configuration_hash
end end
def resolve_role(role, config = {}) def resolve_pool_config(pool_config, config = {})
configs = ActiveRecord::DatabaseConfigurations.new(config) configs = ActiveRecord::DatabaseConfigurations.new(config)
resolver = ConnectionAdapters::Resolver.new(configs) resolver = ConnectionAdapters::Resolver.new(configs)
resolver.resolve_role(role) resolver.resolve_pool_config(pool_config)
end end
def test_url_invalid_adapter def test_url_invalid_adapter
error = assert_raises(LoadError) do error = assert_raises(LoadError) do
resolve_role "ridiculous://foo?encoding=utf8" resolve_pool_config "ridiculous://foo?encoding=utf8"
end end
assert_match "Could not load the 'ridiculous' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", error.message assert_match "Could not load the 'ridiculous' Active Record adapter. Ensure that the adapter is spelled correctly in config/database.yml and that you've added the necessary adapter gem to your Gemfile.", error.message
@ -28,7 +28,7 @@ module ActiveRecord
def test_error_if_no_adapter_method def test_error_if_no_adapter_method
error = assert_raises(AdapterNotFound) do error = assert_raises(AdapterNotFound) do
resolve_role "abstract://foo?encoding=utf8" resolve_pool_config "abstract://foo?encoding=utf8"
end end
assert_match "database configuration specifies nonexistent abstract adapter", error.message assert_match "database configuration specifies nonexistent abstract adapter", error.message
@ -38,121 +38,121 @@ module ActiveRecord
# checks that the adapter file can be required in. # checks that the adapter file can be required in.
def test_url_from_environment def test_url_from_environment
role = resolve :production, "production" => "abstract://foo?encoding=utf8" pool_config = resolve :production, "production" => "abstract://foo?encoding=utf8"
assert_equal({ assert_equal({
adapter: "abstract", adapter: "abstract",
host: "foo", host: "foo",
encoding: "utf8", encoding: "utf8",
name: "production" name: "production"
}, role) }, pool_config)
end end
def test_url_sub_key def test_url_sub_key
role = resolve :production, "production" => { "url" => "abstract://foo?encoding=utf8" } pool_config = resolve :production, "production" => { "url" => "abstract://foo?encoding=utf8" }
assert_equal({ assert_equal({
adapter: "abstract", adapter: "abstract",
host: "foo", host: "foo",
encoding: "utf8", encoding: "utf8",
name: "production" name: "production"
}, role) }, pool_config)
end end
def test_url_sub_key_merges_correctly def test_url_sub_key_merges_correctly
hash = { "url" => "abstract://foo?encoding=utf8&", "adapter" => "sqlite3", "host" => "bar", "pool" => "3" } hash = { "url" => "abstract://foo?encoding=utf8&", "adapter" => "sqlite3", "host" => "bar", "pool" => "3" }
role = resolve :production, "production" => hash pool_config = resolve :production, "production" => hash
assert_equal({ assert_equal({
adapter: "abstract", adapter: "abstract",
host: "foo", host: "foo",
encoding: "utf8", encoding: "utf8",
pool: "3", pool: "3",
name: "production" name: "production"
}, role) }, pool_config)
end end
def test_url_host_no_db def test_url_host_no_db
role = resolve "abstract://foo?encoding=utf8" pool_config = resolve "abstract://foo?encoding=utf8"
assert_equal({ assert_equal({
adapter: "abstract", adapter: "abstract",
host: "foo", host: "foo",
encoding: "utf8" encoding: "utf8"
}, role) }, pool_config)
end end
def test_url_missing_scheme def test_url_missing_scheme
role = resolve "foo" pool_config = resolve "foo"
assert_equal({ database: "foo" }, role) assert_equal({ database: "foo" }, pool_config)
end end
def test_url_host_db def test_url_host_db
role = resolve "abstract://foo/bar?encoding=utf8" pool_config = resolve "abstract://foo/bar?encoding=utf8"
assert_equal({ assert_equal({
adapter: "abstract", adapter: "abstract",
database: "bar", database: "bar",
host: "foo", host: "foo",
encoding: "utf8" encoding: "utf8"
}, role) }, pool_config)
end end
def test_url_port def test_url_port
role = resolve "abstract://foo:123?encoding=utf8" pool_config = resolve "abstract://foo:123?encoding=utf8"
assert_equal({ assert_equal({
adapter: "abstract", adapter: "abstract",
port: 123, port: 123,
host: "foo", host: "foo",
encoding: "utf8" encoding: "utf8"
}, role) }, pool_config)
end end
def test_encoded_password def test_encoded_password
password = "am@z1ng_p@ssw0rd#!" password = "am@z1ng_p@ssw0rd#!"
encoded_password = URI.encode_www_form_component(password) encoded_password = URI.encode_www_form_component(password)
role = resolve "abstract://foo:#{encoded_password}@localhost/bar" pool_config = resolve "abstract://foo:#{encoded_password}@localhost/bar"
assert_equal password, role[:password] assert_equal password, pool_config[:password]
end end
def test_url_with_authority_for_sqlite3 def test_url_with_authority_for_sqlite3
role = resolve "sqlite3:///foo_test" pool_config = resolve "sqlite3:///foo_test"
assert_equal("/foo_test", role[:database]) assert_equal("/foo_test", pool_config[:database])
end end
def test_url_absolute_path_for_sqlite3 def test_url_absolute_path_for_sqlite3
role = resolve "sqlite3:/foo_test" pool_config = resolve "sqlite3:/foo_test"
assert_equal("/foo_test", role[:database]) assert_equal("/foo_test", pool_config[:database])
end end
def test_url_relative_path_for_sqlite3 def test_url_relative_path_for_sqlite3
role = resolve "sqlite3:foo_test" pool_config = resolve "sqlite3:foo_test"
assert_equal("foo_test", role[:database]) assert_equal("foo_test", pool_config[:database])
end end
def test_url_memory_db_for_sqlite3 def test_url_memory_db_for_sqlite3
role = resolve "sqlite3::memory:" pool_config = resolve "sqlite3::memory:"
assert_equal(":memory:", role[:database]) assert_equal(":memory:", pool_config[:database])
end end
def test_url_sub_key_for_sqlite3 def test_url_sub_key_for_sqlite3
role = resolve :production, "production" => { "url" => "sqlite3:foo?encoding=utf8" } pool_config = resolve :production, "production" => { "url" => "sqlite3:foo?encoding=utf8" }
assert_equal({ assert_equal({
adapter: "sqlite3", adapter: "sqlite3",
database: "foo", database: "foo",
encoding: "utf8", encoding: "utf8",
name: "production" name: "production"
}, role) }, pool_config)
end end
def test_role_connection_specification_name_on_key_lookup def test_pool_config_connection_specification_name_on_key_lookup
role = resolve_role(:readonly, "readonly" => { "adapter" => "sqlite3" }) pool_config = resolve_pool_config(:readonly, "readonly" => { "adapter" => "sqlite3" })
assert_equal "readonly", role.connection_specification_name assert_equal "readonly", pool_config.connection_specification_name
end end
def test_role_connection_specification_name_with_inline_config def test_pool_config_connection_specification_name_with_inline_config
role = resolve_role("adapter" => "sqlite3") pool_config = resolve_pool_config("adapter" => "sqlite3")
assert_equal "primary", role.connection_specification_name, "should default to primary id" assert_equal "primary", pool_config.connection_specification_name, "should default to primary id"
end end
def test_role_with_invalid_type def test_pool_config_with_invalid_type
assert_raises TypeError do assert_raises TypeError do
resolve_role(Object.new) resolve_pool_config(Object.new)
end end
end end
end end

View File

@ -555,10 +555,10 @@ class QueryCacheTest < ActiveRecord::TestCase
private private
def with_temporary_connection_pool def with_temporary_connection_pool
role = ActiveRecord::Base.connection_handler.send(:owner_to_role_manager).fetch("primary").get_role(:default) pool_config = ActiveRecord::Base.connection_handler.send(:owner_to_pool_manager).fetch("primary").get_pool_config(:default)
new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new(role) new_pool = ActiveRecord::ConnectionAdapters::ConnectionPool.new(pool_config)
role.stub(:pool, new_pool) do pool_config.stub(:pool, new_pool) do
yield yield
end end
end end

View File

@ -59,8 +59,8 @@ module ActiveRecord
def test_pool_has_reaper def test_pool_has_reaper
config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", spec_name: "primary") config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", spec_name: "primary")
role = Role.new("primary", config) pool_config = PoolConfig.new("primary", config)
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
assert pool.reaper assert pool.reaper
ensure ensure
@ -68,10 +68,10 @@ module ActiveRecord
end end
def test_reaping_frequency_configuration def test_reaping_frequency_configuration
role = duplicated_role pool_config = duplicated_pool_config
role.db_config.configuration_hash[:reaping_frequency] = "10.01" pool_config.db_config.configuration_hash[:reaping_frequency] = "10.01"
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
assert_equal 10.01, pool.reaper.frequency assert_equal 10.01, pool.reaper.frequency
ensure ensure
@ -79,10 +79,10 @@ module ActiveRecord
end end
def test_connection_pool_starts_reaper def test_connection_pool_starts_reaper
role = duplicated_role pool_config = duplicated_pool_config
role.db_config.configuration_hash[:reaping_frequency] = "0.0001" pool_config.db_config.configuration_hash[:reaping_frequency] = "0.0001"
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
conn, child = new_conn_in_thread(pool) conn, child = new_conn_in_thread(pool)
@ -97,11 +97,11 @@ module ActiveRecord
end end
def test_reaper_works_after_pool_discard def test_reaper_works_after_pool_discard
role = duplicated_role pool_config = duplicated_pool_config
role.db_config.configuration_hash[:reaping_frequency] = "0.0001" pool_config.db_config.configuration_hash[:reaping_frequency] = "0.0001"
2.times do 2.times do
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
conn, child = new_conn_in_thread(pool) conn, child = new_conn_in_thread(pool)
@ -119,8 +119,8 @@ module ActiveRecord
# This doesn't test the reaper directly, but we want to test the action # This doesn't test the reaper directly, but we want to test the action
# it would take on a discarded pool # it would take on a discarded pool
def test_reap_flush_on_discarded_pool def test_reap_flush_on_discarded_pool
role = duplicated_role pool_config = duplicated_pool_config
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
pool.discard! pool.discard!
pool.reap pool.reap
@ -128,14 +128,14 @@ module ActiveRecord
end end
def test_connection_pool_starts_reaper_in_fork def test_connection_pool_starts_reaper_in_fork
role = duplicated_role pool_config = duplicated_pool_config
role.db_config.configuration_hash[:reaping_frequency] = "0.0001" pool_config.db_config.configuration_hash[:reaping_frequency] = "0.0001"
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
pool.checkout pool.checkout
pid = fork do pid = fork do
pool = ConnectionPool.new(role) pool = ConnectionPool.new(pool_config)
conn, child = new_conn_in_thread(pool) conn, child = new_conn_in_thread(pool)
child.terminate child.terminate
@ -173,10 +173,10 @@ module ActiveRecord
end end
private private
def duplicated_role def duplicated_pool_config
old_config = ActiveRecord::Base.connection_pool.db_config.configuration_hash old_config = ActiveRecord::Base.connection_pool.db_config.configuration_hash
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", old_config.dup) db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", old_config.dup)
Role.new("primary", db_config) PoolConfig.new("primary", db_config)
end end
def new_conn_in_thread(pool) def new_conn_in_thread(pool)

View File

@ -13,7 +13,7 @@ class TestUnconnectedAdapter < ActiveRecord::TestCase
@specification = ActiveRecord::Base.remove_connection @specification = ActiveRecord::Base.remove_connection
# Clear out connection info from other pids (like a fork parent) too # Clear out connection info from other pids (like a fork parent) too
ActiveRecord::ConnectionAdapters::Role.discard_pools! ActiveRecord::ConnectionAdapters::PoolConfig.discard_pools!
end end
teardown do teardown do