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