diff options
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb')
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb new file mode 100644 index 0000000000..8685988e80 --- /dev/null +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -0,0 +1,128 @@ +module ActiveRecord + module ConnectionAdapters + class ConnectionPool + # Check for activity after at least +verification_timeout+ seconds. + # Defaults to 0 (always check.) + attr_accessor :verification_timeout + attr_reader :active_connections, :spec + + def initialize(spec) + @verification_timeout = 0 + + # The thread id -> adapter cache. + @active_connections = {} + + # The ConnectionSpecification for this pool + @spec = spec + end + + def active_connection_name #:nodoc: + Thread.current.object_id + end + + def active_connection + active_connections[active_connection_name] + end + + # Returns the connection currently associated with the class. This can + # also be used to "borrow" the connection to do database work unrelated + # to any of the specific Active Records. + def connection + if conn = active_connections[active_connection_name] + conn + else + # retrieve_connection sets the cache key. + conn = retrieve_connection + active_connections[active_connection_name] = conn + end + end + + # Clears the cache which maps classes to connections. + def clear_active_connections! + clear_entries!(@active_connections, [active_connection_name]) do |name, conn| + conn.disconnect! + end + end + + # Clears the cache which maps classes + def clear_reloadable_connections! + @active_connections.each do |name, conn| + if conn.requires_reloading? + conn.disconnect! + @active_connections.delete(name) + end + end + end + + # Verify active connections. + def verify_active_connections! #:nodoc: + remove_stale_cached_threads!(@active_connections) do |name, conn| + conn.disconnect! + end + active_connections.each_value do |connection| + connection.verify!(@verification_timeout) + end + end + + def retrieve_connection #:nodoc: + # Name is nil if establish_connection hasn't been called for + # some class along the inheritance chain up to AR::Base yet. + name = active_connection_name + if conn = active_connections[name] + # Verify the connection. + conn.verify!(@verification_timeout) + else + self.connection = spec + conn = active_connections[name] + end + + conn or raise ConnectionNotEstablished + end + + # Returns true if a connection that's accessible to this class has already been opened. + def connected? + active_connections[active_connection_name] ? true : false + end + + def disconnect! + clear_cache!(@active_connections) do |name, conn| + conn.disconnect! + end + end + + # Set the connection for the class. + def connection=(spec) #:nodoc: + if spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter) + active_connections[active_connection_name] = spec + elsif spec.kind_of?(ActiveRecord::Base::ConnectionSpecification) + self.connection = ActiveRecord::Base.send(spec.adapter_method, spec.config) + else + raise ConnectionNotEstablished + end + end + + private + def clear_cache!(cache, &block) + cache.each(&block) if block_given? + cache.clear + end + + # Remove stale threads from the cache. + def remove_stale_cached_threads!(cache, &block) + stale = Set.new(cache.keys) + + Thread.list.each do |thread| + stale.delete(thread.object_id) if thread.alive? + end + clear_entries!(cache, stale, &block) + end + + def clear_entries!(cache, keys, &block) + keys.each do |key| + block.call(key, cache[key]) + cache.delete(key) + end + end + end + end +end
\ No newline at end of file |