public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Introduce synchronization around connection pool access

- use new active support Module#synchronize
- allow_concurrency now switches between a null monitor and a
  regular monitor (defaulting to null monitor to avoid overhead)
Nick (author)
Sat Apr 19 10:42:43 -0700 2008
commit  50cd4bdc99ebaf3ac879e4e7fea43c5b55ca5f68
tree    3a52394e0e0843826bf3f07b30a5a22b2593b6bf
parent  b185d157fe5c14ecac348558d0c0b42658de7097
...
 
 
1
2
3
4
5
6
 
7
8
9
10
11
12
13
14
...
44
45
46
47
 
48
49
50
...
60
61
62
63
 
64
65
66
...
70
71
72
73
 
74
75
76
...
119
120
121
 
122
123
124
...
1
2
3
4
5
 
 
 
6
7
8
9
 
 
10
11
12
...
42
43
44
 
45
46
47
48
...
58
59
60
 
61
62
63
64
...
68
69
70
 
71
72
73
74
...
117
118
119
120
121
122
123
0
@@ -1,14 +1,12 @@
0
+require 'set'
0
+
0
 module ActiveRecord
0
   module ConnectionAdapters
0
     class ConnectionPool
0
-      # Check for activity after at least +verification_timeout+ seconds.
0
-      # Defaults to 0 (always check.)
0
-      attr_accessor :verification_timeout
0
+      delegate :verification_timeout, :to => "::ActiveRecord::Base"
0
       attr_reader :active_connections, :spec
0
 
0
       def initialize(spec)
0
-        @verification_timeout = 0
0
-
0
         # The thread id -> adapter cache.
0
         @active_connections = {}
0
 
0
@@ -44,7 +42,7 @@ module ActiveRecord
0
         end
0
       end
0
 
0
-      # Clears the cache which maps classes 
0
+      # Clears the cache which maps classes
0
       def clear_reloadable_connections!
0
         @active_connections.each do |name, conn|
0
           if conn.requires_reloading?
0
@@ -60,7 +58,7 @@ module ActiveRecord
0
           conn.disconnect!
0
         end
0
         active_connections.each_value do |connection|
0
-          connection.verify!(@verification_timeout)
0
+          connection.verify!(verification_timeout)
0
         end
0
       end
0
 
0
@@ -70,7 +68,7 @@ module ActiveRecord
0
         name = active_connection_name
0
         if conn = active_connections[name]
0
           # Verify the connection.
0
-          conn.verify!(@verification_timeout)
0
+          conn.verify!(verification_timeout)
0
         else
0
           self.connection = spec
0
           conn = active_connections[name]
0
@@ -119,6 +117,7 @@ module ActiveRecord
0
 
0
         def clear_entries!(cache, keys, &block)
0
           keys.each do |key|
0
+            next unless cache.has_key?(key)
0
             block.call(key, cache[key])
0
             cache.delete(key)
0
           end
...
1
 
2
3
4
...
9
10
11
 
 
 
 
 
 
 
 
 
12
13
14
...
18
19
20
 
 
 
 
 
 
 
 
 
 
21
22
 
23
24
25
...
36
37
38
39
40
41
 
42
43
44
 
45
46
47
48
 
49
50
51
52
53
54
 
55
56
57
...
59
60
61
 
 
 
62
63
64
...
107
108
109
110
 
 
 
111
112
113
...
171
172
173
 
 
 
 
 
174
175
...
 
1
2
3
4
...
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
41
42
43
44
...
55
56
57
 
 
 
58
59
60
 
61
62
 
 
 
63
64
65
66
 
 
 
67
68
69
70
...
72
73
74
75
76
77
78
79
80
...
123
124
125
 
126
127
128
129
130
131
...
189
190
191
192
193
194
195
196
197
198
0
@@ -1,4 +1,4 @@
0
-require 'set'
0
+require 'monitor'
0
 
0
 module ActiveRecord
0
   class Base
0
@@ -9,6 +9,15 @@ module ActiveRecord
0
       end
0
     end
0
 
