5
# Raised when a connection could not be obtained within the connection
6
# acquisition timeout period.
7
class ConnectionTimeoutError < ConnectionNotEstablished
10
module ConnectionAdapters
11
# Connection pool base class for managing ActiveRecord database
16
# A connection pool synchronizes thread access to a limited number of
17
# database connections. The basic idea is that each thread checks out a
18
# database connection from the pool, uses that connection, and checks the
19
# connection back in. ConnectionPool is completely thread-safe, and will
20
# ensure that a connection cannot be used by two threads at the same time,
21
# as long as ConnectionPool's contract is correctly followed. It will also
22
# handle cases in which there are more threads than connections: if all
23
# connections have been checked out, and a thread tries to checkout a
24
# connection anyway, then ConnectionPool will wait until some other thread
25
# has checked in a connection.
27
# == Obtaining (checking out) a connection
29
# Connections can be obtained and used from a connection pool in several
32
# 1. Simply use ActiveRecord::Base.connection as with ActiveRecord 2.1 and
33
# earlier (pre-connection-pooling). Eventually, when you're done with
34
# the connection(s) and wish it to be returned to the pool, you call
35
# ActiveRecord::Base.clear_active_connections!. This will be the
36
# default behavior for ActiveRecord when used in conjunction with
37
# ActionPack's request handling cycle.
38
# 2. Manually check out a connection from the pool with
39
# ActiveRecord::Base.connection_pool.checkout. You are responsible for
40
# returning this connection to the pool when finished by calling
41
# ActiveRecord::Base.connection_pool.checkin(connection).
42
# 3. Use ActiveRecord::Base.connection_pool.with_connection(&block), which
43
# obtains a connection, yields it as the sole argument to the block,
44
# and returns it to the pool after the block completes.
46
# Connections in the pool are actually AbstractAdapter objects (or objects
47
# compatible with AbstractAdapter's interface).
51
# There are two connection-pooling-related options that you can add to
52
# your database connection configuration:
54
# * +pool+: number indicating size of connection pool (default 5)
55
# * +wait_timeout+: number of seconds to block and wait for a connection
56
# before giving up and raising a timeout error (default 5 seconds).
60
# Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
61
# object which describes database connection information (e.g. adapter,
62
# host name, username, password, etc), as well as the maximum size for
63
# this ConnectionPool.
65
# The default ConnectionPool maximum size is 5.
69
# The cache of reserved connections mapped to threads
70
@reserved_connections = {}
72
# The mutex used to synchronize pool access
73
@connection_mutex = Monitor.new
74
@queue = @connection_mutex.new_cond
76
# default 5 second timeout unless on ruby 1.9
78
if RUBY_VERSION < '1.9'
79
spec.config[:wait_timeout] || 5
82
# default max pool size to 5
83
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
89
# Retrieve the connection associated with the current thread, or call
90
# #checkout to obtain one if necessary.
92
# #connection can be called any number of times; the connection is
93
# held in a hash keyed by the thread id.
95
if conn = @reserved_connections[current_connection_id]
98
@reserved_connections[current_connection_id] = checkout
102
# Signal that the thread is finished with the current connection.
103
# #release_connection releases the connection-thread association
104
# and returns the connection to the pool.
105
def release_connection
106
conn = @reserved_connections.delete(current_connection_id)
110
# Reserve a connection, and yield it to a block. Ensure the connection is
111
# checked back in when finished.
119
# Returns true if a connection has already been opened.
124
# Disconnects all connections in the pool, and clears the pool.
126
@reserved_connections.each do |name,conn|
129
@reserved_connections = {}
130
@connections.each do |conn|
136
# Clears the cache which maps classes
137
def clear_reloadable_connections!
138
@reserved_connections.each do |name, conn|
141
@reserved_connections = {}
142
@connections.each do |conn|
143
conn.disconnect! if conn.requires_reloading?
148
# Verify active connections and remove and disconnect connections
149
# associated with stale threads.
150
def verify_active_connections! #:nodoc:
151
clear_stale_cached_connections!
152
@connections.each do |connection|
157
# Return any checked-out connections back to the pool by threads that
158
# are no longer alive.
159
def clear_stale_cached_connections!
160
remove_stale_cached_threads!(@reserved_connections) do |name, conn|
165
# Check-out a database connection from the pool, indicating that you want
166
# to use it. You should call #checkin when you no longer need this.
168
# This is done by either returning an existing connection, or by creating
169
# a new connection. If the maximum number of connections for this pool has
170
# already been reached, but the pool is empty (i.e. they're all being used),
171
# then this method will wait until a thread has checked in a connection.
172
# The wait time is bounded however: if no connection can be checked out
173
# within the timeout specified for this pool, then a ConnectionTimeoutError
174
# exception will be raised.
176
# Returns: an AbstractAdapter object.
179
# - ConnectionTimeoutError: no connection can be obtained from the pool
180
# within the timeout period.
182
# Checkout an available connection
183
@connection_mutex.synchronize do
185
conn = if @checked_out.size < @connections.size
186
checkout_existing_connection
187
elsif @connections.size < @size
188
checkout_new_connection
191
# No connections available; wait for one
192
if @queue.wait(@timeout)
195
# try looting dead threads
196
clear_stale_cached_connections!
197
if @size == @checked_out.size
198
raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
205
# Check-in a database connection back into the pool, indicating that you
206
# no longer need this connection.
208
# +conn+: an AbstractAdapter object, which was obtained by earlier by
209
# calling +checkout+ on this pool.
211
@connection_mutex.synchronize do
212
conn.run_callbacks :checkin
213
@checked_out.delete conn
218
synchronize :clear_reloadable_connections!, :verify_active_connections!,
219
:connected?, :disconnect!, :with => :@connection_mutex
223
ActiveRecord::Base.send(spec.adapter_method, spec.config)
226
def current_connection_id #:nodoc:
227
Thread.current.object_id
230
# Remove stale threads from the cache.
231
def remove_stale_cached_threads!(cache, &block)
232
keys = Set.new(cache.keys)
234
Thread.list.each do |thread|
235
keys.delete(thread.object_id) if thread.alive?
238
next unless cache.has_key?(key)
239
block.call(key, cache[key])
244
def checkout_new_connection
247
checkout_and_verify(c)
250
def checkout_existing_connection
251
c = (@connections - @checked_out).first
252
checkout_and_verify(c)
255
def checkout_and_verify(c)
257
c.run_callbacks :checkout
263
# ConnectionHandler is a collection of ConnectionPool objects. It is used
264
# for keeping separate connection pools for ActiveRecord models that connect
265
# to different databases.
267
# For example, suppose that you have 5 models, with the following hierarchy:
277
# Suppose that Book is to connect to a separate database (i.e. one other
278
# than the default database). Then Book, ScaryBook and GoodBook will all use
279
# the same connection pool. Likewise, Author and BankAccount will use the
280
# same connection pool. However, the connection pool used by Author/BankAccount
281
# is not the same as the one used by Book/ScaryBook/GoodBook.
283
# Normally there is only a single ConnectionHandler instance, accessible via
284
# ActiveRecord::Base.connection_handler. ActiveRecord models use this to
285
# determine that connection pool that they should use.
286
class ConnectionHandler
287
def initialize(pools = {})
288
@connection_pools = pools
292
@connection_pools ||= {}
295
def establish_connection(name, spec)
296
@connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
299
# Returns any connections in use by the current thread back to the pool,
300
# and also returns connections to the pool cached by threads that are no
302
def clear_active_connections!
303
@connection_pools.each_value {|pool| pool.release_connection }
306
# Clears the cache which maps classes
307
def clear_reloadable_connections!
308
@connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
311
def clear_all_connections!
312
@connection_pools.each_value {|pool| pool.disconnect! }
315
# Verify active connections.
316
def verify_active_connections! #:nodoc:
317
@connection_pools.each_value {|pool| pool.verify_active_connections! }
320
# Locate the connection of the nearest super class. This can be an
321
# active or defined connection: if it is the latter, it will be
322
# opened and set as the active connection for the class it was defined
323
# for (not necessarily the current class).
324
def retrieve_connection(klass) #:nodoc:
325
pool = retrieve_connection_pool(klass)
326
(pool && pool.connection) or raise ConnectionNotEstablished
329
# Returns true if a connection that's accessible to this class has
330
# already been opened.
331
def connected?(klass)
332
conn = retrieve_connection_pool(klass)
333
conn ? conn.connected? : false
336
# Remove the connection for this class. This will close the active
337
# connection and the defined connection (if they exist). The result
338
# can be used as an argument for establish_connection, for easily
339
# re-establishing the connection.
340
def remove_connection(klass)
341
pool = @connection_pools[klass.name]
342
@connection_pools.delete_if { |key, value| value == pool }
343
pool.disconnect! if pool
344
pool.spec.config if pool
347
def retrieve_connection_pool(klass)
348
pool = @connection_pools[klass.name]
350
return nil if ActiveRecord::Base == klass
351
retrieve_connection_pool klass.superclass
355
class ConnectionManagement
363
# Don't return connection (and peform implicit rollback) if
364
# this request is a part of integration test
365
unless env.key?("rack.test")
366
ActiveRecord::Base.clear_active_connections!