From 41563b49a235ce84419024abcef0825e44e28877 Mon Sep 17 00:00:00 2001 From: Jonathan Rochkind Date: Tue, 13 Mar 2012 18:00:55 -0400 Subject: ConnectionPool.checkout takes account of ruby using 'non-blocking condition variables' in mutex ConditionVariables --- .../abstract/connection_pool.rb | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 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 index f198be0802..3af285c7c8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -226,8 +226,9 @@ connection. For example: ActiveRecord::Base.connection.close # - ConnectionTimeoutError: no connection can be obtained from the pool # within the timeout period. def checkout - # Checkout an available connection synchronize do + waited_time = 0 + loop do conn = @connections.find { |c| c.lease } @@ -243,17 +244,25 @@ connection. For example: ActiveRecord::Base.connection.close return conn end - @queue.wait(@timeout) + if waited_time >= @timeout + raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout} (waited #{waited_time} seconds). The max pool size is currently #{@size}; consider increasing it." + end - if(active_connections.size < @connections.size) - next - else + # Sometimes our wait can end because a connection is available, + # but another thread can snatch it up first. If timeout hasn't + # passed but no connection is avail, looks like that happened -- + # loop and wait again, for the time remaining on our timeout. + before_wait = Time.now + @queue.wait( [@timeout - waited_time, 0].max ) + waited_time += (Time.now - before_wait) + + # Will go away in Rails 4, when we don't clean up + # after leaked connections automatically anymore. Right now, clean + # up after we've returned from a 'wait' if it looks like it's + # needed, then loop and try again. + if(active_connections.size >= @connections.size) clear_stale_cached_connections! - if @size == active_connections.size - raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it." - end end - end end end -- cgit v1.2.3