aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG2
-rwxr-xr-xactiverecord/lib/active_record/base.rb25
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb66
-rw-r--r--activerecord/test/method_scoping_test.rb6
-rw-r--r--activerecord/test/threaded_connections_test.rb10
5 files changed, 78 insertions, 31 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 5cde7f465b..aee47c652e 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -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
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 70d88e561b..9e3c54c7d4 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -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
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
index fe581a14b5..8b70b2f047 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
@@ -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
+ def thread_safe_active_connections #:nodoc:
+ @@active_connections[Thread.current.object_id] ||= {}
+ end
+
+ 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
-
- @active_connection_name = nil
+
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
diff --git a/activerecord/test/method_scoping_test.rb b/activerecord/test/method_scoping_test.rb
index 551d7c1dd3..c01aab6a36 100644
--- a/activerecord/test/method_scoping_test.rb
+++ b/activerecord/test/method_scoping_test.rb
@@ -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
diff --git a/activerecord/test/threaded_connections_test.rb b/activerecord/test/threaded_connections_test.rb
index 177c6c7e13..d9cc47eef3 100644
--- a/activerecord/test/threaded_connections_test.rb
+++ b/activerecord/test/threaded_connections_test.rb
@@ -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)