aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/lib/active_record.rb1
-rw-r--r--activerecord/lib/active_record/connection_handling.rb4
-rw-r--r--activerecord/lib/active_record/core.rb4
-rw-r--r--activerecord/lib/active_record/log_subscriber.rb4
-rw-r--r--activerecord/lib/active_record/runtime_registry.rb32
-rw-r--r--activerecord/lib/active_record/scoping.rb12
-rw-r--r--activerecord/test/cases/base_test.rb4
-rw-r--r--activesupport/lib/active_support/notifications.rb9
-rw-r--r--activesupport/lib/active_support/per_thread_registry.rb41
9 files changed, 92 insertions, 19 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 3bfc6772b2..249eabfd7d 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -50,6 +50,7 @@ module ActiveRecord
autoload :Querying
autoload :ReadonlyAttributes
autoload :Reflection
+ autoload :RuntimeRegistry
autoload :Sanitization
autoload :Schema
autoload :SchemaDumper
diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb
index 1e03414c29..3f175988db 100644
--- a/activerecord/lib/active_record/connection_handling.rb
+++ b/activerecord/lib/active_record/connection_handling.rb
@@ -54,11 +54,11 @@ module ActiveRecord
end
def connection_id
- Thread.current['ActiveRecord::Base.connection_id']
+ ActiveRecord::RuntimeRegistry.instance.connection_id
end
def connection_id=(connection_id)
- Thread.current['ActiveRecord::Base.connection_id'] = connection_id
+ ActiveRecord::RuntimeRegistry.instance.connection_id = connection_id
end
# Returns the configuration of the associated connection as a hash:
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index afa1766615..7a8408155a 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -80,11 +80,11 @@ module ActiveRecord
class_attribute :default_connection_handler, instance_writer: false
def self.connection_handler
- Thread.current[:active_record_connection_handler] || self.default_connection_handler
+ ActiveRecord::RuntimeRegistry.instance.connection_handler || self.default_connection_handler
end
def self.connection_handler=(handler)
- Thread.current[:active_record_connection_handler] = handler
+ ActiveRecord::RuntimeRegistry.instance.connection_handler = handler
end
self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb
index c1ba524c84..69371a1dab 100644
--- a/activerecord/lib/active_record/log_subscriber.rb
+++ b/activerecord/lib/active_record/log_subscriber.rb
@@ -3,11 +3,11 @@ module ActiveRecord
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
def self.runtime=(value)
- Thread.current[:active_record_sql_runtime] = value
+ ActiveRecord::RuntimeRegistry.instance.sql_runtime = value
end
def self.runtime
- Thread.current[:active_record_sql_runtime] ||= 0
+ ActiveRecord::RuntimeRegistry.instance.sql_runtime ||= 0
end
def self.reset_runtime
diff --git a/activerecord/lib/active_record/runtime_registry.rb b/activerecord/lib/active_record/runtime_registry.rb
new file mode 100644
index 0000000000..3f0ac68143
--- /dev/null
+++ b/activerecord/lib/active_record/runtime_registry.rb
@@ -0,0 +1,32 @@
+require 'active_support/per_thread_registry'
+
+module ActiveRecord
+ # This is a registry class for storing local variables in active record. The
+ # class allows you to access variables that are local to the current thread.
+ # These thread local variables are stored as attributes in the
+ # +RuntimeRegistry+ class.
+ #
+ # You can access the thread local variables by calling a variable's name on
+ # the +RuntimeRegistry+ class. For example, if you wanted to obtain the
+ # connection handler for the current thread, you would invoke:
+ #
+ # ActiveRecord::RuntimeRegistry.instance.connection_handler
+ #
+ # The +PerThreadRegistry+ module will make a new +RuntimeRegistry+ instance
+ # and store it in +Thread.current+. Whenever you make a call for an attribute
+ # on the +RuntimeRegistry+ class, the call will be sent to the instance that
+ # is stored in +Thread.current+.
+ #
+ # Note that you can also make the following call which would provide an
+ # equivalent result as the previous code:
+ #
+ # ActiveRecord::RuntimeRegistry.connection_handler
+ #
+ # However, this is less performant because it makes a call to +method_missing+
+ # before it sends the method call to the +instance+.
+ class RuntimeRegistry
+ extend ActiveSupport::PerThreadRegistry
+
+ attr_accessor :connection_handler, :sql_runtime, :connection_id
+ end
+end
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index f108ab0fe0..6ab36a23a7 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -1,3 +1,5 @@
+require 'active_support/per_thread_registry'
+
module ActiveRecord
module Scoping
extend ActiveSupport::Concern
@@ -34,7 +36,7 @@ module ActiveRecord
# to get the current_scope for the +Board+ model, then you would use the
# following code:
#
- # registry = ActiveRecord::Scoping::ScopeRegistry.current
+ # registry = ActiveRecord::Scoping::ScopeRegistry.instance
# registry.set_value_for(:current_scope, "Board", some_new_scope)
#
# Now when you run:
@@ -48,12 +50,10 @@ module ActiveRecord
# ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
# "Board", some_new_scope)
class ScopeRegistry # :nodoc:
- class << self
- delegate :value_for, :set_value_for, to: :current
+ extend ActiveSupport::PerThreadRegistry
- def current
- Thread.current["scope_registry"] ||= new
- end
+ class << self
+ delegate :value_for, :set_value_for, to: :instance
end
VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index e57dbd5a09..83fc0b48f9 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1377,9 +1377,9 @@ class BasicsTest < ActiveRecord::TestCase
UnloadablePost.send(:current_scope=, UnloadablePost.all)
UnloadablePost.unloadable
- assert_not_nil ActiveRecord::Scoping::ScopeRegistry.current.value_for(:current_scope, "UnloadablePost")
+ assert_not_nil ActiveRecord::Scoping::ScopeRegistry.instance.value_for(:current_scope, "UnloadablePost")
ActiveSupport::Dependencies.remove_unloadable_constants!
- assert_nil ActiveRecord::Scoping::ScopeRegistry.current.value_for(:current_scope, "UnloadablePost")
+ assert_nil ActiveRecord::Scoping::ScopeRegistry.instance.value_for(:current_scope, "UnloadablePost")
ensure
Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
end
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index ab2bb5fafe..5c985601f4 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -1,5 +1,6 @@
require 'active_support/notifications/instrumenter'
require 'active_support/notifications/fanout'
+require 'active_support/per_thread_registry'
module ActiveSupport
# = Notifications
@@ -190,12 +191,10 @@ module ActiveSupport
# The instrumenters for multiple notifiers are held in a single instance of
# this class.
class InstrumentationRegistry # :nodoc:
- class << self
- delegate :instrumenter_for, to: :current
+ extend ActiveSupport::PerThreadRegistry
- def current
- Thread.current[:instrumentation_registry] ||= new
- end
+ class << self
+ delegate :instrumenter_for, to: :instance
end
def initialize
diff --git a/activesupport/lib/active_support/per_thread_registry.rb b/activesupport/lib/active_support/per_thread_registry.rb
new file mode 100644
index 0000000000..b89ce2cbeb
--- /dev/null
+++ b/activesupport/lib/active_support/per_thread_registry.rb
@@ -0,0 +1,41 @@
+module ActiveSupport
+ # This module creates a local registry class inside each thread. It provides
+ # basic methods which will store thread locals in a single class. This
+ # prevents the proliferation of too many thread locals and allows you to
+ # explicitly keep track of each of the variables you're using as thread
+ # locals in a class which includes this module.
+ #
+ # For example, instead of using a bunch of different thread locals to keep
+ # track of some variables like so:
+ #
+ # Thread.current[:active_record_connection_handler] = connection_handler
+ # Thread.current[:active_record_sql_runtime] = sql_runtime
+ #
+ # You could use the following class which implements the +PerThreadRegistry+
+ # module:
+ #
+ # class NewRegistry
+ # extend ActiveSupport::PerThreadRegistry
+ #
+ # attr_accessor :connection_handler, :sql_runtime
+ # end
+ #
+ # NewRegistry.instance.connection_handler = connection_handler
+ # NewRegistry.instance.sql_runtime = sql_runtime
+ #
+ # The new way of keeping track of the thread locals will create a new local
+ # inside of +Thread.current+ with a key which is the name of the extended
+ # class. Now you can easily access per thread variables by just calling the
+ # variable name on the registry.
+ module PerThreadRegistry
+ def instance
+ Thread.current[self.name] ||= new
+ end
+
+ protected
+
+ def method_missing(*args, &block)
+ instance.send(*args, &block)
+ end
+ end
+end