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:
Jeremy Kemper
2006-03-13 17:28:55 +00:00
parent 8ff4463193
commit 25fb2db409
5 changed files with 79 additions and 32 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)