0
+    class NullMonitor
0
+      def synchronize
0
+        yield
0
+      end
0
+    end
0
+
0
+    cattr_accessor :connection_pools_lock, :instance_writer => false
0
+    @@connection_pools_lock = NullMonitor.new
0
+
0
     # Check for activity after at least +verification_timeout+ seconds.
0
     # Defaults to 0 (always check.)
0
     cattr_accessor :verification_timeout, :instance_writer => false
0
@@ -18,8 +27,18 @@ module ActiveRecord
0
     @@connection_pools = {}
0
 
0
     class << self
0
+      def allow_concurrency=(flag)
0
+        if @@allow_concurrency != flag
0
+          if flag
0
+            self.connection_pools_lock = Monitor.new
0
+          else
0
+            self.connection_pools_lock = NullMonitor.new
0
+          end
0
+        end
0
+      end
0
+
0
       # for internal use only
0
-      def active_connections
0
+      def active_connections #:nodoc:
0
         @@connection_pools.inject({}) do |hash,kv|
0
           hash[kv.first] = kv.last.active_connection
0
           hash.delete(kv.first) unless hash[kv.first]
0
@@ -36,22 +55,16 @@ module ActiveRecord
0
 
0
       # Clears the cache which maps classes to connections.
0
       def clear_active_connections!
0
-        clear_cache!(@@connection_pools) do |name, pool|
0
-          pool.clear_active_connections!
0
-        end
0
+        @@connection_pools.each_value {|pool| pool.clear_active_connections! }
0
       end
0
       
0
-      # Clears the cache which maps classes 
0
+      # Clears the cache which maps classes
0
       def clear_reloadable_connections!
0
-        clear_cache!(@@connection_pools) do |name, pool|
0
-          pool.clear_reloadable_connections!
0
-        end
0
+        @@connection_pools.each_value {|pool| pool.clear_reloadable_connections! }
0
       end
0
 
0
       def clear_all_connections!
0
-        clear_cache!(@@connection_pools) do |name, pool|
0
-          pool.disconnect!
0
-        end
0
+        clear_cache!(@@connection_pools) {|name, pool| pool.disconnect! }
0
       end
0
 
0
       # Verify active connections.
0
@@ -59,6 +72,9 @@ module ActiveRecord
0
         @@connection_pools.each_value {|pool| pool.verify_active_connections!}
0
       end
0
 
0
+      synchronize :active_connections, :clear_active_connections!, :clear_reloadable_connections!,
0
+        :clear_all_connections!, :verify_active_connections!, :with => :connection_pools_lock
0
+
0
       private
0
         def clear_cache!(cache, &block)
0
           cache.each(&block) if block_given?
0
@@ -107,7 +123,9 @@ module ActiveRecord
0
           raise AdapterNotSpecified unless defined? RAILS_ENV
0
           establish_connection(RAILS_ENV)
0
         when ConnectionSpecification
0
-          @@connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
0
+          connection_pools_lock.synchronize do
0
+            @@connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)
0
+          end
0
         when Symbol, String
0
           if configuration = configurations[spec.to_s]
0
             establish_connection(configuration)
0
@@ -171,5 +189,10 @@ module ActiveRecord
0
       pool.disconnect! if pool
0
       pool.spec.config if pool
0
     end
0
+
0
+    class << self
0
+      synchronize :retrieve_connection, :retrieve_connection_pool, :connected?,
0
+        :remove_connection, :with => :connection_pools_lock
0
+    end
0
   end
0
 end
...
11
12
13
 
 
14
15
16
17
18
 
 
19
20
21
...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
0
@@ -11,11 +11,15 @@ unless %w(FrontBase).include? ActiveRecord::Base.connection.adapter_name
0
     def setup
0
       @connection = ActiveRecord::Base.remove_connection
0
       @connections = []
0
+      @allow_concurrency = ActiveRecord::Base.allow_concurrency
0
+      ActiveRecord::Base.allow_concurrency = true
0
     end
0
 
0
     def teardown
0
       # clear the connection cache
0
       ActiveRecord::Base.clear_active_connections!
0
+      # set allow_concurrency to saved value
0
+      ActiveRecord::Base.allow_concurrency = @allow_concurrency
0
       # reestablish old connection
0
       ActiveRecord::Base.establish_connection(@connection)
0
     end

Comments