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 ActiveRecord::Core.connection_handler. All Active Record models use this handler to determine the connection pool that they should use.
# 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
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
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
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 560 def clear_all_connections! connection_pool_list.each(&:disconnect!) end
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
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
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 523 def connection_pool_list owner_to_pool.values.compact end
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 527 def connection_pools ActiveSupport::Deprecation.warn(" 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.) ".squish) Hash[connection_pool_list.map { |pool| [pool.spec, pool] }] end
# 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 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
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
© 2004–2017 David Heinemeier Hansson
Licensed under the MIT License.