aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Rochkind <jonathan@dnil.net>2012-03-13 18:00:55 -0400
committerJonathan Rochkind <jonathan@dnil.net>2012-03-13 18:00:55 -0400
commit41563b49a235ce84419024abcef0825e44e28877 (patch)
tree3ca7543afd0958dda8b1f958b7533c7c3dd72e33
parent596ecf753eb87ee4f11fc87682b321c64b09d733 (diff)
downloadrails-41563b49a235ce84419024abcef0825e44e28877.tar.gz
rails-41563b49a235ce84419024abcef0825e44e28877.tar.bz2
rails-41563b49a235ce84419024abcef0825e44e28877.zip
ConnectionPool.checkout takes account of ruby using 'non-blocking condition variables' in mutex ConditionVariables
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb27
1 files 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