提交 f63df2bd 编写于 作者: R Rafael França 提交者: Rafael Mendonça França

Merge pull request #36949 from 97jaz/thread-local-prepared-statements

Make prepared statement status thread and instance-specific
上级 97f9609d
......@@ -11,6 +11,7 @@
require "arel/collectors/composite"
require "arel/collectors/sql_string"
require "arel/collectors/substitute_binds"
require "concurrent/atomic/thread_local_var"
module ActiveRecord
module ConnectionAdapters # :nodoc:
......@@ -78,7 +79,7 @@ class AbstractAdapter
SIMPLE_INT = /\A\d+\z/
attr_accessor :pool
attr_reader :visitor, :owner, :logger, :lock, :prepared_statements
attr_reader :visitor, :owner, :logger, :lock
alias :in_use? :owner
set_callback :checkin, :after, :enable_lazy_transactions!
......@@ -129,10 +130,10 @@ def initialize(connection, logger = nil, config = {}) # :nodoc:
@lock = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
@prepared_statements = true
@prepared_statement_status = Concurrent::ThreadLocalVar.new(true)
@visitor.extend(DetermineIfPreparableVisitor)
else
@prepared_statements = false
@prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
end
@advisory_locks_enabled = self.class.type_cast_config_to_boolean(
......@@ -175,6 +176,10 @@ def schema_migration # :nodoc:
end
end
def prepared_statements
@prepared_statement_status.value
end
class Version
include Comparable
......@@ -259,10 +264,7 @@ def seconds_idle # :nodoc:
end
def unprepared_statement
old_prepared_statements, @prepared_statements = @prepared_statements, false
yield
ensure
@prepared_statements = old_prepared_statements
@prepared_statement_status.bind(false) { yield }
end
# Returns the human-readable name of the adapter. Use mixed case - one
......
......@@ -39,8 +39,8 @@ class Mysql2Adapter < AbstractMysqlAdapter
include MySQL::DatabaseStatements
def initialize(connection, logger, connection_options, config)
super
@prepared_statements = false unless config.key?(:prepared_statements)
superclass_config = config.reverse_merge(prepared_statements: false)
super(connection, logger, connection_options, superclass_config)
configure_connection
end
......
# frozen_string_literal: true
require "cases/helper"
require "models/course"
require "models/entrant"
module ActiveRecord
class PreparedStatementStatusTest < ActiveRecord::TestCase
def test_prepared_statement_status_is_thread_and_instance_specific
course_conn = Course.connection
entrant_conn = Entrant.connection
inside = Concurrent::Event.new
preventing = Concurrent::Event.new
finished = Concurrent::Event.new
assert_not_same course_conn, entrant_conn
if current_adapter?(:Mysql2Adapter)
# The mysql adapter does not use prepared
# statements by default.
assert_not course_conn.prepared_statements
assert_not entrant_conn.prepared_statements
else
t1 = Thread.new do
course_conn.unprepared_statement do
inside.set
preventing.wait
assert_not course_conn.prepared_statements
assert entrant_conn.prepared_statements
finished.set
end
end
t2 = Thread.new do
entrant_conn.unprepared_statement do
inside.wait
assert course_conn.prepared_statements
assert_not entrant_conn.prepared_statements
preventing.set
finished.wait
end
end
t1.join
t2.join
end
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册