class ActiveRecord::ConnectionAdapters::ConnectionPool
5 seconds).
after which the Reaper will consider a connection reapable. (default
* dead_connection_timeout
: number of seconds from last checkout
run the Reaper).
thread or a thread dies unexpectedly. (Default nil, which means don’t
occur if a programmer forgets to close a connection at the end of a
Reaper, which attempts to find and close dead connections, which can
* reaping_frequency
: frequency in seconds to periodically run the
before giving up and raising a timeout error (default 5 seconds).
* checkout_timeout
: number of seconds to block and wait for a connection
* pool
: number indicating size of connection pool (default 5)
your database connection configuration:
There are several connection-pooling-related options that you can add to
== Options
compatible with AbstractAdapter’s interface).
Connections in the pool are actually AbstractAdapter objects (or objects
and returns it to the pool after the block completes.
obtains a connection, yields it as the sole argument to the block,
3. Use ActiveRecord::Base.connection_pool.with_connection(&block), which
ActiveRecord::Base.connection_pool.checkin(connection).
returning this connection to the pool when finished by calling
ActiveRecord::Base.connection_pool.checkout. You are responsible for
2. Manually check out a connection from the pool with
Action Pack’s request handling cycle.
default behavior for Active Record when used in conjunction with
ActiveRecord::Base.clear_active_connections!. This will be the
the connection(s) and wish it to be returned to the pool, you call
earlier (pre-connection-pooling). Eventually, when you’re done with
1. Simply use ActiveRecord::Base.connection as with Active Record 2.1 and
ways:
Connections can be obtained and used from a connection pool in several
== Obtaining (checking out) a connection
has checked in a connection.
connection anyway, then ConnectionPool will wait until some other thread
connections have been checked out, and a thread tries to checkout a
handle cases in which there are more threads than connections: if all
as long as ConnectionPool’s contract is correctly followed. It will also
ensure that a connection cannot be used by two threads at the same time,
connection back in. ConnectionPool is completely thread-safe, and will
database connection from the pool, uses that connection, and checks the
database connections. The basic idea is that each thread checks out a
A connection pool synchronizes thread access to a limited number of
== Introduction
connections.
Connection pool base class for managing Active Record database
def acquire_connection
Raises:
queue for a connection to become available.
connection if the pool is not at capacity, 3) waiting on the
from the queue of available connections, 2) creating a new
Acquire a connection by one of 1) immediately removing one
def acquire_connection if conn = @available.poll conn elsif @connections.size < @size checkout_new_connection else @available.poll(@checkout_timeout) end end
def active_connection?
def active_connection? synchronize do @reserved_connections.fetch(current_connection_id) { return false }.in_use? end end
def checkin(conn)
+conn+: an AbstractAdapter object, which was obtained by earlier by
no longer need this connection.
Check-in a database connection back into the pool, indicating that you
def checkin(conn) synchronize do conn.run_callbacks :checkin do conn.expire end release conn @available.add conn end end
def checkout
Raises:
Returns: an AbstractAdapter object.
size limit set), an ActiveRecord::ConnectionTimeoutError exception will be raised.
number of currently leased connections is greater than or equal to the
If all connections are leased and the pool is at capacity (meaning the
creating a new connection and leasing it.
This is done by either returning and leasing existing connection, or by
to use it. You should call #checkin when you no longer need this.
Check-out a database connection from the pool, indicating that you want
def checkout synchronize do conn = acquire_connection conn.lease checkout_and_verify(conn) end end
def checkout_and_verify(c)
def checkout_and_verify(c) c.run_callbacks :checkout do c.verify! end c end
def checkout_new_connection
def checkout_new_connection raise ConnectionNotEstablished unless @automatic_reconnect c = new_connection c.pool = self @connections << c c end
def clear_reloadable_connections!
def clear_reloadable_connections! synchronize do @reserved_connections.clear @connections.each do |conn| checkin conn conn.disconnect! if conn.requires_reloading? end @connections.delete_if do |conn| conn.requires_reloading? end @available.clear @connections.each do |conn| @available.add conn end end end
def clear_stale_cached_connections! # :nodoc:
def clear_stale_cached_connections! # :nodoc: reap end
def connected?
def connected? synchronize { @connections.any? } end
def connection
#connection can be called any number of times; the connection is
#checkout to obtain one if necessary.
Retrieve the connection associated with the current thread, or call
def connection # this is correctly done double-checked locking # (ThreadSafe::Cache's lookups have volatile semantics) @reserved_connections[current_connection_id] || synchronize do @reserved_connections[current_connection_id] ||= checkout end end
def current_connection_id #:nodoc:
def current_connection_id #:nodoc: Base.connection_id ||= Thread.current.object_id end
def disconnect!
def disconnect! synchronize do @reserved_connections.clear @connections.each do |conn| checkin conn conn.disconnect! end @connections = [] @available.clear end end
def initialize(spec)
this ConnectionPool.
host name, username, password, etc), as well as the maximum size for
object which describes database connection information (e.g. adapter,
Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
def initialize(spec) super() @spec = spec @checkout_timeout = spec.config[:checkout_timeout] || 5 @dead_connection_timeout = spec.config[:dead_connection_timeout] || 5 @reaper = Reaper.new self, spec.config[:reaping_frequency] @reaper.run # default max pool size to 5 @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5 # The cache of reserved connections mapped to threads @reserved_connections = ThreadSafe::Cache.new(:initial_capacity => @size) @connections = [] @automatic_reconnect = true @available = Queue.new self end
def new_connection
def new_connection Base.send(spec.adapter_method, spec.config) end
def reap
if a programmer forgets to close a connection at the end of a thread
Removes dead connections from the pool. A dead connection can occur
def reap synchronize do stale = Time.now - @dead_connection_timeout connections.dup.each do |conn| if conn.in_use? && stale > conn.last_use && !conn.active? remove conn end end end end
def release(conn)
def release(conn) thread_id = if @reserved_connections[current_connection_id] == conn current_connection_id else @reserved_connections.keys.find { |k| @reserved_connections[k] == conn } end @reserved_connections.delete thread_id if thread_id end
def release_connection(with_id = current_connection_id)
#release_connection releases the connection-thread association
Signal that the thread is finished with the current connection.
def release_connection(with_id = current_connection_id) synchronize do conn = @reserved_connections.delete(with_id) checkin conn if conn end end
def remove(conn)
Remove a connection from the connection pool. The connection will
def remove(conn) synchronize do @connections.delete conn @available.delete conn # FIXME: we might want to store the key on the connection so that removing # from the reserved hash will be a little easier. release conn @available.add checkout_new_connection if @available.any_waiting? end end
def with_connection
exists checkout a connection, yield it to the block, and checkin the
If a connection already exists yield it to the block. If no connection
def with_connection connection_id = current_connection_id fresh_connection = true unless active_connection? yield connection ensure release_connection(connection_id) if fresh_connection end