класс ActiveRecord::ConnectionAdapters::ConnectionHandler
ConnectionHandler — это коллекция объектов ConnectionPool. Она используется для хранения отдельных пулов соединений для моделей Active Record, которые подключаются к различным базам данных.
Например, предположим, что у вас есть 5 моделей с такой иерархией:
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
И файл database.yml, который выглядит так:
development: database: my_application host: localhost library_db: database: library host: some.library.org
Ваша основная база данных в среде разработки — «my_application», но модель Book подключается к отдельной базе данных под названием «library_db» (она может даже находиться на другом компьютере).
Book, ScaryBook и GoodBook будут использовать один и тот же пул соединений для «library_db», в то время как Author, BankAccount и любые другие создаваемые вами модели будут использовать стандартный пул соединений для «my_application».
Различные пулы соединений управляются одной экземпляром ConnectionHandler, доступной через ActiveRecord::Core.connection_handler. Все модели Active Record используют этот обработчик для определения пула соединений, который они должны использовать.
Публичные методы класса
# 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 Публичные методы экземпляра
# File activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb, line 544 def active_connections? connection_pool_list.any?(&:active_connection?) end
Возвращает true, если среди пулов соединений, управляемых ConnectionHandler, существуют активные соединения.
# 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
# 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
Очищает кэш, сопоставляющий классы.
# 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
Возвращает true, если для этого класса уже открыто доступное соединение.
# 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
# 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 Удаляет соединение для этого класса. Это закроет активное соединение и определенное соединение (если они существуют). Результат можно использовать в качестве аргумента для #establish_connection для лёгкого повторного установления соединения.
# 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 Извлечение пула соединений происходит часто, поэтому мы кэшируем его в @class_to_pool. Это делает извлечение пула соединений O(1) после того, как процесс прогреется. При установлении или удалении соединения мы аннулируем кэш.
В идеале, мы бы использовали fetch здесь, так как class_to_pool иногда может быть пустым. Однако, бенчмаркинг (gist.github.com/jonleighton/3552829) показал, что fetch значительно медленнее, чем []. Поэтому в случае null-значения кэширование не произойдёт, но это нормально, так как случай null-значения не является распространённым, для которого мы хотели бы оптимизировать.
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.