Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 628 lines (548 sloc) 20.759 kb
d869298 @raggi Don't depend on rubygems loading thread (for Mutex)
raggi authored
1 require 'thread'
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
2 require 'monitor'
50cd4bd @nicksieger Introduce synchronization around connection pool access
nicksieger authored
3 require 'set'
bd2f5c0 @tenderlove pushing caching and visitors down to the connection
tenderlove authored
4 require 'active_support/core_ext/module/deprecation'
50cd4bd @nicksieger Introduce synchronization around connection pool access
nicksieger authored
5
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
6 module ActiveRecord
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
7 # Raised when a connection could not be obtained within the connection
8 # acquisition timeout period.
9 class ConnectionTimeoutError < ConnectionNotEstablished
10 end
11
cceabe0 @tenderlove raise a pull full error when the connection pool is full and no connecti...
tenderlove authored
12 # Raised when a connection pool is full and another connection is requested
13 class PoolFullError < ConnectionNotEstablished
14 end
15
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
16 module ConnectionAdapters
f17159b @fxn edit pass: the names of Rails components have a space, ie, "Active Recor...
fxn authored
17 # Connection pool base class for managing Active Record database
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
18 # connections.
19 #
a293278 @lifo Merge docrails
lifo authored
20 # == Introduction
21 #
22 # A connection pool synchronizes thread access to a limited number of
23 # database connections. The basic idea is that each thread checks out a
24 # database connection from the pool, uses that connection, and checks the
25 # connection back in. ConnectionPool is completely thread-safe, and will
26 # ensure that a connection cannot be used by two threads at the same time,
27 # as long as ConnectionPool's contract is correctly followed. It will also
28 # handle cases in which there are more threads than connections: if all
29 # connections have been checked out, and a thread tries to checkout a
30 # connection anyway, then ConnectionPool will wait until some other thread
31 # has checked in a connection.
32 #
33 # == Obtaining (checking out) a connection
34 #
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
35 # Connections can be obtained and used from a connection pool in several
36 # ways:
37 #
f17159b @fxn edit pass: the names of Rails components have a space, ie, "Active Recor...
fxn authored
38 # 1. Simply use ActiveRecord::Base.connection as with Active Record 2.1 and
817a07b @nicksieger More doco and class/method renames. Now have a strategy for integration ...
nicksieger authored
39 # earlier (pre-connection-pooling). Eventually, when you're done with
40 # the connection(s) and wish it to be returned to the pool, you call
41 # ActiveRecord::Base.clear_active_connections!. This will be the
f17159b @fxn edit pass: the names of Rails components have a space, ie, "Active Recor...
fxn authored
42 # default behavior for Active Record when used in conjunction with
43 # Action Pack's request handling cycle.
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
44 # 2. Manually check out a connection from the pool with
45 # ActiveRecord::Base.connection_pool.checkout. You are responsible for
46 # returning this connection to the pool when finished by calling
47 # ActiveRecord::Base.connection_pool.checkin(connection).
48 # 3. Use ActiveRecord::Base.connection_pool.with_connection(&block), which
49 # obtains a connection, yields it as the sole argument to the block,
50 # and returns it to the pool after the block completes.
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
51 #
a293278 @lifo Merge docrails
lifo authored
52 # Connections in the pool are actually AbstractAdapter objects (or objects
53 # compatible with AbstractAdapter's interface).
54 #
55 # == Options
56 #
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
57 # There are several connection-pooling-related options that you can add to
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
58 # your database connection configuration:
59 #
60 # * +pool+: number indicating size of connection pool (default 5)
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
61 # * +checkout_timeout+: number of seconds to block and wait for a connection
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
62 # before giving up and raising a timeout error (default 5 seconds).
82b05fb @rafaelfranca Whitespaces :scissors:
rafaelfranca authored
63 # * +reaping_frequency+: frequency in seconds to periodically run the
64 # Reaper, which attempts to find and close dead connections, which can
65 # occur if a programmer forgets to close a connection at the end of a
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
66 # thread or a thread dies unexpectedly. (Default nil, which means don't
82b05fb @rafaelfranca Whitespaces :scissors:
rafaelfranca authored
67 # run the Reaper).
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
68 # * +dead_connection_timeout+: number of seconds from last checkout
69 # after which the Reaper will consider a connection reapable. (default
82b05fb @rafaelfranca Whitespaces :scissors:
rafaelfranca authored
70 # 5 seconds).
817a07b @nicksieger More doco and class/method renames. Now have a strategy for integration ...
nicksieger authored
71 class ConnectionPool
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
72 # Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
73 # with which it shares a Monitor. But could be a generic Queue.
74 #
75 # The Queue in stdlib's 'thread' could replace this class except
76 # stdlib's doesn't support waiting with a timeout.
77 class Queue
78 def initialize(lock = Monitor.new)
79 @lock = lock
80 @cond = @lock.new_cond
81 @num_waiting = 0
82 @queue = []
83 end
84
85 # Test if any threads are currently waiting on the queue.
86 def any_waiting?
87 synchronize do
88 @num_waiting > 0
89 end
90 end
91
92 # Return the number of threads currently waiting on this
93 # queue.
94 def num_waiting
95 synchronize do
96 @num_waiting
97 end
98 end
99
100 # Add +element+ to the queue. Never blocks.
101 def add(element)
102 synchronize do
103 @queue.push element
104 @cond.signal
105 end
106 end
107
108 # If +element+ is in the queue, remove and return it, or nil.
109 def delete(element)
110 synchronize do
111 @queue.delete(element)
112 end
113 end
114
115 # Remove all elements from the queue.
116 def clear
117 synchronize do
118 @queue.clear
119 end
120 end
121
122 # Remove the head of the queue.
123 #
124 # If +timeout+ is not given, remove and return the head the
125 # queue if the number of available elements is strictly
126 # greater than the number of threads currently waiting (that
127 # is, don't jump ahead in line). Otherwise, return nil.
128 #
129 # If +timeout+ is given, block if it there is no element
130 # available, waiting up to +timeout+ seconds for an element to
131 # become available.
132 #
133 # Raises:
134 # - ConnectionTimeoutError if +timeout+ is given and no element
135 # becomes available after +timeout+ seconds,
136 def poll(timeout = nil)
137 synchronize do
138 if timeout
139 no_wait_poll || wait_poll(timeout)
140 else
141 no_wait_poll
142 end
143 end
144 end
145
146 private
147
148 def synchronize(&block)
149 @lock.synchronize(&block)
150 end
151
152 # Test if the queue currently contains any elements.
153 def any?
154 !@queue.empty?
155 end
156
157 # A thread can remove an element from the queue without
158 # waiting if an only if the number of currently available
159 # connections is strictly greater than the number of waiting
160 # threads.
161 def can_remove_no_wait?
162 @queue.size > @num_waiting
163 end
164
165 # Removes and returns the head of the queue if possible, or nil.
166 def remove
167 @queue.shift
168 end
169
170 # Remove and return the head the queue if the number of
171 # available elements is strictly greater than the number of
172 # threads currently waiting. Otherwise, return nil.
173 def no_wait_poll
174 remove if can_remove_no_wait?
175 end
176
177 # Waits on the queue up to +timeout+ seconds, then removes and
178 # returns the head of the queue.
179 def wait_poll(timeout)
180 @num_waiting += 1
181
182 t0 = Time.now
183 elapsed = 0
184 loop do
185 @cond.wait(timeout - elapsed)
186
187 return remove if any?
188
189 elapsed = Time.now - t0
190 raise ConnectionTimeoutError if elapsed >= timeout
191 end
192 ensure
193 @num_waiting -= 1
194 end
195 end
196
41c24eb @tenderlove each connection pool has a reaper
tenderlove authored
197 # Every +frequency+ seconds, the reaper will call +reap+ on +pool+.
198 # A reaper instantiated with a nil frequency will never reap the
199 # connection pool.
641b43e @tenderlove updating the reaping frequency documentation
tenderlove authored
200 #
201 # Configure the frequency by setting "reaping_frequency" in your
82b05fb @rafaelfranca Whitespaces :scissors:
rafaelfranca authored
202 # database yaml file.
cde7692 @tenderlove introduce a timer class for reaping connections
tenderlove authored
203 class Reaper
204 attr_reader :pool, :frequency
205
206 def initialize(pool, frequency)
207 @pool = pool
208 @frequency = frequency
209 end
210
59f2696 @tenderlove rename start to run and use Thread.pass rather than sleeping to schedule...
tenderlove authored
211 def run
cde7692 @tenderlove introduce a timer class for reaping connections
tenderlove authored
212 return unless frequency
213 Thread.new(frequency, pool) { |t, p|
214 while true
215 sleep t
216 p.reap
217 end
218 }
219 end
220 end
221
c606fe2 @tenderlove push synchronization in to each method. Reduces method calls and makes
tenderlove authored
222 include MonitorMixin
223
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
224 attr_accessor :automatic_reconnect, :checkout_timeout, :dead_connection_timeout
41c24eb @tenderlove each connection pool has a reaper
tenderlove authored
225 attr_reader :spec, :connections, :size, :reaper
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
226
a293278 @lifo Merge docrails
lifo authored
227 # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
228 # object which describes database connection information (e.g. adapter,
229 # host name, username, password, etc), as well as the maximum size for
230 # this ConnectionPool.
231 #
232 # The default ConnectionPool maximum size is 5.
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
233 def initialize(spec)
c606fe2 @tenderlove push synchronization in to each method. Reduces method calls and makes
tenderlove authored
234 super()
235
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
236 @spec = spec
dd77733 @jeremy Timeout the connection pool monitor on ruby 1.8 only
jeremy authored
237
029952e @nicksieger Extract a base class for connection pools, start to flesh out reserve/re...
nicksieger authored
238 # The cache of reserved connections mapped to threads
239 @reserved_connections = {}
dd77733 @jeremy Timeout the connection pool monitor on ruby 1.8 only
jeremy authored
240
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
241 @checkout_timeout = spec.config[:checkout_timeout] || 5
242 @dead_connection_timeout = spec.config[:dead_connection_timeout]
41c24eb @tenderlove each connection pool has a reaper
tenderlove authored
243 @reaper = Reaper.new self, spec.config[:reaping_frequency]
59f2696 @tenderlove rename start to run and use Thread.pass rather than sleeping to schedule...
tenderlove authored
244 @reaper.run
dd77733 @jeremy Timeout the connection pool monitor on ruby 1.8 only
jeremy authored
245
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
246 # default max pool size to 5
247 @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
dd77733 @jeremy Timeout the connection pool monitor on ruby 1.8 only
jeremy authored
248
7db90aa @jonleighton Make it the responsibility of the connection to hold onto an ARel visito...
jonleighton authored
249 @connections = []
acccb72 @tenderlove column cache now lives on the connection pool
tenderlove authored
250 @automatic_reconnect = true
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
251
252 @available = Queue.new self
253 end
254
255 # Hack for tests to be able to add connections. Do not call outside of tests
256 def insert_connection_for_test!(c) #:nodoc:
257 synchronize do
258 @connections << c
259 @available.add c
260 end
c94651f @tenderlove almost fisted
tenderlove authored
261 end
262
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
263 # Retrieve the connection associated with the current thread, or call
264 # #checkout to obtain one if necessary.
265 #
266 # #connection can be called any number of times; the connection is
267 # held in a hash keyed by the thread id.
268 def connection
c2d416f @pmahoney Synchronize read and modification of @reserved_connections hash to avoid...
pmahoney authored
269 synchronize do
270 @reserved_connections[current_connection_id] ||= checkout
271 end
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
272 end
273
d523504 @tenderlove make active_connection? return true only if there is an open connection ...
tenderlove authored
274 # Is there an open connection that is being used for the current thread?
4211866 @tenderlove adding active_connection? to the connection pool
tenderlove authored
275 def active_connection?
c2d416f @pmahoney Synchronize read and modification of @reserved_connections hash to avoid...
pmahoney authored
276 synchronize do
277 @reserved_connections.fetch(current_connection_id) {
278 return false
279 }.in_use?
280 end
4211866 @tenderlove adding active_connection? to the connection pool
tenderlove authored
281 end
282
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
283 # Signal that the thread is finished with the current connection.
817a07b @nicksieger More doco and class/method renames. Now have a strategy for integration ...
nicksieger authored
284 # #release_connection releases the connection-thread association
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
285 # and returns the connection to the pool.
3344520 @tenderlove reduce the number of times current_connection_id is called in with_conne...
tenderlove authored
286 def release_connection(with_id = current_connection_id)
b8f7482 @tenderlove opening a connection will block if the pool is full
tenderlove authored
287 synchronize do
288 conn = @reserved_connections.delete(with_id)
289 checkin conn if conn
290 end
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
291 end
292
0034b78 @smartinez87 Remove extra white spaces on ActiveRecord docs.
smartinez87 authored
293 # If a connection already exists yield it to the block. If no connection
b451de0 @spastorino Deletes trailing whitespaces (over text files only find * -type f -exec ...
spastorino authored
294 # exists checkout a connection, yield it to the block, and checkin the
5501b99 @coderrr Ensure ActiveRecord::Base.connection_pool.with_connection creates a new ...
coderrr authored
295 # connection when finished.
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
296 def with_connection
3344520 @tenderlove reduce the number of times current_connection_id is called in with_conne...
tenderlove authored
297 connection_id = current_connection_id
ce3d8d6 @tenderlove Start implementing @reserved_connections in terms of connection leases.
tenderlove authored
298 fresh_connection = true unless active_connection?
5501b99 @coderrr Ensure ActiveRecord::Base.connection_pool.with_connection creates a new ...
coderrr authored
299 yield connection
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
300 ensure
3344520 @tenderlove reduce the number of times current_connection_id is called in with_conne...
tenderlove authored
301 release_connection(connection_id) if fresh_connection
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
302 end
303
029952e @nicksieger Extract a base class for connection pools, start to flesh out reserve/re...
nicksieger authored
304 # Returns true if a connection has already been opened.
305 def connected?
c606fe2 @tenderlove push synchronization in to each method. Reduces method calls and makes
tenderlove authored
306 synchronize { @connections.any? }
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
307 end
308
a293278 @lifo Merge docrails
lifo authored
309 # Disconnects all connections in the pool, and clears the pool.
029952e @nicksieger Extract a base class for connection pools, start to flesh out reserve/re...
nicksieger authored
310 def disconnect!
c606fe2 @tenderlove push synchronization in to each method. Reduces method calls and makes
tenderlove authored
311 synchronize do
312 @reserved_connections = {}
313 @connections.each do |conn|
314 checkin conn
315 conn.disconnect!
316 end
317 @connections = []
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
318 @available.clear
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
319 end
320 end
321
8f1b141 @smartinez87 Fixed punctuation errors.
smartinez87 authored
322 # Clears the cache which maps classes.
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
323 def clear_reloadable_connections!
c606fe2 @tenderlove push synchronization in to each method. Reduces method calls and makes
tenderlove authored
324 synchronize do
325 @reserved_connections = {}
326 @connections.each do |conn|
327 checkin conn
328 conn.disconnect! if conn.requires_reloading?
329 end
330 @connections.delete_if do |conn|
331 conn.requires_reloading?
332 end
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
333 @available.clear
334 @connections.each do |conn|
335 @available.add conn
336 end
62c4e4d @ebeigarts Fix connection reloading in development mode. [#4929 state:resolved]
ebeigarts authored
337 end
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
338 end
339
cceabe0 @tenderlove raise a pull full error when the connection pool is full and no connecti...
tenderlove authored
340 def clear_stale_cached_connections! # :nodoc:
27ebb3d @jrochkind deprecated clear_stale_active_connections! can call #reap instead of no-...
jrochkind authored
341 reap
d07a6b1 @nicksieger Make clear_active_connections! also return stale connections back to the...
nicksieger authored
342 end
27ebb3d @jrochkind deprecated clear_stale_active_connections! can call #reap instead of no-...
jrochkind authored
343 deprecate :clear_stale_cached_connections! => "Please use #reap instead"
d07a6b1 @nicksieger Make clear_active_connections! also return stale connections back to the...
nicksieger authored
344
a293278 @lifo Merge docrails
lifo authored
345 # Check-out a database connection from the pool, indicating that you want
346 # to use it. You should call #checkin when you no longer need this.
347 #
cceabe0 @tenderlove raise a pull full error when the connection pool is full and no connecti...
tenderlove authored
348 # This is done by either returning and leasing existing connection, or by
349 # creating a new connection and leasing it.
350 #
351 # If all connections are leased and the pool is at capacity (meaning the
352 # number of currently leased connections is greater than or equal to the
353 # size limit set), an ActiveRecord::PoolFullError exception will be raised.
a293278 @lifo Merge docrails
lifo authored
354 #
355 # Returns: an AbstractAdapter object.
356 #
357 # Raises:
cceabe0 @tenderlove raise a pull full error when the connection pool is full and no connecti...
tenderlove authored
358 # - PoolFullError: no connection can be obtained from the pool.
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
359 def checkout
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
360 synchronize do
361 conn = acquire_connection
362 conn.lease
363 checkout_and_verify(conn)
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
364 end
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
365 end
366
a293278 @lifo Merge docrails
lifo authored
367 # Check-in a database connection back into the pool, indicating that you
368 # no longer need this connection.
369 #
370 # +conn+: an AbstractAdapter object, which was obtained by earlier by
371 # calling +checkout+ on this pool.
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
372 def checkin(conn)
c606fe2 @tenderlove push synchronization in to each method. Reduces method calls and makes
tenderlove authored
373 synchronize do
57bc25c @jfirebaugh Use run_callbacks; the generated _run_<name>_callbacks method is not a p...
jfirebaugh authored
374 conn.run_callbacks :checkin do
b72b477 @tenderlove Use connection lease to determine "checked_out" connections
tenderlove authored
375 conn.expire
471a394 @nicksieger Modify connection pool callbacks to be compatible w/ new style
nicksieger authored
376 end
0210c44 @tenderlove make sure connections returned after close are marked as in_use
tenderlove authored
377
378 release conn
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
379
380 @available.add conn
8e5e02b @nicksieger Collapse connection pool class hierarchy; YAGNI.
nicksieger authored
381 end
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
382 end
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
383
17ff88c @tenderlove connections can be removed from the pool
tenderlove authored
384 # Remove a connection from the connection pool. The connection will
385 # remain open and active but will no longer be managed by this pool.
386 def remove(conn)
387 synchronize do
388 @connections.delete conn
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
389 @available.delete conn
e060cf0 @tenderlove deal with removing connections associated with the current thread
tenderlove authored
390
391 # FIXME: we might want to store the key on the connection so that removing
392 # from the reserved hash will be a little easier.
0210c44 @tenderlove make sure connections returned after close are marked as in_use
tenderlove authored
393 release conn
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
394
395 @available.add checkout_new_connection if @available.any_waiting?
17ff88c @tenderlove connections can be removed from the pool
tenderlove authored
396 end
397 end
398
86729eb @tenderlove connections can be reaped via the `reap` method
tenderlove authored
399 # Removes dead connections from the pool. A dead connection can occur
400 # if a programmer forgets to close a connection at the end of a thread
401 # or a thread dies unexpectedly.
402 def reap
403 synchronize do
cb6f839 @jrochkind ConnectionPool wait_timeout no longer used for different types of timeou...
jrochkind authored
404 stale = Time.now - @dead_connection_timeout
86729eb @tenderlove connections can be reaped via the `reap` method
tenderlove authored
405 connections.dup.each do |conn|
b1ac881 @tenderlove connections are only removed if they are inactve
tenderlove authored
406 remove conn if conn.in_use? && stale > conn.last_use && !conn.active?
86729eb @tenderlove connections can be reaped via the `reap` method
tenderlove authored
407 end
408 end
409 end
410
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
411 private
7db90aa @jonleighton Make it the responsibility of the connection to hold onto an ARel visito...
jonleighton authored
412
02b2335 @pmahoney Make connection pool fair with respect to waiting threads.
pmahoney authored
413 # Acquire a connection by one of 1) immediately removing one
414 # from the queue of available connections, 2) creating a new
415 # connection if the pool is not at capacity, 3) waiting on the
416 # queue for a connection to become available.
417 #
418 # Raises:
419 # - PoolFullError if a connection could not be acquired (FIXME:
420 # why not ConnectionTimeoutError?
421 def acquire_connection
422 if conn = @available.poll
423 conn
424 elsif @connections.size < @size
425 checkout_new_connection
426 else
427 t0 = Time.now
428 begin
429 @available.poll(@checkout_timeout)
430 rescue ConnectionTimeoutError
431 msg = 'could not obtain a database connection within %0.3f seconds (waited %0.3f seconds)' %
432 [@checkout_timeout, Time.now - t0]
433 raise PoolFullError, msg
434 end
435 end
436 end
437
0210c44 @tenderlove make sure connections returned after close are marked as in_use
tenderlove authored
438 def release(conn)
d56f5c8 @mark-rushakoff Remove unused assignments
mark-rushakoff authored
439 thread_id = if @reserved_connections[current_connection_id] == conn
440 current_connection_id
0210c44 @tenderlove make sure connections returned after close are marked as in_use
tenderlove authored
441 else
d56f5c8 @mark-rushakoff Remove unused assignments
mark-rushakoff authored
442 @reserved_connections.keys.find { |k|
0210c44 @tenderlove make sure connections returned after close are marked as in_use
tenderlove authored
443 @reserved_connections[k] == conn
444 }
445 end
446
447 @reserved_connections.delete thread_id if thread_id
448 end
449
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
450 def new_connection
e030f26 @jonleighton Simplify AR configuration code.
jonleighton authored
451 ActiveRecord::Model.send(spec.adapter_method, spec.config)
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
452 end
453
d07a6b1 @nicksieger Make clear_active_connections! also return stale connections back to the...
nicksieger authored
454 def current_connection_id #:nodoc:
e030f26 @jonleighton Simplify AR configuration code.
jonleighton authored
455 ActiveRecord::Model.connection_id ||= Thread.current.object_id
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
456 end
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
457
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
458 def checkout_new_connection
acccb72 @tenderlove column cache now lives on the connection pool
tenderlove authored
459 raise ConnectionNotEstablished unless @automatic_reconnect
460
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
461 c = new_connection
29d2040 @tenderlove AbstractAdapter#close can be called to add the connection back to the
tenderlove authored
462 c.pool = self
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
463 @connections << c
b72b477 @tenderlove Use connection lease to determine "checked_out" connections
tenderlove authored
464 c
a96b7d4 @nicksieger Add connection reset and verification upon each connection checkout
nicksieger authored
465 end
466
467 def checkout_and_verify(c)
471a394 @nicksieger Modify connection pool callbacks to be compatible w/ new style
nicksieger authored
468 c.run_callbacks :checkout do
469 c.verify!
470 end
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
471 c
472 end
473 end
474
a293278 @lifo Merge docrails
lifo authored
475 # ConnectionHandler is a collection of ConnectionPool objects. It is used
f17159b @fxn edit pass: the names of Rails components have a space, ie, "Active Recor...
fxn authored
476 # for keeping separate connection pools for Active Record models that connect
a293278 @lifo Merge docrails
lifo authored
477 # to different databases.
478 #
479 # For example, suppose that you have 5 models, with the following hierarchy:
480 #
481 # |
482 # +-- Book
483 # | |
484 # | +-- ScaryBook
485 # | +-- GoodBook
486 # +-- Author
487 # +-- BankAccount
488 #
489 # Suppose that Book is to connect to a separate database (i.e. one other
490 # than the default database). Then Book, ScaryBook and GoodBook will all use
491 # the same connection pool. Likewise, Author and BankAccount will use the
492 # same connection pool. However, the connection pool used by Author/BankAccount
493 # is not the same as the one used by Book/ScaryBook/GoodBook.
494 #
495 # Normally there is only a single ConnectionHandler instance, accessible via
f17159b @fxn edit pass: the names of Rails components have a space, ie, "Active Recor...
fxn authored
496 # ActiveRecord::Base.connection_handler. Active Record models use this to
a293278 @lifo Merge docrails
lifo authored
497 # determine that connection pool that they should use.
ca6d717 @nicksieger Deprecate allow_concurrency and make it have no effect
nicksieger authored
498 class ConnectionHandler
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
499 def initialize(pools = Hash.new { |h,k| h[k] = {} })
72d959d @nicksieger Split connection handler into single- and multiple-thread versions.
nicksieger authored
500 @connection_pools = pools
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
501 @class_to_pool = Hash.new { |h,k| h[k] = {} }
502 end
503
504 def connection_pools
decafdd @tenderlove use Process.pid rather than $$
tenderlove authored
505 @connection_pools[Process.pid]
72d959d @nicksieger Split connection handler into single- and multiple-thread versions.
nicksieger authored
506 end
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
507
508 def establish_connection(name, spec)
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
509 set_pool_for_spec spec, ConnectionAdapters::ConnectionPool.new(spec)
510 set_class_to_pool name, connection_pools[spec]
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
511 end
512
25f9497 @tenderlove adding active_connections? to the connection pool for finding open conne...
tenderlove authored
513 # Returns true if there are any active connections among the connection
514 # pools that the ConnectionHandler is managing.
515 def active_connections?
516 connection_pools.values.any? { |pool| pool.active_connection? }
517 end
518
d07a6b1 @nicksieger Make clear_active_connections! also return stale connections back to the...
nicksieger authored
519 # Returns any connections in use by the current thread back to the pool,
520 # and also returns connections to the pool cached by threads that are no
521 # longer alive.
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
522 def clear_active_connections!
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
523 connection_pools.each_value {|pool| pool.release_connection }
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
524 end
525
8f1b141 @smartinez87 Fixed punctuation errors.
smartinez87 authored
526 # Clears the cache which maps classes.
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
527 def clear_reloadable_connections!
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
528 connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
529 end
530
531 def clear_all_connections!
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
532 connection_pools.each_value {|pool| pool.disconnect! }
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
533 end
534
535 # Locate the connection of the nearest super class. This can be an
536 # active or defined connection: if it is the latter, it will be
537 # opened and set as the active connection for the class it was defined
538 # for (not necessarily the current class).
539 def retrieve_connection(klass) #:nodoc:
540 pool = retrieve_connection_pool(klass)
541 (pool && pool.connection) or raise ConnectionNotEstablished
542 end
543
82fcd9d @nicksieger Clean up the code, get rid of reserve/release, add some more docs
nicksieger authored
544 # Returns true if a connection that's accessible to this class has
545 # already been opened.
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
546 def connected?(klass)
0832bc6 @lifo Make sure ActiveRecord::Base.connected? doesn't raise an exception for d...
lifo authored
547 conn = retrieve_connection_pool(klass)
a4458f5 @tenderlove removing useless ternary
tenderlove authored
548 conn && conn.connected?
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
549 end
550
551 # Remove the connection for this class. This will close the active
552 # connection and the defined connection (if they exist). The result
553 # can be used as an argument for establish_connection, for easily
554 # re-establishing the connection.
555 def remove_connection(klass)
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
556 pool = class_to_pool.delete(klass.name)
04ef434 @tenderlove only test for existence of +pool+ once
tenderlove authored
557 return nil unless pool
558
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
559 connection_pools.delete pool.spec
acccb72 @tenderlove column cache now lives on the connection pool
tenderlove authored
560 pool.automatic_reconnect = false
04ef434 @tenderlove only test for existence of +pool+ once
tenderlove authored
561 pool.disconnect!
562 pool.spec.config
ff97e9d @nicksieger Connection handling methods extracted out into separate ConnectionHandle...
nicksieger authored
563 end
564
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
565 def retrieve_connection_pool(klass)
e030f26 @jonleighton Simplify AR configuration code.
jonleighton authored
566 if !(klass < Model::Tag)
567 get_pool_for_class('ActiveRecord::Model') # default connection
568 else
569 pool = get_pool_for_class(klass.name)
570 pool || retrieve_connection_pool(klass.superclass)
571 end
fe575dd @nicksieger Nearing the finish line. Initial fixed-size connection pool implemented,...
nicksieger authored
572 end
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
573
574 private
575
576 def class_to_pool
decafdd @tenderlove use Process.pid rather than $$
tenderlove authored
577 @class_to_pool[Process.pid]
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
578 end
579
580 def set_pool_for_spec(spec, pool)
decafdd @tenderlove use Process.pid rather than $$
tenderlove authored
581 @connection_pools[Process.pid][spec] = pool
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
582 end
583
584 def set_class_to_pool(name, pool)
decafdd @tenderlove use Process.pid rather than $$
tenderlove authored
585 @class_to_pool[Process.pid][name] = pool
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
586 pool
587 end
588
589 def get_pool_for_class(klass)
decafdd @tenderlove use Process.pid rather than $$
tenderlove authored
590 @class_to_pool[Process.pid].fetch(klass) {
aaff1a4 @tenderlove database connections are automatically established after forking.
tenderlove authored
591 c_to_p = @class_to_pool.values.find { |class_to_pool|
592 class_to_pool[klass]
593 }
594
595 if c_to_p
596 pool = c_to_p[klass]
597 pool = ConnectionAdapters::ConnectionPool.new pool.spec
598 set_pool_for_spec pool.spec, pool
599 set_class_to_pool klass, pool
600 else
601 set_class_to_pool klass, nil
602 end
603 }
604 end
72d959d @nicksieger Split connection handler into single- and multiple-thread versions.
nicksieger authored
605 end
1b22071 @josh Ensure ActiveRecord session store's connections are checked in after eac...
josh authored
606
607 class ConnectionManagement
608 def initialize(app)
609 @app = app
610 end
611
612 def call(env)
c7b7c6a @tenderlove make sure that active connections are not cleared during test when an ex...
tenderlove authored
613 testing = env.key?('rack.test')
614
2b81240 @lest use Rack::BodyProxy in activerecord middlewares
lest authored
615 response = @app.call(env)
616 response[2] = ::Rack::BodyProxy.new(response[2]) do
617 ActiveRecord::Base.clear_active_connections! unless testing
618 end
e524609 @tenderlove proxy body responses so we close database connections after body is flus...
tenderlove authored
619
2b81240 @lest use Rack::BodyProxy in activerecord middlewares
lest authored
620 response
3b2a032 @tenderlove clearing active connections in the ConnectionManagement middleware if an...
tenderlove authored
621 rescue
c7b7c6a @tenderlove make sure that active connections are not cleared during test when an ex...
tenderlove authored
622 ActiveRecord::Base.clear_active_connections! unless testing
3b2a032 @tenderlove clearing active connections in the ConnectionManagement middleware if an...
tenderlove authored
623 raise
1b22071 @josh Ensure ActiveRecord session store's connections are checked in after eac...
josh authored
624 end
625 end
6edaa26 @nicksieger Initial conversion to connection pool
nicksieger authored
626 end
21eb18a @alk Fix race in ConnectionPool#checkout
alk authored
627 end
Something went wrong with that request. Please try again.