mirror of
https://github.com/github/rails.git
synced 2026-01-28 15:58:03 -05:00
Dynamically set allow_concurrency. Closes #4044.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3862 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
*SVN*
|
||||
|
||||
* Dynamically set allow_concurrency. #4044 [Stefan Kaes]
|
||||
|
||||
* Added Base#to_xml that'll turn the current record into a XML representation [DHH]. Example:
|
||||
|
||||
topic.to_xml
|
||||
|
||||
@@ -310,7 +310,7 @@ module ActiveRecord #:nodoc:
|
||||
# Determines whether or not to use a connection for each thread, or a single shared connection for all threads.
|
||||
# Defaults to false. Set to true if you're writing a threaded application.
|
||||
cattr_accessor :allow_concurrency
|
||||
@@allow_concurrency = true
|
||||
@@allow_concurrency = false
|
||||
|
||||
# Determines whether to speed up access by generating optimized reader
|
||||
# methods to avoid expensive calls to method_missing when accessing
|
||||
@@ -1140,15 +1140,22 @@ module ActiveRecord #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def scoped_methods
|
||||
if allow_concurrency
|
||||
Thread.current[:scoped_methods] ||= {}
|
||||
Thread.current[:scoped_methods][self] ||= []
|
||||
else
|
||||
@scoped_methods ||= []
|
||||
end
|
||||
def thread_safe_scoped_methods #:nodoc:
|
||||
scoped_methods = (Thread.current[:scoped_methods] ||= {})
|
||||
scoped_methods[self] ||= []
|
||||
end
|
||||
|
||||
|
||||
def single_threaded_scoped_methods #:nodoc:
|
||||
@scoped_methods ||= []
|
||||
end
|
||||
|
||||
# pick up the correct scoped_methods version from @@allow_concurrency
|
||||
if @@allow_concurrency
|
||||
alias_method :scoped_methods, :thread_safe_scoped_methods
|
||||
else
|
||||
alias_method :scoped_methods, :single_threaded_scoped_methods
|
||||
end
|
||||
|
||||
def current_scoped_methods
|
||||
scoped_methods.last
|
||||
end
|
||||
|
||||
@@ -22,15 +22,35 @@ module ActiveRecord
|
||||
|
||||
class << self
|
||||
# Retrieve the connection cache.
|
||||
def active_connections
|
||||
if @@allow_concurrency
|
||||
@@active_connections[Thread.current.object_id] ||= {}
|
||||
else
|
||||
@@active_connections
|
||||
end
|
||||
def thread_safe_active_connections #:nodoc:
|
||||
@@active_connections[Thread.current.object_id] ||= {}
|
||||
end
|
||||
|
||||
@active_connection_name = nil
|
||||
|
||||
def single_threaded_active_connections #:nodoc:
|
||||
@@active_connections
|
||||
end
|
||||
|
||||
# pick up the right active_connection method from @@allow_concurrency
|
||||
if @@allow_concurrency
|
||||
alias_method :active_connections, :thread_safe_active_connections
|
||||
else
|
||||
alias_method :active_connections, :single_threaded_active_connections
|
||||
end
|
||||
|
||||
# set concurrency support flag (not thread safe, like most of the methods in this file)
|
||||
def allow_concurrency=(threaded)
|
||||
logger.debug "allow_concurrency=#{threaded}" if logger
|
||||
return if @@allow_concurrency == threaded
|
||||
clear_all_cached_connections!
|
||||
@@allow_concurrency = threaded
|
||||
method_prefix = threaded ? "thread_safe" : "single_threaded"
|
||||
sing = (class << self; self; end)
|
||||
[:active_connections, :scoped_methods].each do |method|
|
||||
sing.send(:alias_method, method, "#{method_prefix}_#{method}")
|
||||
end
|
||||
log_connections if logger
|
||||
end
|
||||
|
||||
def active_connection_name
|
||||
@active_connection_name ||=
|
||||
if active_connections[name] || @@defined_connections[name]
|
||||
@@ -62,15 +82,19 @@ module ActiveRecord
|
||||
|
||||
# Clears the cache which maps classes to connections.
|
||||
def clear_active_connections!
|
||||
clear_cache!(@@active_connections)
|
||||
clear_cache!(@@active_connections) do |name, conn|
|
||||
conn.disconnect!
|
||||
end
|
||||
end
|
||||
|
||||
# Verify active connections.
|
||||
def verify_active_connections!
|
||||
remove_stale_cached_threads!(@@active_connections) do |name, conn|
|
||||
conn.disconnect!
|
||||
if @@allow_concurrency
|
||||
remove_stale_cached_threads!(@@active_connections) do |name, conn|
|
||||
conn.disconnect!
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
active_connections.each_value do |connection|
|
||||
connection.verify!(@@verification_timeout)
|
||||
end
|
||||
@@ -106,6 +130,18 @@ module ActiveRecord
|
||||
clear_cache!(cache, thread_id, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def clear_all_cached_connections!
|
||||
if @@allow_concurrency
|
||||
@@active_connections.each_value do |connection_hash_for_thread|
|
||||
connection_hash_for_thread.each_value {|conn| conn.disconnect! }
|
||||
connection_hash_for_thread.clear
|
||||
end
|
||||
else
|
||||
@@active_connections.each_value {|conn| conn.disconnect! }
|
||||
end
|
||||
@@active_connections.clear
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the connection currently associated with the class. This can
|
||||
@@ -167,14 +203,6 @@ module ActiveRecord
|
||||
end
|
||||
end
|
||||
|
||||
def self.active_connections #:nodoc:
|
||||
if @@allow_concurrency
|
||||
Thread.current['active_connections'] ||= {}
|
||||
else
|
||||
@@active_connections ||= {}
|
||||
end
|
||||
end
|
||||
|
||||
# Locate the connection of the nearest super class. This can be an
|
||||
# active or defined connections: if it is the latter, it will be
|
||||
# opened and set as the active connection for the class it was defined
|
||||
|
||||
@@ -9,7 +9,7 @@ class MethodScopingTest < Test::Unit::TestCase
|
||||
|
||||
def test_set_conditions
|
||||
Developer.with_scope(:find => { :conditions => 'just a test...' }) do
|
||||
assert_equal 'just a test...', Thread.current[:scoped_methods][Developer][-1][:find][:conditions]
|
||||
assert_equal 'just a test...', Developer.send(:current_scoped_methods)[:find][:conditions]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -64,7 +64,7 @@ class MethodScopingTest < Test::Unit::TestCase
|
||||
new_comment = nil
|
||||
|
||||
VerySpecialComment.with_scope(:create => { :post_id => 1 }) do
|
||||
assert_equal({ :post_id => 1 }, Thread.current[:scoped_methods][VerySpecialComment][-1][:create])
|
||||
assert_equal({ :post_id => 1 }, VerySpecialComment.send(:current_scoped_methods)[:create])
|
||||
new_comment = VerySpecialComment.create :body => "Wonderful world"
|
||||
end
|
||||
|
||||
@@ -123,7 +123,7 @@ class NestedScopingTest < Test::Unit::TestCase
|
||||
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
||||
Developer.with_exclusive_scope(:find => { :conditions => "name = 'Jamis'" }) do
|
||||
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.instance_eval('current_scoped_methods'))
|
||||
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Thread.current[:scoped_methods][Developer][-1])
|
||||
assert_equal({:find => { :conditions => "name = 'Jamis'" }}, Developer.send(:scoped_methods)[-1])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,6 +9,16 @@ class ThreadedConnectionsTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.remove_connection
|
||||
@connections = []
|
||||
@allow_concurrency = ActiveRecord::Base.allow_concurrency
|
||||
end
|
||||
|
||||
def teardown
|
||||
# clear the connection cache
|
||||
ActiveRecord::Base.send(:clear_all_cached_connections!)
|
||||
# set allow_concurrency to saved value
|
||||
ActiveRecord::Base.allow_concurrency = @allow_concurrency
|
||||
# reestablish old connection
|
||||
ActiveRecord::Base.establish_connection(@connection)
|
||||
end
|
||||
|
||||
def gather_connections(use_threaded_connections)
|
||||
|
||||
Reference in New Issue
Block a user