Skip to content

Commit 1a2ca19

Browse files
committed
AbstractAdapter: only synchronize when necessary
Ref: rails#28083 Right now all database operations are synchronized with a monitor even though it's useless in the vast majority of cases. The synchronization is only useful when transactional fixtures are enabled. In production, connections are never shared across threads, as such this extra synchronization is wasteful.
1 parent 625e292 commit 1a2ca19

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ def lock_thread=(lock_thread)
173173
else
174174
@lock_thread = nil
175175
end
176+
177+
if (active_connection = @thread_cached_conns[connection_cache_key(current_thread)])
178+
active_connection.synchronized = lock_thread
179+
end
176180
end
177181

178182
# Retrieve the connection associated with the current thread, or call
@@ -352,7 +356,9 @@ def clear_reloadable_connections!
352356
# Raises:
353357
# - ActiveRecord::ConnectionTimeoutError no connection can be obtained from the pool.
354358
def checkout(checkout_timeout = @checkout_timeout)
355-
checkout_and_verify(acquire_connection(checkout_timeout))
359+
connection = checkout_and_verify(acquire_connection(checkout_timeout))
360+
connection.synchronized = @lock_thread
361+
connection
356362
end
357363

358364
# Check-in a database connection back into the pool, indicating that you

activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require "active_record/connection_adapters/sql_type_metadata"
55
require "active_record/connection_adapters/abstract/schema_dumper"
66
require "active_record/connection_adapters/abstract/schema_creation"
7+
require "active_support/concurrency/null_lock"
78
require "active_support/concurrency/load_interlock_aware_monitor"
89
require "arel/collectors/bind"
910
require "arel/collectors/composite"
@@ -155,7 +156,7 @@ def initialize(config_or_deprecated_connection, deprecated_logger = nil, depreca
155156
@idle_since = Process.clock_gettime(Process::CLOCK_MONOTONIC)
156157
@visitor = arel_visitor
157158
@statements = build_statement_pool
158-
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
159+
self.synchronized = false
159160

160161
@prepared_statements = self.class.type_cast_config_to_boolean(
161162
@config.fetch(:prepared_statements) { default_prepared_statements }
@@ -171,6 +172,14 @@ def initialize(config_or_deprecated_connection, deprecated_logger = nil, depreca
171172
@verified = false
172173
end
173174

175+
def synchronized=(synchronized) # :nodoc:
176+
@lock = if synchronized
177+
ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
178+
else
179+
ActiveSupport::Concurrency::NullLock
180+
end
181+
end
182+
174183
EXCEPTION_NEVER = { Exception => :never }.freeze # :nodoc:
175184
EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze # :nodoc:
176185
private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveSupport
4+
module Concurrency
5+
module NullLock # :nodoc:
6+
extend self
7+
8+
def synchronize
9+
yield
10+
end
11+
end
12+
end
13+
end

0 commit comments

Comments
 (0)