mirror of https://github.com/rails/rails
Merge pull request #37199 from seejohnrun/reduce-surface-area-of-connection-specification
Reduce surface area of ConnectionSpecification
This commit is contained in:
commit
9b6433bb82
|
@ -10,6 +10,7 @@ module ActiveRecord
|
|||
|
||||
autoload :Column
|
||||
autoload :ConnectionSpecification
|
||||
autoload :Resolver
|
||||
|
||||
autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
|
||||
autoload :IndexDefinition
|
||||
|
|
|
@ -385,14 +385,14 @@ module ActiveRecord
|
|||
|
||||
@spec = spec
|
||||
|
||||
@checkout_timeout = (spec.underlying_configuration_hash[:checkout_timeout] && spec.underlying_configuration_hash[:checkout_timeout].to_f) || 5
|
||||
if @idle_timeout = spec.underlying_configuration_hash.fetch(:idle_timeout, 300)
|
||||
@checkout_timeout = (spec.db_config.configuration_hash[:checkout_timeout] && spec.db_config.configuration_hash[:checkout_timeout].to_f) || 5
|
||||
if @idle_timeout = spec.db_config.configuration_hash.fetch(:idle_timeout, 300)
|
||||
@idle_timeout = @idle_timeout.to_f
|
||||
@idle_timeout = nil if @idle_timeout <= 0
|
||||
end
|
||||
|
||||
# default max pool size to 5
|
||||
@size = (spec.underlying_configuration_hash[:pool] && spec.underlying_configuration_hash[:pool].to_i) || 5
|
||||
@size = (spec.db_config.configuration_hash[:pool] && spec.db_config.configuration_hash[:pool].to_i) || 5
|
||||
|
||||
# This variable tracks the cache of threads mapped to reserved connections, with the
|
||||
# sole purpose of speeding up the +connection+ method. It is not the authoritative
|
||||
|
@ -422,7 +422,7 @@ module ActiveRecord
|
|||
|
||||
# +reaping_frequency+ is configurable mostly for historical reasons, but it could
|
||||
# also be useful if someone wants a very low +idle_timeout+.
|
||||
reaping_frequency = spec.underlying_configuration_hash.fetch(:reaping_frequency, 60)
|
||||
reaping_frequency = spec.db_config.configuration_hash.fetch(:reaping_frequency, 60)
|
||||
@reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
|
||||
@reaper.run
|
||||
end
|
||||
|
@ -505,7 +505,7 @@ module ActiveRecord
|
|||
# Raises:
|
||||
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
||||
# connections in the pool within a timeout interval (default duration is
|
||||
# <tt>spec.underlying_configuration_hash[:checkout_timeout] * 2</tt> seconds).
|
||||
# <tt>spec.db_config.configuration_hash[:checkout_timeout] * 2</tt> seconds).
|
||||
def disconnect(raise_on_acquisition_timeout = true)
|
||||
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
||||
synchronize do
|
||||
|
@ -526,7 +526,7 @@ module ActiveRecord
|
|||
#
|
||||
# The pool first tries to gain ownership of all connections. If unable to
|
||||
# do so within a timeout interval (default duration is
|
||||
# <tt>spec.underlying_configuration_hash[:checkout_timeout] * 2</tt> seconds), then the pool is forcefully
|
||||
# <tt>spec.db_config.configuration_hash[:checkout_timeout] * 2</tt> seconds), then the pool is forcefully
|
||||
# disconnected without any regard for other connection owning threads.
|
||||
def disconnect!
|
||||
disconnect(false)
|
||||
|
@ -557,7 +557,7 @@ module ActiveRecord
|
|||
# Raises:
|
||||
# - ActiveRecord::ExclusiveConnectionTimeoutError if unable to gain ownership of all
|
||||
# connections in the pool within a timeout interval (default duration is
|
||||
# <tt>spec.underlying_configuration_hash[:checkout_timeout] * 2</tt> seconds).
|
||||
# <tt>spec.db_config.configuration_hash[:checkout_timeout] * 2</tt> seconds).
|
||||
def clear_reloadable_connections(raise_on_acquisition_timeout = true)
|
||||
with_exclusively_acquired_all_connections(raise_on_acquisition_timeout) do
|
||||
synchronize do
|
||||
|
@ -579,7 +579,7 @@ module ActiveRecord
|
|||
#
|
||||
# The pool first tries to gain ownership of all connections. If unable to
|
||||
# do so within a timeout interval (default duration is
|
||||
# <tt>spec.underlying_configuration_hash[:checkout_timeout] * 2</tt> seconds), then the pool forcefully
|
||||
# <tt>spec.db_config.configuration_hash[:checkout_timeout] * 2</tt> seconds), then the pool forcefully
|
||||
# clears the cache and reloads connections without any regard for other
|
||||
# connection owning threads.
|
||||
def clear_reloadable_connections!
|
||||
|
@ -899,7 +899,7 @@ module ActiveRecord
|
|||
alias_method :release, :remove_connection_from_thread_cache
|
||||
|
||||
def new_connection
|
||||
Base.send(spec.adapter_method, spec.underlying_configuration_hash).tap do |conn|
|
||||
Base.send(spec.db_config.adapter_method, spec.db_config.configuration_hash).tap do |conn|
|
||||
conn.check_version
|
||||
end
|
||||
end
|
||||
|
@ -1063,7 +1063,7 @@ module ActiveRecord
|
|||
alias :connection_pools :connection_pool_list
|
||||
|
||||
def establish_connection(config)
|
||||
resolver = ConnectionSpecification::Resolver.new(Base.configurations)
|
||||
resolver = Resolver.new(Base.configurations)
|
||||
spec = resolver.spec(config)
|
||||
|
||||
remove_connection(spec.name)
|
||||
|
@ -1074,7 +1074,7 @@ module ActiveRecord
|
|||
}
|
||||
if spec
|
||||
payload[:spec_name] = spec.name
|
||||
payload[:config] = spec.underlying_configuration_hash
|
||||
payload[:config] = spec.db_config.configuration_hash
|
||||
end
|
||||
|
||||
message_bus.instrument("!connection.active_record", payload) do
|
||||
|
@ -1149,7 +1149,7 @@ module ActiveRecord
|
|||
if pool = owner_to_pool.delete(spec_name)
|
||||
pool.automatic_reconnect = false
|
||||
pool.disconnect!
|
||||
pool.spec.underlying_configuration_hash
|
||||
pool.spec.db_config.configuration_hash
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1164,7 +1164,7 @@ module ActiveRecord
|
|||
# A connection was established in an ancestor process that must have
|
||||
# subsequently forked. We can't reuse the connection, but we can copy
|
||||
# the specification and establish a new connection with it.
|
||||
establish_connection(ancestor_pool.spec.to_hash).tap do |pool|
|
||||
establish_connection(ancestor_pool.spec.db_config.configuration_hash).tap do |pool|
|
||||
pool.schema_cache = ancestor_pool.schema_cache if ancestor_pool.schema_cache
|
||||
end
|
||||
else
|
||||
|
|
|
@ -5,258 +5,10 @@ require "uri"
|
|||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class ConnectionSpecification # :nodoc:
|
||||
attr_reader :name, :adapter_method, :db_config
|
||||
attr_reader :name, :db_config
|
||||
|
||||
def initialize(name, db_config, adapter_method)
|
||||
@name, @db_config, @adapter_method = name, db_config, adapter_method
|
||||
end
|
||||
|
||||
def underlying_configuration_hash
|
||||
@db_config.configuration_hash
|
||||
end
|
||||
|
||||
def initialize_dup(original)
|
||||
@db_config = original.db_config.dup
|
||||
end
|
||||
|
||||
def to_hash
|
||||
underlying_configuration_hash.dup.merge(name: @name)
|
||||
end
|
||||
|
||||
# Expands a connection string into a hash.
|
||||
class ConnectionUrlResolver # :nodoc:
|
||||
# == Example
|
||||
#
|
||||
# url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
|
||||
# ConnectionUrlResolver.new(url).to_hash
|
||||
# # => {
|
||||
# adapter: "postgresql",
|
||||
# host: "localhost",
|
||||
# port: 9000,
|
||||
# database: "foo_test",
|
||||
# username: "foo",
|
||||
# password: "bar",
|
||||
# pool: "5",
|
||||
# timeout: "3000"
|
||||
# }
|
||||
def initialize(url)
|
||||
raise "Database URL cannot be empty" if url.blank?
|
||||
@uri = uri_parser.parse(url)
|
||||
@adapter = @uri.scheme && @uri.scheme.tr("-", "_")
|
||||
@adapter = "postgresql" if @adapter == "postgres"
|
||||
|
||||
if @uri.opaque
|
||||
@uri.opaque, @query = @uri.opaque.split("?", 2)
|
||||
else
|
||||
@query = @uri.query
|
||||
end
|
||||
end
|
||||
|
||||
# Converts the given URL to a full connection hash.
|
||||
def to_hash
|
||||
config = raw_config.compact_blank
|
||||
config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
|
||||
config
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :uri
|
||||
|
||||
def uri_parser
|
||||
@uri_parser ||= URI::Parser.new
|
||||
end
|
||||
|
||||
# Converts the query parameters of the URI into a hash.
|
||||
#
|
||||
# "localhost?pool=5&reaping_frequency=2"
|
||||
# # => { pool: "5", reaping_frequency: "2" }
|
||||
#
|
||||
# returns empty hash if no query present.
|
||||
#
|
||||
# "localhost"
|
||||
# # => {}
|
||||
def query_hash
|
||||
Hash[(@query || "").split("&").map { |pair| pair.split("=") }].symbolize_keys
|
||||
end
|
||||
|
||||
def raw_config
|
||||
if uri.opaque
|
||||
query_hash.merge(
|
||||
adapter: @adapter,
|
||||
database: uri.opaque
|
||||
)
|
||||
else
|
||||
query_hash.merge(
|
||||
adapter: @adapter,
|
||||
username: uri.user,
|
||||
password: uri.password,
|
||||
port: uri.port,
|
||||
database: database_from_path,
|
||||
host: uri.hostname
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns name of the database.
|
||||
def database_from_path
|
||||
if @adapter == "sqlite3"
|
||||
# 'sqlite3:/foo' is absolute, because that makes sense. The
|
||||
# corresponding relative version, 'sqlite3:foo', is handled
|
||||
# elsewhere, as an "opaque".
|
||||
|
||||
uri.path
|
||||
else
|
||||
# Only SQLite uses a filename as the "database" name; for
|
||||
# anything else, a leading slash would be silly.
|
||||
|
||||
uri.path.sub(%r{^/}, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Builds a ConnectionSpecification from user input.
|
||||
class Resolver # :nodoc:
|
||||
attr_reader :configurations
|
||||
|
||||
# Accepts a list of db config objects.
|
||||
def initialize(configurations)
|
||||
@configurations = configurations
|
||||
end
|
||||
|
||||
# Returns an instance of ConnectionSpecification for a given adapter.
|
||||
# Accepts a hash one layer deep that contains all connection information.
|
||||
#
|
||||
# == Example
|
||||
#
|
||||
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
||||
# spec = Resolver.new(config).spec(:production)
|
||||
# spec.adapter_method
|
||||
# # => "sqlite3_connection"
|
||||
# spec.underlying_configuration_hash
|
||||
# # => { host: "localhost", database: "foo", adapter: "sqlite3" }
|
||||
#
|
||||
def spec(config)
|
||||
pool_name = config if config.is_a?(Symbol)
|
||||
|
||||
db_config = resolve(config, pool_name)
|
||||
spec = db_config.configuration_hash
|
||||
|
||||
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
||||
|
||||
# Require the adapter itself and give useful feedback about
|
||||
# 1. Missing adapter gems and
|
||||
# 2. Adapter gems' missing dependencies.
|
||||
path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
|
||||
begin
|
||||
require path_to_adapter
|
||||
rescue LoadError => e
|
||||
# We couldn't require the adapter itself. Raise an exception that
|
||||
# points out config typos and missing gems.
|
||||
if e.path == path_to_adapter
|
||||
# We can assume that a non-builtin adapter was specified, so it's
|
||||
# either misspelled or missing from Gemfile.
|
||||
raise LoadError, "Could not load the '#{spec[:adapter]}' 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.", e.backtrace
|
||||
|
||||
# Bubbled up from the adapter require. Prefix the exception message
|
||||
# with some guidance about how to address it and reraise.
|
||||
else
|
||||
raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
||||
end
|
||||
end
|
||||
|
||||
adapter_method = "#{spec[:adapter]}_connection"
|
||||
|
||||
unless ActiveRecord::Base.respond_to?(adapter_method)
|
||||
raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
|
||||
end
|
||||
|
||||
ConnectionSpecification.new(spec.delete(:name) || "primary", db_config, adapter_method)
|
||||
end
|
||||
|
||||
# Returns fully resolved connection, accepts hash, string or symbol.
|
||||
# Always returns a DatabaseConfiguration::DatabaseConfig
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# Symbol representing current environment.
|
||||
#
|
||||
# Resolver.new("production" => {}).resolve(:production)
|
||||
# # => DatabaseConfigurations::HashConfig.new(env_name: "production", config: {})
|
||||
#
|
||||
# One layer deep hash of connection values.
|
||||
#
|
||||
# Resolver.new({}).resolve("adapter" => "sqlite3")
|
||||
# # => DatabaseConfigurations::HashConfig.new(config: {"adapter" => "sqlite3"})
|
||||
#
|
||||
# Connection URL.
|
||||
#
|
||||
# Resolver.new({}).resolve("postgresql://localhost/foo")
|
||||
# # => DatabaseConfigurations::UrlConfig.new(config: {"adapter" => "postgresql", "host" => "localhost", "database" => "foo"})
|
||||
#
|
||||
def resolve(config_or_env, pool_name = nil)
|
||||
env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
|
||||
|
||||
case config_or_env
|
||||
when Symbol
|
||||
resolve_symbol_connection(config_or_env, pool_name)
|
||||
when String
|
||||
DatabaseConfigurations::UrlConfig.new(env, "primary", config_or_env)
|
||||
when Hash
|
||||
DatabaseConfigurations::HashConfig.new(env, "primary", config_or_env)
|
||||
when DatabaseConfigurations::DatabaseConfig
|
||||
config_or_env
|
||||
else
|
||||
raise TypeError, "Invalid type for configuration. Expected Symbol, String, or Hash. Got #{config_or_env.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Takes the environment such as +:production+ or +:development+ and a
|
||||
# pool name the corresponds to the name given by the connection pool
|
||||
# to the connection. That pool name is merged into the hash with the
|
||||
# name key.
|
||||
#
|
||||
# This requires that the @configurations was initialized with a key that
|
||||
# matches.
|
||||
#
|
||||
# configurations = #<ActiveRecord::DatabaseConfigurations:0x00007fd9fdace3e0
|
||||
# @configurations=[
|
||||
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd9fdace250
|
||||
# @env_name="production", @spec_name="primary", @config={database: "my_db"}>
|
||||
# ]>
|
||||
#
|
||||
# Resolver.new(configurations).resolve_symbol_connection(:production, "primary")
|
||||
# # => DatabaseConfigurations::HashConfig(config: database: "my_db", env_name: "production", spec_name: "primary")
|
||||
def resolve_symbol_connection(env_name, pool_name)
|
||||
db_config = configurations.find_db_config(env_name)
|
||||
|
||||
if db_config
|
||||
config = db_config.configuration_hash.merge(name: pool_name.to_s)
|
||||
DatabaseConfigurations::HashConfig.new(db_config.env_name, db_config.spec_name, config)
|
||||
else
|
||||
raise AdapterNotSpecified, <<~MSG
|
||||
The `#{env_name}` database is not configured for the `#{ActiveRecord::ConnectionHandling::DEFAULT_ENV.call}` environment.
|
||||
|
||||
Available databases configurations are:
|
||||
|
||||
#{build_configuration_sentence}
|
||||
MSG
|
||||
end
|
||||
end
|
||||
|
||||
def build_configuration_sentence # :nodoc:
|
||||
configs = configurations.configs_for(include_replicas: true)
|
||||
|
||||
configs.group_by(&:env_name).map do |env, config|
|
||||
namespaces = config.map(&:spec_name)
|
||||
if namespaces.size > 1
|
||||
"#{env}: #{namespaces.join(", ")}"
|
||||
else
|
||||
env
|
||||
end
|
||||
end.join("\n")
|
||||
end
|
||||
def initialize(name, db_config)
|
||||
@name, @db_config = name, db_config
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
# Builds a ConnectionSpecification from user input.
|
||||
class Resolver # :nodoc:
|
||||
attr_reader :configurations
|
||||
|
||||
# Accepts a list of db config objects.
|
||||
def initialize(configurations)
|
||||
@configurations = configurations
|
||||
end
|
||||
|
||||
# Returns an instance of ConnectionSpecification for a given adapter.
|
||||
# Accepts a hash one layer deep that contains all connection information.
|
||||
#
|
||||
# == Example
|
||||
#
|
||||
# config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } }
|
||||
# spec = Resolver.new(config).spec(:production)
|
||||
# spec.db_config.configuration_hash
|
||||
# # => { host: "localhost", database: "foo", adapter: "sqlite3" }
|
||||
#
|
||||
def spec(config)
|
||||
pool_name = config if config.is_a?(Symbol)
|
||||
|
||||
db_config = resolve(config, pool_name)
|
||||
spec = db_config.configuration_hash
|
||||
|
||||
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
||||
|
||||
# Require the adapter itself and give useful feedback about
|
||||
# 1. Missing adapter gems and
|
||||
# 2. Adapter gems' missing dependencies.
|
||||
path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter"
|
||||
begin
|
||||
require path_to_adapter
|
||||
rescue LoadError => e
|
||||
# We couldn't require the adapter itself. Raise an exception that
|
||||
# points out config typos and missing gems.
|
||||
if e.path == path_to_adapter
|
||||
# We can assume that a non-builtin adapter was specified, so it's
|
||||
# either misspelled or missing from Gemfile.
|
||||
raise LoadError, "Could not load the '#{spec[:adapter]}' 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.", e.backtrace
|
||||
|
||||
# Bubbled up from the adapter require. Prefix the exception message
|
||||
# with some guidance about how to address it and reraise.
|
||||
else
|
||||
raise LoadError, "Error loading the '#{spec[:adapter]}' Active Record adapter. Missing a gem it depends on? #{e.message}", e.backtrace
|
||||
end
|
||||
end
|
||||
|
||||
unless ActiveRecord::Base.respond_to?(db_config.adapter_method)
|
||||
raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
|
||||
end
|
||||
|
||||
ConnectionSpecification.new(spec.delete(:name) || "primary", db_config)
|
||||
end
|
||||
|
||||
# Returns fully resolved connection, accepts hash, string or symbol.
|
||||
# Always returns a DatabaseConfiguration::DatabaseConfig
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# Symbol representing current environment.
|
||||
#
|
||||
# Resolver.new("production" => {}).resolve(:production)
|
||||
# # => DatabaseConfigurations::HashConfig.new(env_name: "production", config: {})
|
||||
#
|
||||
# One layer deep hash of connection values.
|
||||
#
|
||||
# Resolver.new({}).resolve("adapter" => "sqlite3")
|
||||
# # => DatabaseConfigurations::HashConfig.new(config: {"adapter" => "sqlite3"})
|
||||
#
|
||||
# Connection URL.
|
||||
#
|
||||
# Resolver.new({}).resolve("postgresql://localhost/foo")
|
||||
# # => DatabaseConfigurations::UrlConfig.new(config: {"adapter" => "postgresql", "host" => "localhost", "database" => "foo"})
|
||||
#
|
||||
def resolve(config_or_env, pool_name = nil)
|
||||
env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
|
||||
|
||||
case config_or_env
|
||||
when Symbol
|
||||
resolve_symbol_connection(config_or_env, pool_name)
|
||||
when String
|
||||
DatabaseConfigurations::UrlConfig.new(env, "primary", config_or_env)
|
||||
when Hash
|
||||
DatabaseConfigurations::HashConfig.new(env, "primary", config_or_env)
|
||||
when DatabaseConfigurations::DatabaseConfig
|
||||
config_or_env
|
||||
else
|
||||
raise TypeError, "Invalid type for configuration. Expected Symbol, String, or Hash. Got #{config_or_env.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Takes the environment such as +:production+ or +:development+ and a
|
||||
# pool name the corresponds to the name given by the connection pool
|
||||
# to the connection. That pool name is merged into the hash with the
|
||||
# name key.
|
||||
#
|
||||
# This requires that the @configurations was initialized with a key that
|
||||
# matches.
|
||||
#
|
||||
# configurations = #<ActiveRecord::DatabaseConfigurations:0x00007fd9fdace3e0
|
||||
# @configurations=[
|
||||
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd9fdace250
|
||||
# @env_name="production", @spec_name="primary", @config={database: "my_db"}>
|
||||
# ]>
|
||||
#
|
||||
# Resolver.new(configurations).resolve_symbol_connection(:production, "primary")
|
||||
# # => DatabaseConfigurations::HashConfig(config: database: "my_db", env_name: "production", spec_name: "primary")
|
||||
def resolve_symbol_connection(env_name, pool_name)
|
||||
db_config = configurations.find_db_config(env_name)
|
||||
|
||||
if db_config
|
||||
config = db_config.configuration_hash.merge(name: pool_name.to_s)
|
||||
DatabaseConfigurations::HashConfig.new(db_config.env_name, db_config.spec_name, config)
|
||||
else
|
||||
raise AdapterNotSpecified, <<~MSG
|
||||
The `#{env_name}` database is not configured for the `#{ActiveRecord::ConnectionHandling::DEFAULT_ENV.call}` environment.
|
||||
|
||||
Available databases configurations are:
|
||||
|
||||
#{build_configuration_sentence}
|
||||
MSG
|
||||
end
|
||||
end
|
||||
|
||||
def build_configuration_sentence # :nodoc:
|
||||
configs = configurations.configs_for(include_replicas: true)
|
||||
|
||||
configs.group_by(&:env_name).map do |env, config|
|
||||
namespaces = config.map(&:spec_name)
|
||||
if namespaces.size > 1
|
||||
"#{env}: #{namespaces.join(", ")}"
|
||||
else
|
||||
env
|
||||
end
|
||||
end.join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -183,7 +183,7 @@ module ActiveRecord
|
|||
pool_name = primary_class? ? "primary" : name
|
||||
self.connection_specification_name = pool_name
|
||||
|
||||
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
|
||||
resolver = ConnectionAdapters::Resolver.new(Base.configurations)
|
||||
config_hash = resolver.resolve(config_or_env, pool_name).configuration_hash
|
||||
config_hash[:name] = pool_name
|
||||
|
||||
|
@ -227,7 +227,7 @@ module ActiveRecord
|
|||
#
|
||||
# Please use only for reading.
|
||||
def connection_config
|
||||
connection_pool.spec.underlying_configuration_hash
|
||||
connection_pool.spec.db_config.configuration_hash
|
||||
end
|
||||
|
||||
def connection_pool
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
require "active_record/database_configurations/database_config"
|
||||
require "active_record/database_configurations/hash_config"
|
||||
require "active_record/database_configurations/url_config"
|
||||
require "active_record/database_configurations/connection_url_resolver"
|
||||
|
||||
module ActiveRecord
|
||||
# ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveRecord
|
||||
class DatabaseConfigurations
|
||||
# Expands a connection string into a hash.
|
||||
class ConnectionUrlResolver # :nodoc:
|
||||
# == Example
|
||||
#
|
||||
# url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
|
||||
# ConnectionUrlResolver.new(url).to_hash
|
||||
# # => {
|
||||
# adapter: "postgresql",
|
||||
# host: "localhost",
|
||||
# port: 9000,
|
||||
# database: "foo_test",
|
||||
# username: "foo",
|
||||
# password: "bar",
|
||||
# pool: "5",
|
||||
# timeout: "3000"
|
||||
# }
|
||||
def initialize(url)
|
||||
raise "Database URL cannot be empty" if url.blank?
|
||||
@uri = uri_parser.parse(url)
|
||||
@adapter = @uri.scheme && @uri.scheme.tr("-", "_")
|
||||
@adapter = "postgresql" if @adapter == "postgres"
|
||||
|
||||
if @uri.opaque
|
||||
@uri.opaque, @query = @uri.opaque.split("?", 2)
|
||||
else
|
||||
@query = @uri.query
|
||||
end
|
||||
end
|
||||
|
||||
# Converts the given URL to a full connection hash.
|
||||
def to_hash
|
||||
config = raw_config.compact_blank
|
||||
config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
|
||||
config
|
||||
end
|
||||
|
||||
private
|
||||
attr_reader :uri
|
||||
|
||||
def uri_parser
|
||||
@uri_parser ||= URI::Parser.new
|
||||
end
|
||||
|
||||
# Converts the query parameters of the URI into a hash.
|
||||
#
|
||||
# "localhost?pool=5&reaping_frequency=2"
|
||||
# # => { pool: "5", reaping_frequency: "2" }
|
||||
#
|
||||
# returns empty hash if no query present.
|
||||
#
|
||||
# "localhost"
|
||||
# # => {}
|
||||
def query_hash
|
||||
Hash[(@query || "").split("&").map { |pair| pair.split("=") }].symbolize_keys
|
||||
end
|
||||
|
||||
def raw_config
|
||||
if uri.opaque
|
||||
query_hash.merge(
|
||||
adapter: @adapter,
|
||||
database: uri.opaque
|
||||
)
|
||||
else
|
||||
query_hash.merge(
|
||||
adapter: @adapter,
|
||||
username: uri.user,
|
||||
password: uri.password,
|
||||
port: uri.port,
|
||||
database: database_from_path,
|
||||
host: uri.hostname
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns name of the database.
|
||||
def database_from_path
|
||||
if @adapter == "sqlite3"
|
||||
# 'sqlite3:/foo' is absolute, because that makes sense. The
|
||||
# corresponding relative version, 'sqlite3:foo', is handled
|
||||
# elsewhere, as an "opaque".
|
||||
|
||||
uri.path
|
||||
else
|
||||
# Only SQLite uses a filename as the "database" name; for
|
||||
# anything else, a leading slash would be silly.
|
||||
|
||||
uri.path.sub(%r{^/}, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,8 +18,12 @@ module ActiveRecord
|
|||
configuration_hash.stringify_keys
|
||||
end
|
||||
|
||||
def initialize_dup(original)
|
||||
@config = original.configuration_hash.dup
|
||||
def adapter_method
|
||||
"#{adapter}_connection"
|
||||
end
|
||||
|
||||
def adapter
|
||||
configuration_hash[:adapter]
|
||||
end
|
||||
|
||||
def replica?
|
||||
|
|
|
@ -53,7 +53,7 @@ module ActiveRecord
|
|||
private
|
||||
def resolve_url_key
|
||||
if configuration_hash[:url] && !configuration_hash[:url].match?(/^jdbc:/)
|
||||
connection_hash = ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(configuration_hash[:url]).to_hash
|
||||
connection_hash = ConnectionUrlResolver.new(configuration_hash[:url]).to_hash
|
||||
configuration_hash.merge!(connection_hash)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -64,7 +64,7 @@ module ActiveRecord
|
|||
if url.nil? || /^jdbc:/.match?(url)
|
||||
{ url: url }
|
||||
else
|
||||
ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(url).to_hash
|
||||
ConnectionUrlResolver.new(url).to_hash
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ module ActiveRecord
|
|||
if options.has_key?(:config)
|
||||
@current_config = options[:config]
|
||||
else
|
||||
@current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: options[:env], spec_name: options[:spec]).underlying_configuration_hash
|
||||
@current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: options[:env], spec_name: options[:spec]).db_config.configuration_hash
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -136,7 +136,7 @@ module ActiveRecord
|
|||
old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
|
||||
each_local_configuration { |configuration| create configuration }
|
||||
if old_pool
|
||||
ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.to_hash)
|
||||
ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.db_config.configuration_hash)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module ActiveRecord
|
|||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
db = Post.connection_pool.spec.underlying_configuration_hash[:database]
|
||||
db = Post.connection_pool.spec.db_config.configuration_hash[:database]
|
||||
table = Post.table_name
|
||||
@db_name = db
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ module ActiveRecord
|
|||
|
||||
def test_close
|
||||
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "primary", {})
|
||||
pool = Pool.new(ConnectionSpecification.new("primary", db_config, nil))
|
||||
pool = Pool.new(ConnectionSpecification.new("primary", db_config))
|
||||
pool.insert_connection_for_test! @adapter
|
||||
@adapter.pool = pool
|
||||
|
||||
|
|
|
@ -27,13 +27,14 @@ module ActiveRecord
|
|||
ENV["RACK_ENV"] = original_rack_env
|
||||
end
|
||||
|
||||
def test_establish_connection_uses_spec_name
|
||||
def test_establish_connection_uses_config_hash_with_spec_name
|
||||
old_config = ActiveRecord::Base.configurations
|
||||
config = { "readonly" => { "adapter" => "sqlite3", "pool" => "5" } }
|
||||
ActiveRecord::Base.configurations = config
|
||||
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
|
||||
spec = resolver.spec(:readonly)
|
||||
@handler.establish_connection(spec.to_hash)
|
||||
resolver = ConnectionAdapters::Resolver.new(ActiveRecord::Base.configurations)
|
||||
config_hash = resolver.resolve(config["readonly"], "readonly").configuration_hash
|
||||
config_hash[:name] = "readonly"
|
||||
@handler.establish_connection(config_hash)
|
||||
|
||||
assert_not_nil @handler.retrieve_connection_pool("readonly")
|
||||
ensure
|
||||
|
@ -62,13 +63,13 @@ module ActiveRecord
|
|||
@handler.establish_connection(:readonly)
|
||||
|
||||
assert_not_nil pool = @handler.retrieve_connection_pool("readonly")
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
|
||||
assert_not_nil pool = @handler.retrieve_connection_pool("primary")
|
||||
assert_equal "db/primary.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/primary.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
|
||||
assert_not_nil pool = @handler.retrieve_connection_pool("common")
|
||||
assert_equal "db/common.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/common.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
ENV["RAILS_ENV"] = previous_env
|
||||
|
@ -92,7 +93,7 @@ module ActiveRecord
|
|||
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
||||
assert_match "db/primary.sqlite3", ActiveRecord::Base.connection.pool.spec.underlying_configuration_hash[:database]
|
||||
assert_match "db/primary.sqlite3", ActiveRecord::Base.connection.pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
ENV["RAILS_ENV"] = previous_env
|
||||
|
@ -115,7 +116,7 @@ module ActiveRecord
|
|||
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
||||
assert_match "db/primary.sqlite3", ActiveRecord::Base.connection.pool.spec.underlying_configuration_hash[:database]
|
||||
assert_match "db/primary.sqlite3", ActiveRecord::Base.connection.pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
ENV["RAILS_ENV"] = previous_env
|
||||
|
@ -131,7 +132,7 @@ module ActiveRecord
|
|||
@handler.establish_connection(:development)
|
||||
|
||||
assert_not_nil pool = @handler.retrieve_connection_pool("development")
|
||||
assert_equal "db/primary.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/primary.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
end
|
||||
|
@ -146,7 +147,7 @@ module ActiveRecord
|
|||
@handler.establish_connection(:development_readonly)
|
||||
|
||||
assert_not_nil pool = @handler.retrieve_connection_pool("development_readonly")
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
end
|
||||
|
@ -210,7 +211,7 @@ module ActiveRecord
|
|||
|
||||
assert_same klass2.connection, ActiveRecord::Base.connection
|
||||
|
||||
pool = klass2.establish_connection(ActiveRecord::Base.connection_pool.spec.underlying_configuration_hash)
|
||||
pool = klass2.establish_connection(ActiveRecord::Base.connection_pool.spec.db_config.configuration_hash)
|
||||
assert_same klass2.connection, pool.connection
|
||||
assert_not_same klass2.connection, ActiveRecord::Base.connection
|
||||
|
||||
|
|
|
@ -82,10 +82,10 @@ module ActiveRecord
|
|||
ActiveRecord::Base.connects_to(database: { writing: :primary, reading: :readonly })
|
||||
|
||||
assert_not_nil pool = ActiveRecord::Base.connection_handlers[:writing].retrieve_connection_pool("primary")
|
||||
assert_equal "db/primary.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/primary.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
|
||||
assert_not_nil pool = ActiveRecord::Base.connection_handlers[:reading].retrieve_connection_pool("primary")
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
ActiveRecord::Base.establish_connection(:arunit)
|
||||
|
@ -140,10 +140,10 @@ module ActiveRecord
|
|||
ActiveRecord::Base.connects_to(database: { default: :primary, readonly: :readonly })
|
||||
|
||||
assert_not_nil pool = ActiveRecord::Base.connection_handlers[:default].retrieve_connection_pool("primary")
|
||||
assert_equal "db/primary.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/primary.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
|
||||
assert_not_nil pool = ActiveRecord::Base.connection_handlers[:readonly].retrieve_connection_pool("primary")
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
ActiveRecord::Base.establish_connection(:arunit)
|
||||
|
@ -162,7 +162,7 @@ module ActiveRecord
|
|||
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
|
||||
|
||||
assert_not_nil pool = handler.retrieve_connection_pool("primary")
|
||||
assert_equal({ adapter: "postgresql", database: "bar", host: "localhost" }, pool.spec.underlying_configuration_hash)
|
||||
assert_equal({ adapter: "postgresql", database: "bar", host: "localhost" }, pool.spec.db_config.configuration_hash)
|
||||
end
|
||||
ensure
|
||||
ActiveRecord::Base.establish_connection(:arunit)
|
||||
|
@ -182,7 +182,7 @@ module ActiveRecord
|
|||
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
|
||||
|
||||
assert_not_nil pool = handler.retrieve_connection_pool("primary")
|
||||
assert_equal(config, pool.spec.underlying_configuration_hash)
|
||||
assert_equal(config, pool.spec.db_config.configuration_hash)
|
||||
end
|
||||
ensure
|
||||
ActiveRecord::Base.establish_connection(:arunit)
|
||||
|
@ -222,7 +222,7 @@ module ActiveRecord
|
|||
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
|
||||
|
||||
assert_not_nil pool = handler.retrieve_connection_pool("primary")
|
||||
assert_equal(config["default_env"]["animals"], pool.spec.underlying_configuration_hash)
|
||||
assert_equal(config["default_env"]["animals"], pool.spec.db_config.configuration_hash)
|
||||
end
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
|
@ -249,7 +249,7 @@ module ActiveRecord
|
|||
assert_equal handler, ActiveRecord::Base.connection_handlers[:writing]
|
||||
|
||||
assert_not_nil pool = handler.retrieve_connection_pool("primary")
|
||||
assert_equal(config["default_env"]["primary"], pool.spec.underlying_configuration_hash)
|
||||
assert_equal(config["default_env"]["primary"], pool.spec.db_config.configuration_hash)
|
||||
end
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
|
@ -284,7 +284,7 @@ module ActiveRecord
|
|||
ActiveRecord::Base.connects_to database: { writing: :development, reading: :development_readonly }
|
||||
|
||||
assert_not_nil pool = ActiveRecord::Base.connection_handlers[:reading].retrieve_connection_pool("primary")
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.underlying_configuration_hash[:database]
|
||||
assert_equal "db/readonly.sqlite3", pool.spec.db_config.configuration_hash[:database]
|
||||
ensure
|
||||
ActiveRecord::Base.configurations = @prev_configs
|
||||
ActiveRecord::Base.establish_connection(:arunit)
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "cases/helper"
|
||||
|
||||
module ActiveRecord
|
||||
module ConnectionAdapters
|
||||
class ConnectionSpecificationTest < ActiveRecord::TestCase
|
||||
def test_dup_deep_copy_config
|
||||
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("development", "primary", { a: :b })
|
||||
spec = ConnectionSpecification.new("primary", db_config, "bar")
|
||||
assert_not_equal(spec.underlying_configuration_hash.object_id, spec.dup.underlying_configuration_hash.object_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -24,7 +24,7 @@ module ActiveRecord
|
|||
|
||||
def resolve_spec(spec, config)
|
||||
configs = ActiveRecord::DatabaseConfigurations.new(config)
|
||||
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(configs)
|
||||
resolver = ConnectionAdapters::Resolver.new(configs)
|
||||
resolver.resolve(spec, spec).configuration_hash
|
||||
end
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ module ActiveRecord
|
|||
def test_idle_timeout_configuration
|
||||
@pool.disconnect!
|
||||
spec = ActiveRecord::Base.connection_pool.spec
|
||||
spec.underlying_configuration_hash.merge!(idle_timeout: "0.02")
|
||||
spec.db_config.configuration_hash.merge!(idle_timeout: "0.02")
|
||||
@pool = ConnectionPool.new(spec)
|
||||
idle_conn = @pool.checkout
|
||||
@pool.checkin(idle_conn)
|
||||
|
@ -224,7 +224,7 @@ module ActiveRecord
|
|||
def test_disable_flush
|
||||
@pool.disconnect!
|
||||
spec = ActiveRecord::Base.connection_pool.spec
|
||||
spec.underlying_configuration_hash.merge!(idle_timeout: -5)
|
||||
spec.db_config.configuration_hash.merge!(idle_timeout: -5)
|
||||
@pool = ConnectionPool.new(spec)
|
||||
idle_conn = @pool.checkout
|
||||
@pool.checkin(idle_conn)
|
||||
|
@ -718,8 +718,12 @@ module ActiveRecord
|
|||
|
||||
private
|
||||
def with_single_connection_pool
|
||||
one_conn_spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
one_conn_spec.underlying_configuration_hash[:pool] = 1 # this is safe to do, because .dupped ConnectionSpecification also auto-dups its config
|
||||
old_config = ActiveRecord::Base.connection_pool.spec.db_config.configuration_hash
|
||||
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", old_config.dup)
|
||||
one_conn_spec = ConnectionSpecification.new("primary", db_config)
|
||||
|
||||
one_conn_spec.db_config.configuration_hash[:pool] = 1 # this is safe to do, because .dupped ConnectionSpecification also auto-dups its config
|
||||
|
||||
yield(pool = ConnectionPool.new(one_conn_spec))
|
||||
ensure
|
||||
pool.disconnect! if pool
|
||||
|
|
|
@ -8,13 +8,13 @@ module ActiveRecord
|
|||
class ResolverTest < ActiveRecord::TestCase
|
||||
def resolve(spec, config = {})
|
||||
configs = ActiveRecord::DatabaseConfigurations.new(config)
|
||||
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(configs)
|
||||
resolver = ConnectionAdapters::Resolver.new(configs)
|
||||
resolver.resolve(spec, spec).configuration_hash
|
||||
end
|
||||
|
||||
def spec(spec, config = {})
|
||||
configs = ActiveRecord::DatabaseConfigurations.new(config)
|
||||
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(configs)
|
||||
resolver = ConnectionAdapters::Resolver.new(configs)
|
||||
resolver.spec(spec)
|
||||
end
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ end
|
|||
|
||||
def in_memory_db?
|
||||
current_adapter?(:SQLite3Adapter) &&
|
||||
ActiveRecord::Base.connection_pool.spec.underlying_configuration_hash[:database] == ":memory:"
|
||||
ActiveRecord::Base.connection_pool.spec.db_config.configuration_hash[:database] == ":memory:"
|
||||
end
|
||||
|
||||
def subsecond_precision_supported?
|
||||
|
|
|
@ -58,7 +58,8 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def test_pool_has_reaper
|
||||
spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", spec_name: "primary")
|
||||
spec = ConnectionSpecification.new("primary", config)
|
||||
pool = ConnectionPool.new spec
|
||||
|
||||
assert pool.reaper
|
||||
|
@ -67,17 +68,19 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def test_reaping_frequency_configuration
|
||||
spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
spec.underlying_configuration_hash[:reaping_frequency] = "10.01"
|
||||
spec = duplicated_spec
|
||||
spec.db_config.configuration_hash[:reaping_frequency] = "10.01"
|
||||
|
||||
pool = ConnectionPool.new spec
|
||||
|
||||
assert_equal 10.01, pool.reaper.frequency
|
||||
ensure
|
||||
pool.discard!
|
||||
end
|
||||
|
||||
def test_connection_pool_starts_reaper
|
||||
spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
spec.underlying_configuration_hash[:reaping_frequency] = "0.0001"
|
||||
spec = duplicated_spec
|
||||
spec.db_config.configuration_hash[:reaping_frequency] = "0.0001"
|
||||
|
||||
pool = ConnectionPool.new spec
|
||||
|
||||
|
@ -94,8 +97,8 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def test_reaper_works_after_pool_discard
|
||||
spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
spec.underlying_configuration_hash[:reaping_frequency] = "0.0001"
|
||||
spec = duplicated_spec
|
||||
spec.db_config.configuration_hash[:reaping_frequency] = "0.0001"
|
||||
|
||||
2.times do
|
||||
pool = ConnectionPool.new spec
|
||||
|
@ -116,7 +119,7 @@ module ActiveRecord
|
|||
# This doesn't test the reaper directly, but we want to test the action
|
||||
# it would take on a discarded pool
|
||||
def test_reap_flush_on_discarded_pool
|
||||
spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
spec = duplicated_spec
|
||||
pool = ConnectionPool.new spec
|
||||
|
||||
pool.discard!
|
||||
|
@ -125,8 +128,8 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def test_connection_pool_starts_reaper_in_fork
|
||||
spec = ActiveRecord::Base.connection_pool.spec.dup
|
||||
spec.underlying_configuration_hash[:reaping_frequency] = "0.0001"
|
||||
spec = duplicated_spec
|
||||
spec.db_config.configuration_hash[:reaping_frequency] = "0.0001"
|
||||
|
||||
pool = ConnectionPool.new spec
|
||||
pool.checkout
|
||||
|
@ -169,6 +172,13 @@ module ActiveRecord
|
|||
pool.discard!
|
||||
end
|
||||
|
||||
private
|
||||
def duplicated_spec
|
||||
old_config = ActiveRecord::Base.connection_pool.spec.db_config.configuration_hash
|
||||
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new("arunit", "primary", old_config.dup)
|
||||
ConnectionSpecification.new("primary", db_config)
|
||||
end
|
||||
|
||||
def new_conn_in_thread(pool)
|
||||
event = Concurrent::Event.new
|
||||
conn = nil
|
||||
|
|
|
@ -359,7 +359,7 @@ module ApplicationTests
|
|||
db_migrate_and_schema_dump_and_load "schema"
|
||||
|
||||
app_file "db/seeds.rb", <<-RUBY
|
||||
print Book.connection.pool.spec.underlying_configuration_hash[:database]
|
||||
print Book.connection.pool.spec.db_config.configuration_hash[:database]
|
||||
RUBY
|
||||
|
||||
output = rails("db:seed")
|
||||
|
|
Loading…
Reference in New Issue