Class: ActiveRecord::ConnectionAdapters::ConnectionHandler
Relationships & Source Files | |
Inherits: | Object |
Defined in: | activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb |
Overview
ConnectionHandler
is a collection of ConnectionPool objects. It is used for keeping separate connection pools for Active Record models that connect to different databases.
For example, suppose that you have 5 models, with the following hierarchy:
class Author < ActiveRecord::Base
end
class BankAccount < ActiveRecord::Base
end
class Book < ActiveRecord::Base
establish_connection "library_db"
end
class ScaryBook < Book
end
class GoodBook < Book
end
And a database.yml that looked like this:
development:
database: my_application
host: localhost
library_db:
database: library
host: some.library.org
Your primary database in the development environment is “my_application” but the Book model connects to a separate database called “library_db” (this can even be a database on a different machine).
Book, ScaryBook and GoodBook will all use the same connection pool to “library_db” while Author, BankAccount, and any other models you create will use the default connection pool to “my_application”.
The various connection pools are managed by a single instance of ConnectionHandler
accessible via Base.connection_handler. All Active Record models use this handler to determine the connection pool that they should use.
Class Method Summary
- .new ⇒ ConnectionHandler constructor
Instance Attribute Summary
-
#active_connections? ⇒ Boolean
readonly
Returns true if there are any active connections among the connection pools that the
ConnectionHandler
is managing.
Instance Method Summary
-
#clear_active_connections!
Returns any connections in use by the current thread back to the pool, and also returns connections to the pool cached by threads that are no longer alive.
- #clear_all_connections!
-
#clear_reloadable_connections!
Clears the cache which maps classes.
-
#connected?(klass) ⇒ Boolean
Returns true if a connection that's accessible to this class has already been opened.
- #connection_pool_list
- #connection_pools
- #establish_connection(owner, spec)
-
#remove_connection(owner)
Remove the connection for this class.
-
#retrieve_connection_pool(klass)
Retrieving the connection pool happens a lot so we cache it in @class_to_pool.
Constructor Details
.new ⇒ ConnectionHandler
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 511
def initialize # These caches are keyed by klass.name, NOT klass. Keying them by klass # alone would lead to memory leaks in development mode as all previous # instances of the class would stay in memory. @owner_to_pool = ThreadSafe::Cache.new(:initial_capacity => 2) do |h,k| h[k] = ThreadSafe::Cache.new(:initial_capacity => 2) end @class_to_pool = ThreadSafe::Cache.new(:initial_capacity => 2) do |h,k| h[k] = ThreadSafe::Cache.new end end
Instance Attribute Details
#active_connections? ⇒ Boolean
(readonly)
Returns true if there are any active connections among the connection pools that the ConnectionHandler
is managing.
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 544
def active_connections? connection_pool_list.any?(&:active_connection?) end
Instance Method Details
#clear_active_connections!
Returns any connections in use by the current thread back to the pool, and also returns connections to the pool cached by threads that are no longer alive.
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 551
def clear_active_connections! connection_pool_list.each(&:release_connection) end
#clear_all_connections!
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 560
def clear_all_connections! connection_pool_list.each(&:disconnect!) end
#clear_reloadable_connections!
Clears the cache which maps classes.
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 556
def clear_reloadable_connections! connection_pool_list.each(&:clear_reloadable_connections!) end
#connected?(klass) ⇒ Boolean
Returns true if a connection that's accessible to this class has already been opened.
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 578
def connected?(klass) conn = retrieve_connection_pool(klass) conn && conn.connected? end
#connection_pool_list
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 523
def connection_pool_list owner_to_pool.values.compact end
#connection_pools
[ GitHub ]# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 527
def connection_pools ActiveSupport::Deprecation.warn(<<-MSG.squish) In the next release, this will return the same as `#connection_pool_list`. (An array of pools, rather than a hash mapping specs to pools.) MSG Hash[connection_pool_list.map { |pool| [pool.spec, pool] }] end
#establish_connection(owner, spec)
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 536
def establish_connection(owner, spec) @class_to_pool.clear raise RuntimeError, "Anonymous class is not allowed." unless owner.name owner_to_pool[owner.name] = ConnectionAdapters::ConnectionPool.new(spec) end
#remove_connection(owner)
Remove the connection for this class. This will close the active connection and the defined connection (if they exist). The result can be used as an argument for establish_connection, for easily re-establishing the connection.
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 587
def remove_connection(owner) if pool = owner_to_pool.delete(owner.name) @class_to_pool.clear pool.automatic_reconnect = false pool.disconnect! pool.spec.config end end
#retrieve_connection_pool(klass)
Retrieving the connection pool happens a lot so we cache it in @class_to_pool. This makes retrieving the connection pool O(1) once the process is warm. When a connection is established or removed, we invalidate the cache.
Ideally we would use #fetch
here, as class_to_pool may sometimes be nil. However, benchmarking (gist.github.com/jonleighton/3552829) showed that #fetch
is significantly slower than #[]
. So in the nil case, no caching will take place, but that's ok since the nil case is not the common one that we wish to optimise for.
# File 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb', line 605
def retrieve_connection_pool(klass) class_to_pool[klass.name] ||= begin until pool = pool_for(klass) klass = klass.superclass break unless klass <= Base end class_to_pool[klass.name] = pool end end