aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
diff options
context:
space:
mode:
authorthedarkone <thedarkone2@gmail.com>2015-04-04 22:33:32 +0200
committerthedarkone <thedarkone2@gmail.com>2015-05-14 02:25:57 +0200
commita3923e667ca2c78734665389be964aa8492cfe1c (patch)
tree2208fc621f40a2829ae0d73eb482afd0c4e26ef6 /activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
parent2c7c11d545dff93d91af4555d3babea813ccd3b3 (diff)
downloadrails-a3923e667ca2c78734665389be964aa8492cfe1c.tar.gz
rails-a3923e667ca2c78734665389be964aa8492cfe1c.tar.bz2
rails-a3923e667ca2c78734665389be964aa8492cfe1c.zip
AR::ConPool - reduce post checkout critical section.
Move post checkout connection verification out of mutex.synchronize.
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb31
1 files changed, 23 insertions, 8 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 77e64a22be..aeaaa48945 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -258,9 +258,7 @@ module ActiveRecord
def connection
# this is correctly done double-checked locking
# (ThreadSafe::Cache's lookups have volatile semantics)
- @reserved_connections[current_connection_id] || synchronize do
- @reserved_connections[current_connection_id] ||= checkout
- end
+ @reserved_connections[current_connection_id] || synchronized_connection_retrieval
end
# Is there an open connection that is being used for the current thread?
@@ -342,11 +340,8 @@ module ActiveRecord
# Raises:
# - ConnectionTimeoutError: no connection can be obtained from the pool.
def checkout
- synchronize do
- conn = acquire_connection
- conn.lease
- checkout_and_verify(conn)
- end
+ conn = synchronize { acquire_connection.tap(&:lease) }
+ checkout_and_verify(conn)
end
# Check-in a database connection back into the pool, indicating that you
@@ -377,6 +372,15 @@ module ActiveRecord
release conn, conn.owner
+ # @available.any_waiting? => true means that prior to removing this
+ # conn, the pool was at its max size (@connections.size == @size)
+ # this would mean that any threads stuck waiting in the queue wouldn't
+ # know they could checkout_new_connection, so let's do it for them.
+ # Because condition-wait loop is encapsulated in the Queue class
+ # (that in turn is oblivious to ConnectionPool implementation), threads
+ # that are "stuck" there are helpless, they have no way of creating
+ # new connections and are completely reliant on us feeding available
+ # connections into the Queue.
@available.add checkout_new_connection if @available.any_waiting?
end
end
@@ -404,6 +408,17 @@ module ActiveRecord
end
private
+ def synchronized_connection_retrieval
+ conn = synchronize do
+ # re-checking under lock for correct DCL semantics
+ @reserved_connections[current_connection_id] ||= acquire_connection.tap(&:lease)
+ end
+ begin
+ checkout_and_verify(conn)
+ rescue Exception # clean up if something goes wrong in post_checkout
+ synchronize { @reserved_connections.delete_pair(current_connection_id, conn) }
+ end
+ end
# Acquire a connection by one of 1) immediately removing one
# from the queue of available connections, 2) creating a new