123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::ConnectionAdapters::ConnectionHandler

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

Instance Attribute Summary

Instance Method Summary

Constructor Details

.newConnectionHandler

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

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

Raises:

  • (RuntimeError)
[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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.

[ GitHub ]

  
# 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