aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
diff options
context:
space:
mode:
authorNick <nick@nicksieger.com>2008-04-19 00:24:01 -0500
committerNick Sieger <nick@nicksieger.com>2008-08-29 14:12:08 -0500
commit6edaa267174dfedaf5b152b9eba25b4eb5e34c99 (patch)
treec5dbbcf112bb933e653f2f89d1c1dca17c377aca /activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
parent1a81f156bd81990a50ecf13986b2131dbd20a62b (diff)
downloadrails-6edaa267174dfedaf5b152b9eba25b4eb5e34c99.tar.gz
rails-6edaa267174dfedaf5b152b9eba25b4eb5e34c99.tar.bz2
rails-6edaa267174dfedaf5b152b9eba25b4eb5e34c99.zip
Initial conversion to connection pool
So far so good, tests still run clean. Next steps: synchronize connection pool access and modification, and change allow_concurrency to simply switch a real lock for a null lock.
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.rb128
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