seamless_database_pool 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Brian Durand
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -7,11 +7,10 @@ desc 'Default: run unit tests.'
7
7
  task :default => :test
8
8
 
9
9
  begin
10
- require 'spec/rake/spectask'
11
- desc 'Test seamless_database_pool.'
12
- Spec::Rake::SpecTask.new(:test) do |t|
13
- t.spec_files = FileList.new('spec/**/*_spec.rb')
14
- end
10
+ require 'rspec'
11
+ require 'rspec/core/rake_task'
12
+ desc 'Run the unit tests'
13
+ RSpec::Core::RakeTask.new(:test)
15
14
 
16
15
  namespace :test do
17
16
  desc "Run all tests including for all database adapters"
@@ -38,8 +37,8 @@ begin
38
37
 
39
38
  namespace :adapters do
40
39
  desc "Internal task to run database adapter tests"
41
- Spec::Rake::SpecTask.new(:specified) do |t|
42
- t.spec_files = FileList.new('spec/connection_adapters_spec.rb')
40
+ RSpec::Core::RakeTask.new(:specified) do |t|
41
+ t.pattern = FileList.new('spec/connection_adapters_spec.rb')
43
42
  end
44
43
 
45
44
  YAML.load_file(File.expand_path("../spec/database.yml", __FILE__)).keys.each do |adapter_name|
@@ -58,7 +57,7 @@ begin
58
57
  end
59
58
  rescue LoadError
60
59
  task :test do
61
- STDERR.puts "You must have rspec >= 1.3.0 to run the tests"
60
+ STDERR.puts "You must have rspec >= 2.0 to run the tests"
62
61
  end
63
62
  end
64
63
 
@@ -80,10 +79,10 @@ begin
80
79
  gem.authors = ["Brian Durand"]
81
80
  gem.files = FileList["lib/**/*", "spec/**/*", "README.rdoc", "Rakefile"].to_a
82
81
  gem.has_rdoc = true
83
- gem.extra_rdoc_files = ["README.rdoc"]
82
+ gem.extra_rdoc_files = ["README.rdoc", "MIT-LICENSE"]
84
83
 
85
84
  gem.add_dependency('activerecord', '>= 2.2.2')
86
- gem.add_development_dependency('rspec', '>= 1.2.9')
85
+ gem.add_development_dependency('rspec', '>= 2.0')
87
86
  gem.add_development_dependency('jeweler')
88
87
  end
89
88
 
@@ -1,46 +1,53 @@
1
1
  module ActiveRecord
2
2
  class Base
3
3
  class << self
4
- def seamless_database_pool_connection (config)
4
+ def seamless_database_pool_connection(config)
5
5
  pool_weights = {}
6
-
6
+
7
7
  config = config.with_indifferent_access
8
8
  default_config = {:pool_weight => 1}.merge(config.merge(:adapter => config[:pool_adapter])).with_indifferent_access
9
9
  default_config.delete(:master)
10
10
  default_config.delete(:read_pool)
11
11
  default_config.delete(:pool_adapter)
12
-
12
+
13
13
  master_config = default_config.merge(config[:master]).with_indifferent_access
14
14
  establish_adapter(master_config[:adapter])
15
15
  master_connection = send("#{master_config[:adapter]}_connection".to_sym, master_config)
16
16
  master_connection.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless master_connection.class.include?(SeamlessDatabasePool::ConnectTimeout)
17
17
  master_connection.connect_timeout = master_config[:connect_timeout]
18
18
  pool_weights[master_connection] = master_config[:pool_weight].to_i if master_config[:pool_weight].to_i > 0
19
-
19
+
20
20
  read_connections = []
21
21
  config[:read_pool].each do |read_config|
22
22
  read_config = default_config.merge(read_config).with_indifferent_access
23
23
  read_config[:pool_weight] = read_config[:pool_weight].to_i
24
24
  if read_config[:pool_weight] > 0
25
- establish_adapter(read_config[:adapter])
26
- conn = send("#{read_config[:adapter]}_connection".to_sym, read_config)
27
- conn.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless conn.class.include?(SeamlessDatabasePool::ConnectTimeout)
28
- conn.connect_timeout = read_config[:connect_timeout]
29
- read_connections << conn
30
- pool_weights[conn] = read_config[:pool_weight]
25
+ begin
26
+ establish_adapter(read_config[:adapter])
27
+ conn = send("#{read_config[:adapter]}_connection".to_sym, read_config)
28
+ conn.class.send(:include, SeamlessDatabasePool::ConnectTimeout) unless conn.class.include?(SeamlessDatabasePool::ConnectTimeout)
29
+ conn.connect_timeout = read_config[:connect_timeout]
30
+ read_connections << conn
31
+ pool_weights[conn] = read_config[:pool_weight]
32
+ rescue Exception => e
33
+ if logger
34
+ logger.error("Error connecting to read connection #{read_config.inspect}")
35
+ logger.error(e)
36
+ end
37
+ end
31
38
  end
32
39
  end if config[:read_pool]
33
-
40
+
34
41
  @seamless_database_pool_classes ||= {}
35
42
  klass = @seamless_database_pool_classes[master_connection.class]
36
43
  unless klass
37
44
  klass = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
38
45
  @seamless_database_pool_classes[master_connection.class] = klass
39
46
  end
40
-
47
+
41
48
  return klass.new(nil, logger, master_connection, read_connections, pool_weights)
42
49
  end
43
-
50
+
44
51
  def establish_adapter (adapter)
45
52
  raise AdapterNotSpecified.new("database configuration does not specify adapter") unless adapter
46
53
  raise AdapterNotFound.new("database pool must specify adapters") if adapter == 'seamless_database_pool'
@@ -65,7 +72,7 @@ module ActiveRecord
65
72
  end
66
73
 
67
74
  module SeamlessDatabasePoolBehavior
68
- def self.included (base)
75
+ def self.included(base)
69
76
  base.alias_method_chain(:reload, :seamless_database_pool)
70
77
  end
71
78
 
@@ -86,7 +93,7 @@ module ActiveRecord
86
93
  attr_reader :read_connections, :master_connection
87
94
 
88
95
  # Create an anonymous class that extends this one and proxies methods to the pool connections.
89
- def self.adapter_class (master_connection)
96
+ def self.adapter_class(master_connection)
90
97
  # Define methods to proxy to the appropriate pool
91
98
  read_only_methods = [:select_one, :select_all, :select_value, :select_values, :select, :select_rows, :execute, :tables, :columns]
92
99
  master_methods = []
@@ -131,7 +138,7 @@ module ActiveRecord
131
138
  return klass
132
139
  end
133
140
 
134
- def initialize (connection, logger, master_connection, read_connections, pool_weights)
141
+ def initialize(connection, logger, master_connection, read_connections, pool_weights)
135
142
  super(connection, logger)
136
143
 
137
144
  @master_connection = master_connection
@@ -164,35 +171,37 @@ module ActiveRecord
164
171
 
165
172
  def active?
166
173
  active = true
167
- all_connections.each{|conn| active &= conn.active?}
174
+ do_to_connections {|conn| active &= conn.active?}
168
175
  return active
169
176
  end
170
-
177
+
171
178
  def reconnect!
172
- all_connections.each{|conn| conn.reconnect!}
179
+ do_to_connections {|conn| conn.reconnect!}
173
180
  end
174
-
181
+
175
182
  def disconnect!
176
- all_connections.each{|conn| conn.disconnect!}
183
+ do_to_connections {|conn| conn.disconnect!}
177
184
  end
178
-
185
+
179
186
  def reset!
180
- all_connections.each{|conn| conn.reset!}
187
+ do_to_connections {|conn| conn.reset!}
181
188
  end
182
-
189
+
183
190
  def verify!(*ignored)
184
- all_connections.each{|conn| conn.verify!(*ignored)}
191
+ do_to_connections {|conn| conn.verify!(*ignored)}
185
192
  end
186
-
193
+
187
194
  def reset_runtime
188
- all_connections.inject(0.0){|total, conn| total += conn.reset_runtime}
195
+ total = 0.0
196
+ do_to_connections {|conn| total += conn.reset_runtime}
197
+ total
189
198
  end
190
199
 
191
200
  # Get a random read connection from the pool. If the connection is not active, it will attempt to reconnect
192
201
  # to the database. If that fails, it will be removed from the pool for one minute.
193
202
  def random_read_connection
194
203
  weighted_read_connections = available_read_connections
195
- if @use_master or weighted_read_connections.empty?
204
+ if @use_master || weighted_read_connections.empty?
196
205
  return master_connection
197
206
  else
198
207
  weighted_read_connections[rand(weighted_read_connections.length)]
@@ -235,9 +244,9 @@ module ActiveRecord
235
244
  end
236
245
 
237
246
  def expired?
238
- @expires <= Time.now if @expires
247
+ @expires ? @expires <= Time.now : false
239
248
  end
240
-
249
+
241
250
  def reconnect!
242
251
  failed_connection.reconnect!
243
252
  raise DatabaseConnectionError.new unless failed_connection.active?
@@ -251,13 +260,23 @@ module ActiveRecord
251
260
  available = @available_read_connections.last
252
261
  if available.expired?
253
262
  begin
254
- available.reconnect!# unless available.active?
255
- rescue
263
+ @logger.info("Adding dead database connection back to the pool: #{available.inspect}") if @logger
264
+ available.reconnect!
265
+ rescue => e
256
266
  # Couldn't reconnect so try again in a little bit
267
+ if @logger
268
+ @logger.warn("Failed to reconnect with: #{available.inspect}")
269
+ @logger.warn(e)
270
+ end
257
271
  available.expires = 30.seconds.from_now
258
272
  return available.connections
259
273
  end
274
+
275
+ # If reconnect is successful, the connection will have been re-added to @available_read_connections list,
276
+ # so let's pop this old version of the connection
260
277
  @available_read_connections.pop
278
+
279
+ # Now we'll try again after either expiring our bad connection or re-adding our good one
261
280
  return available_read_connections
262
281
  else
263
282
  return available.connections
@@ -274,17 +293,19 @@ module ActiveRecord
274
293
  end
275
294
 
276
295
  # Temporarily remove a connection from the read pool.
277
- def suppress_read_connection (conn, expire)
296
+ def suppress_read_connection(conn, expire)
278
297
  available = available_read_connections
279
298
  connections = available.reject{|c| c == conn}
280
-
299
+
281
300
  # This wasn't a read connection so don't suppress it
282
301
  return if connections.length == available.length
283
-
302
+
284
303
  if connections.empty?
304
+ @logger.warn("All read connections are marked dead; trying them all again.") if @logger
285
305
  # No connections available so we might as well try them all again
286
306
  reset_available_read_connections
287
307
  else
308
+ @logger.warn("Removing #{conn.inspect} from the connection pool for #{expire} seconds") if @logger
288
309
  # Available connections will now not include the suppressed connection for a while
289
310
  @available_read_connections.push(AvailableConnections.new(connections, conn, expire.seconds.from_now))
290
311
  end
@@ -292,13 +313,13 @@ module ActiveRecord
292
313
 
293
314
  private
294
315
 
295
- def proxy_connection_method (connection, method, proxy_type, *args, &block)
316
+ def proxy_connection_method(connection, method, proxy_type, *args, &block)
296
317
  begin
297
318
  connection.send(method, *args, &block)
298
319
  rescue => e
299
320
  # If the statement was a read statement and it wasn't forced against the master connection
300
321
  # try to reconnect if the connection is dead and then re-run the statement.
301
- if proxy_type == :read and !using_master_connection?
322
+ if proxy_type == :read && !using_master_connection?
302
323
  unless connection.active?
303
324
  suppress_read_connection(connection, 30)
304
325
  connection = current_read_connection
@@ -310,7 +331,18 @@ module ActiveRecord
310
331
  end
311
332
  end
312
333
  end
313
-
334
+
335
+ # Yield a block to each connection in the pool. If the connection is dead, ignore the error
336
+ # unless it is the master connection
337
+ def do_to_connections
338
+ all_connections.each do |conn|
339
+ begin
340
+ yield(conn)
341
+ rescue => e
342
+ raise e if conn == master_connection
343
+ end
344
+ end
345
+ end
314
346
  end
315
347
  end
316
348
  end
@@ -2,7 +2,7 @@ module Arel
2
2
  module SqlCompiler
3
3
  # Hook into arel to use the compiler used by the master connection.
4
4
  class Seamless_Database_PoolCompiler < GenericCompiler
5
- def self.new (relation)
5
+ def self.new(relation)
6
6
  @compiler_classes ||= {}
7
7
  master_adapter = relation.engine.connection.master_connection.adapter_name
8
8
  compiler_class = @compiler_classes[master_adapter]
@@ -1,3 +1,5 @@
1
+ require 'timeout'
2
+
1
3
  module SeamlessDatabasePool
2
4
  # This module is mixed into connection adapters to allow the reconnect! method to timeout if the
3
5
  # IP address becomes unreachable. The default timeout is 1 second, but you can change it by setting
@@ -5,7 +7,7 @@ module SeamlessDatabasePool
5
7
  module ConnectTimeout
6
8
  attr_accessor :connect_timeout
7
9
 
8
- def self.included (base)
10
+ def self.included(base)
9
11
  base.alias_method_chain :reconnect!, :connect_timeout
10
12
  end
11
13
 
@@ -14,8 +16,8 @@ module SeamlessDatabasePool
14
16
  timeout(connect_timeout || 1) do
15
17
  reconnect_without_connect_timeout!
16
18
  end
17
- rescue TimeoutError
18
- raise "reconnect timed out"
19
+ rescue Timeout::Error
20
+ raise ActiveRecord::ConnectionTimeoutError.new("reconnect timed out")
19
21
  end
20
22
  end
21
23
  end
@@ -3,7 +3,7 @@ module SeamlessDatabasePool
3
3
  # and it will keep track of how often each connection calls update, insert, execute,
4
4
  # or select.
5
5
  module ConnectionStatistics
6
- def self.included (base)
6
+ def self.included(base)
7
7
  base.alias_method_chain(:update, :connection_statistics)
8
8
  base.alias_method_chain(:insert, :connection_statistics)
9
9
  base.alias_method_chain(:execute, :connection_statistics)
@@ -19,19 +19,19 @@ module SeamlessDatabasePool
19
19
  @connection_statistics = {}
20
20
  end
21
21
 
22
- def update_with_connection_statistics (sql, name = nil)
22
+ def update_with_connection_statistics(sql, name = nil)
23
23
  increment_connection_statistic(:update) do
24
24
  update_without_connection_statistics(sql, name)
25
25
  end
26
26
  end
27
27
 
28
- def insert_with_connection_statistics (sql, name = nil)
28
+ def insert_with_connection_statistics(sql, name = nil)
29
29
  increment_connection_statistic(:insert) do
30
30
  insert_without_connection_statistics(sql, name)
31
31
  end
32
32
  end
33
33
 
34
- def execute_with_connection_statistics (sql, name = nil)
34
+ def execute_with_connection_statistics(sql, name = nil)
35
35
  increment_connection_statistic(:execute) do
36
36
  execute_without_connection_statistics(sql, name)
37
37
  end
@@ -39,13 +39,13 @@ module SeamlessDatabasePool
39
39
 
40
40
  protected
41
41
 
42
- def select_with_connection_statistics (sql, name = nil)
42
+ def select_with_connection_statistics(sql, name = nil)
43
43
  increment_connection_statistic(:select) do
44
44
  select_without_connection_statistics(sql, name)
45
45
  end
46
46
  end
47
47
 
48
- def increment_connection_statistic (method)
48
+ def increment_connection_statistic(method)
49
49
  if @counting_pool_statistics
50
50
  yield
51
51
  else
@@ -13,11 +13,15 @@ module SeamlessDatabasePool
13
13
  # ...
14
14
 
15
15
  module ControllerFilter
16
- def self.included (base)
16
+ def self.included(base)
17
17
  unless base.respond_to?(:use_database_pool)
18
18
  base.extend(ClassMethods)
19
19
  base.class_eval do
20
- alias_method_chain :perform_action, :seamless_database_pool
20
+ if base.method_defined?(:perform_action) || base.private_method_defined?(:perform_action)
21
+ alias_method_chain :perform_action, :seamless_database_pool
22
+ else
23
+ alias_method_chain :process, :seamless_database_pool
24
+ end
21
25
  alias_method_chain :redirect_to, :seamless_database_pool
22
26
  end
23
27
  end
@@ -40,7 +44,7 @@ module SeamlessDatabasePool
40
44
  # The configuration is inherited from parent controller classes, so if you have default
41
45
  # behavior, you should simply specify it in ApplicationController to have it available
42
46
  # globally.
43
- def use_database_pool (options)
47
+ def use_database_pool(options)
44
48
  remapped_options = seamless_database_pool_options
45
49
  options.each_pair do |actions, connection_method|
46
50
  unless SeamlessDatabasePool::READ_CONNECTION_METHODS.include?(connection_method)
@@ -69,28 +73,45 @@ module SeamlessDatabasePool
69
73
  self.class.seamless_database_pool_options
70
74
  end
71
75
 
72
- def perform_action_with_seamless_database_pool
76
+ # Rails 3.x hook for setting the read connection for the request.
77
+ def process_with_seamless_database_pool(action, *args)
78
+ set_read_only_connection_for_block(action) do
79
+ process_without_seamless_database_pool(action, *args)
80
+ end
81
+ end
82
+
83
+ def redirect_to_with_seamless_database_pool(options = {}, response_status = {})
84
+ if SeamlessDatabasePool.read_only_connection_type(nil) == :master
85
+ use_master_db_connection_on_next_request
86
+ end
87
+ redirect_to_without_seamless_database_pool(options, response_status)
88
+ end
89
+
90
+ private
91
+
92
+ # Rails 2.x hook for setting the read connection for the request.
93
+ def perform_action_with_seamless_database_pool(*args)
94
+ set_read_only_connection_for_block(action_name) do
95
+ perform_action_without_seamless_database_pool(*args)
96
+ end
97
+ end
98
+
99
+ # Set the read only connection for a block. Used to set the connection for a controller action.
100
+ def set_read_only_connection_for_block(action)
73
101
  read_pool_method = nil
74
102
  if session
75
103
  read_pool_method = session[:next_request_db_connection]
76
104
  session[:next_request_db_connection] = nil
77
105
  end
78
106
 
79
- read_pool_method ||= seamless_database_pool_options[action_name.to_sym] || seamless_database_pool_options[:all]
107
+ read_pool_method ||= seamless_database_pool_options[action.to_sym] || seamless_database_pool_options[:all]
80
108
  if read_pool_method
81
109
  SeamlessDatabasePool.set_read_only_connection_type(read_pool_method) do
82
- perform_action_without_seamless_database_pool
110
+ yield
83
111
  end
84
112
  else
85
- perform_action_without_seamless_database_pool
86
- end
87
- end
88
-
89
- def redirect_to_with_seamless_database_pool (options = {}, response_status = {})
90
- if SeamlessDatabasePool.read_only_connection_type(nil) == :master
91
- use_master_db_connection_on_next_request
113
+ yield
92
114
  end
93
- redirect_to_without_seamless_database_pool(options, response_status)
94
115
  end
95
116
  end
96
117
  end
@@ -63,7 +63,7 @@ module SeamlessDatabasePool
63
63
  end
64
64
 
65
65
  # Set the read only connection type to either :master, :random, or :persistent.
66
- def set_read_only_connection_type (connection_type)
66
+ def set_read_only_connection_type(connection_type)
67
67
  saved_connection = Thread.current[:read_only_connection]
68
68
  retval = nil
69
69
  begin
@@ -77,14 +77,14 @@ module SeamlessDatabasePool
77
77
  end
78
78
 
79
79
  # Get the read only connection type currently in use. Will be one of :master, :random, or :persistent.
80
- def read_only_connection_type (default = :master)
80
+ def read_only_connection_type(default = :master)
81
81
  connection_type = Thread.current[:read_only_connection] || default
82
82
  connection_type = :persistent if connection_type.kind_of?(Hash)
83
83
  return connection_type
84
84
  end
85
85
 
86
86
  # Get a read only connection from a connection pool.
87
- def read_only_connection (pool_connection)
87
+ def read_only_connection(pool_connection)
88
88
  return pool_connection.master_connection if pool_connection.using_master_connection?
89
89
  connection_type = Thread.current[:read_only_connection]
90
90
 
@@ -103,7 +103,7 @@ module SeamlessDatabasePool
103
103
  end
104
104
 
105
105
  # This method is provided as a way to change the persistent connection when it fails and a new one is substituted.
106
- def set_persistent_read_connection (pool_connection, read_connection)
106
+ def set_persistent_read_connection(pool_connection, read_connection)
107
107
  connection_type = Thread.current[:read_only_connection]
108
108
  connection_type[pool_connection] = read_connection if connection_type.kind_of?(Hash)
109
109
  end
@@ -1,20 +1,17 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
- require 'cgi'
3
2
 
4
3
  describe "SeamlessDatabasePool::ControllerFilter" do
5
4
 
6
5
  module SeamlessDatabasePool
7
6
  class TestApplicationController
8
- attr_reader :action_name, :session
7
+ attr_reader :session
9
8
 
10
- def initialize(action, session = nil)
11
- @action_name = action
12
- session ||= {}
9
+ def initialize(session)
13
10
  @session = session
14
11
  end
15
12
 
16
- def perform_action
17
- send action_name
13
+ def process(action, *args)
14
+ send action
18
15
  end
19
16
 
20
17
  def redirect_to (options = {}, response_status = {})
@@ -59,78 +56,95 @@ describe "SeamlessDatabasePool::ControllerFilter" do
59
56
  redirect_to(:action => :read)
60
57
  end
61
58
  end
59
+
60
+ class TestRails2ApplicationController < TestApplicationController
61
+ attr_reader :action_name
62
+
63
+ def process(action, *args)
64
+ @action_name = action
65
+ perform_action
66
+ end
67
+
68
+ private
69
+
70
+ def perform_action
71
+ send action_name
72
+ end
73
+ end
74
+
75
+ class TestRails2BaseController < TestRails2ApplicationController
76
+ include ::SeamlessDatabasePool::ControllerFilter
77
+
78
+ use_database_pool :read => :persistent
79
+
80
+ def read
81
+ ::SeamlessDatabasePool.read_only_connection_type
82
+ end
83
+ end
62
84
  end
63
85
 
86
+ let(:session){Hash.new}
87
+ let(:controller){SeamlessDatabasePool::TestOtherController.new(session)}
88
+
64
89
  it "should work with nothing set" do
65
- controller = SeamlessDatabasePool::TestApplicationController.new('base_action')
66
- controller.perform_action.should == :master
90
+ controller = SeamlessDatabasePool::TestApplicationController.new(session)
91
+ controller.process('base_action').should == :master
67
92
  end
68
93
 
69
94
  it "should allow setting a connection type for a single action" do
70
- controller = SeamlessDatabasePool::TestBaseController.new('read')
71
- controller.perform_action.should == :persistent
95
+ controller = SeamlessDatabasePool::TestBaseController.new(session)
96
+ controller.process('read').should == :persistent
72
97
  end
73
98
 
74
99
  it "should allow setting a connection type for actions" do
75
- controller = SeamlessDatabasePool::TestOtherController.new('edit')
76
- controller.perform_action.should == :master
77
- controller = SeamlessDatabasePool::TestOtherController.new('save')
78
- controller.perform_action.should == :master
100
+ controller.process('edit').should == :master
101
+ controller.process('save').should == :master
79
102
  end
80
103
 
81
104
  it "should allow setting a connection type for all actions" do
82
- controller = SeamlessDatabasePool::TestOtherController.new('other')
83
- controller.perform_action.should == :random
105
+ controller.process('other').should == :random
84
106
  end
85
107
 
86
108
  it "should inherit the superclass' options" do
87
- controller = SeamlessDatabasePool::TestOtherController.new('read')
88
- controller.perform_action.should == :persistent
109
+ controller.process('read').should == :persistent
89
110
  end
90
111
 
91
112
  it "should be able to force using the master connection on the next request" do
92
- session = {}
93
-
94
113
  # First request
95
- controller = SeamlessDatabasePool::TestOtherController.new('read', session)
96
- controller.perform_action.should == :persistent
114
+ controller.process('read').should == :persistent
97
115
  controller.use_master_db_connection_on_next_request
98
116
 
99
117
  # Second request
100
- controller = SeamlessDatabasePool::TestOtherController.new('read', session)
101
- controller.perform_action.should == :master
118
+ controller.process('read').should == :master
102
119
 
103
120
  # Third request
104
- controller = SeamlessDatabasePool::TestOtherController.new('read', session)
105
- controller.perform_action.should == :persistent
121
+ controller.process('read').should == :persistent
106
122
  end
107
123
 
108
124
  it "should not break trying to force the master connection if sessions are not enabled" do
109
- controller = SeamlessDatabasePool::TestOtherController.new('read', nil)
110
- controller.perform_action.should == :persistent
125
+ controller.process('read').should == :persistent
111
126
  controller.use_master_db_connection_on_next_request
112
127
 
113
128
  # Second request
114
- controller = SeamlessDatabasePool::TestOtherController.new('read', nil)
115
- controller.perform_action.should == :persistent
129
+ session.clear
130
+ controller.process('read').should == :persistent
116
131
  end
117
132
 
118
133
  it "should force the master connection on the next request for a redirect in master connection block" do
119
- session = {}
120
- controller = SeamlessDatabasePool::TestOtherController.new('redirect_master_action', session)
121
- controller.perform_action.should == {:action => :read}
134
+ controller = SeamlessDatabasePool::TestOtherController.new(session)
135
+ controller.process('redirect_master_action').should == {:action => :read}
122
136
 
123
- controller = SeamlessDatabasePool::TestOtherController.new('read', session)
124
- controller.perform_action.should == :master
137
+ controller.process('read').should == :master
125
138
  end
126
139
 
127
140
  it "should not force the master connection on the next request for a redirect not in master connection block" do
128
- session = {}
129
- controller = SeamlessDatabasePool::TestOtherController.new('redirect_read_action', session)
130
- controller.perform_action.should == {:action => :read}
141
+ controller.process('redirect_read_action').should == {:action => :read}
131
142
 
132
- controller = SeamlessDatabasePool::TestOtherController.new('read', session)
133
- controller.perform_action.should == :persistent
143
+ controller.process('read').should == :persistent
134
144
  end
135
145
 
146
+ it "should work with a Rails 2 controller" do
147
+ controller = SeamlessDatabasePool::TestRails2BaseController.new(session)
148
+ controller.process('read').should == :persistent
149
+ end
136
150
  end
@@ -11,7 +11,7 @@ module SeamlessDatabasePool
11
11
  end
12
12
 
13
13
  def reconnect!
14
- sleep(0.25)
14
+ sleep(0.1)
15
15
  end
16
16
  end
17
17
 
@@ -68,60 +68,60 @@ describe "SeamlessDatabasePoolAdapter ActiveRecord::Base extension" do
68
68
  end
69
69
 
70
70
  describe "SeamlessDatabasePoolAdapter" do
71
-
72
- before(:each) do
73
- @master_connection = SeamlessDatabasePool::MockMasterConnection.new("master")
74
- @read_connection_1 = SeamlessDatabasePool::MockConnection.new("read_1")
75
- @read_connection_2 = SeamlessDatabasePool::MockConnection.new("read_2")
76
- weights = {@master_connection => 1, @read_connection_1 => 1, @read_connection_2 => 2}
77
- connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
78
- @pool_connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1, @read_connection_2], weights)
71
+
72
+ let(:master_connection){ SeamlessDatabasePool::MockMasterConnection.new("master") }
73
+ let(:read_connection_1){ SeamlessDatabasePool::MockConnection.new("read_1") }
74
+ let(:read_connection_2){ SeamlessDatabasePool::MockConnection.new("read_2") }
75
+ let(:pool_connection) do
76
+ weights = {master_connection => 1, read_connection_1 => 1, read_connection_2 => 2}
77
+ connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
78
+ connection_class.new(nil, nil, master_connection, [read_connection_1, read_connection_2], weights)
79
79
  end
80
80
 
81
81
  context "selecting a connection from the pool" do
82
82
  it "should initialize the connection pool" do
83
- @pool_connection.master_connection.should == @master_connection
84
- @pool_connection.read_connections.should == [@read_connection_1, @read_connection_2]
85
- @pool_connection.all_connections.should == [@master_connection, @read_connection_1, @read_connection_2]
86
- @pool_connection.pool_weight(@master_connection).should == 1
87
- @pool_connection.pool_weight(@read_connection_1).should == 1
88
- @pool_connection.pool_weight(@read_connection_2).should == 2
83
+ pool_connection.master_connection.should == master_connection
84
+ pool_connection.read_connections.should == [read_connection_1, read_connection_2]
85
+ pool_connection.all_connections.should == [master_connection, read_connection_1, read_connection_2]
86
+ pool_connection.pool_weight(master_connection).should == 1
87
+ pool_connection.pool_weight(read_connection_1).should == 1
88
+ pool_connection.pool_weight(read_connection_2).should == 2
89
89
  end
90
90
 
91
91
  it "should return the current read connection" do
92
- SeamlessDatabasePool.should_receive(:read_only_connection).with(@pool_connection).and_return(:current)
93
- @pool_connection.current_read_connection.should == :current
92
+ SeamlessDatabasePool.should_receive(:read_only_connection).with(pool_connection).and_return(:current)
93
+ pool_connection.current_read_connection.should == :current
94
94
  end
95
95
 
96
96
  it "should select a random read connection" do
97
97
  mock_connection = stub(:connection, :active? => true)
98
- @pool_connection.should_receive(:available_read_connections).and_return([:fake1, :fake2, mock_connection])
99
- @pool_connection.should_receive(:rand).with(3).and_return(2)
100
- @pool_connection.random_read_connection.should == mock_connection
98
+ pool_connection.should_receive(:available_read_connections).and_return([:fake1, :fake2, mock_connection])
99
+ pool_connection.should_receive(:rand).with(3).and_return(2)
100
+ pool_connection.random_read_connection.should == mock_connection
101
101
  end
102
102
 
103
103
  it "should select the master connection if the read pool is empty" do
104
- @pool_connection.should_receive(:available_read_connections).and_return([])
105
- @pool_connection.random_read_connection.should == @master_connection
104
+ pool_connection.should_receive(:available_read_connections).and_return([])
105
+ pool_connection.random_read_connection.should == master_connection
106
106
  end
107
107
 
108
108
  it "should use the master connection in a block" do
109
- connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
110
- connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
111
- connection.random_read_connection.should == @read_connection_1
109
+ connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
110
+ connection = connection_class.new(nil, mock(:logger), master_connection, [read_connection_1], {read_connection_1 => 1})
111
+ connection.random_read_connection.should == read_connection_1
112
112
  connection.use_master_connection do
113
- connection.random_read_connection.should == @master_connection
113
+ connection.random_read_connection.should == master_connection
114
114
  end
115
- connection.random_read_connection.should == @read_connection_1
115
+ connection.random_read_connection.should == read_connection_1
116
116
  end
117
117
 
118
118
  it "should use the master connection inside a transaction" do
119
- connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
120
- connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
121
- @master_connection.should_receive(:transaction).and_yield
122
- @master_connection.should_receive(:select).with('Transaction SQL', nil)
123
- @read_connection_1.should_receive(:select).with('SQL 1', nil)
124
- @read_connection_1.should_receive(:select).with('SQL 2', nil)
119
+ connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
120
+ connection = connection_class.new(nil, mock(:logger), master_connection, [read_connection_1], {read_connection_1 => 1})
121
+ master_connection.should_receive(:transaction).and_yield
122
+ master_connection.should_receive(:select).with('Transaction SQL', nil)
123
+ read_connection_1.should_receive(:select).with('SQL 1', nil)
124
+ read_connection_1.should_receive(:select).with('SQL 2', nil)
125
125
 
126
126
  SeamlessDatabasePool.use_persistent_read_connection do
127
127
  connection.send(:select, 'SQL 1', nil)
@@ -135,87 +135,87 @@ describe "SeamlessDatabasePoolAdapter" do
135
135
 
136
136
  context "read connection methods" do
137
137
  it "should proxy select methods to a read connection" do
138
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
139
- @read_connection_1.should_receive(:select).with('SQL').and_return(:retval)
140
- @pool_connection.send(:select, 'SQL').should == :retval
138
+ pool_connection.should_receive(:current_read_connection).and_return(read_connection_1)
139
+ read_connection_1.should_receive(:select).with('SQL').and_return(:retval)
140
+ pool_connection.send(:select, 'SQL').should == :retval
141
141
  end
142
142
 
143
143
  it "should proxy execute methods to a read connection" do
144
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
145
- @read_connection_1.should_receive(:execute).with('SQL').and_return(:retval)
146
- @pool_connection.execute('SQL').should == :retval
144
+ pool_connection.should_receive(:current_read_connection).and_return(read_connection_1)
145
+ read_connection_1.should_receive(:execute).with('SQL').and_return(:retval)
146
+ pool_connection.execute('SQL').should == :retval
147
147
  end
148
148
 
149
149
  it "should proxy select_rows methods to a read connection" do
150
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
151
- @read_connection_1.should_receive(:select_rows).with('SQL').and_return(:retval)
152
- @pool_connection.select_rows('SQL').should == :retval
150
+ pool_connection.should_receive(:current_read_connection).and_return(read_connection_1)
151
+ read_connection_1.should_receive(:select_rows).with('SQL').and_return(:retval)
152
+ pool_connection.select_rows('SQL').should == :retval
153
153
  end
154
154
  end
155
155
 
156
156
  context "master connection methods" do
157
157
  it "should proxy insert method to the master connection" do
158
- @master_connection.should_receive(:insert).with('SQL').and_return(:retval)
159
- @pool_connection.insert('SQL').should == :retval
158
+ master_connection.should_receive(:insert).with('SQL').and_return(:retval)
159
+ pool_connection.insert('SQL').should == :retval
160
160
  end
161
161
 
162
162
  it "should proxy update method to the master connection" do
163
- @master_connection.should_receive(:update).with('SQL').and_return(:retval)
164
- @pool_connection.update('SQL').should == :retval
163
+ master_connection.should_receive(:update).with('SQL').and_return(:retval)
164
+ pool_connection.update('SQL').should == :retval
165
165
  end
166
166
 
167
167
  it "should proxy columns method to the master connection" do
168
- @master_connection.should_receive(:columns).with(:table).and_return(:retval)
169
- @pool_connection.columns(:table).should == :retval
168
+ master_connection.should_receive(:columns).with(:table).and_return(:retval)
169
+ pool_connection.columns(:table).should == :retval
170
170
  end
171
171
  end
172
172
 
173
173
  context "fork to all connections" do
174
174
  it "should fork active? to all connections and return true if all are up" do
175
- @master_connection.should_receive(:active?).and_return(true)
176
- @read_connection_1.should_receive(:active?).and_return(true)
177
- @read_connection_2.should_receive(:active?).and_return(true)
178
- @pool_connection.active?.should == true
175
+ master_connection.should_receive(:active?).and_return(true)
176
+ read_connection_1.should_receive(:active?).and_return(true)
177
+ read_connection_2.should_receive(:active?).and_return(true)
178
+ pool_connection.active?.should == true
179
179
  end
180
180
 
181
181
  it "should fork active? to all connections and return false if one is down" do
182
- @master_connection.should_receive(:active?).and_return(true)
183
- @read_connection_1.should_receive(:active?).and_return(true)
184
- @read_connection_2.should_receive(:active?).and_return(false)
185
- @pool_connection.active?.should == false
182
+ master_connection.should_receive(:active?).and_return(true)
183
+ read_connection_1.should_receive(:active?).and_return(true)
184
+ read_connection_2.should_receive(:active?).and_return(false)
185
+ pool_connection.active?.should == false
186
186
  end
187
187
 
188
188
  it "should fork verify! to all connections" do
189
- @master_connection.should_receive(:verify!).with(5)
190
- @read_connection_1.should_receive(:verify!).with(5)
191
- @read_connection_2.should_receive(:verify!).with(5)
192
- @pool_connection.verify!(5)
189
+ master_connection.should_receive(:verify!).with(5)
190
+ read_connection_1.should_receive(:verify!).with(5)
191
+ read_connection_2.should_receive(:verify!).with(5)
192
+ pool_connection.verify!(5)
193
193
  end
194
194
 
195
195
  it "should fork disconnect! to all connections" do
196
- @master_connection.should_receive(:disconnect!)
197
- @read_connection_1.should_receive(:disconnect!)
198
- @read_connection_2.should_receive(:disconnect!)
199
- @pool_connection.disconnect!
196
+ master_connection.should_receive(:disconnect!)
197
+ read_connection_1.should_receive(:disconnect!)
198
+ read_connection_2.should_receive(:disconnect!)
199
+ pool_connection.disconnect!
200
200
  end
201
201
 
202
202
  it "should fork reconnect! to all connections" do
203
- @master_connection.should_receive(:reconnect!)
204
- @read_connection_1.should_receive(:reconnect!)
205
- @read_connection_2.should_receive(:reconnect!)
206
- @pool_connection.reconnect!
203
+ master_connection.should_receive(:reconnect!)
204
+ read_connection_1.should_receive(:reconnect!)
205
+ read_connection_2.should_receive(:reconnect!)
206
+ pool_connection.reconnect!
207
207
  end
208
208
 
209
209
  it "should timeout reconnect! calls to dead servers" do
210
- @read_connection_1.connect_timeout = 0.1
211
- lambda{@pool_connection.reconnect!}.should raise_error("reconnect timed out")
210
+ read_connection_1.connect_timeout = 0.01
211
+ lambda{read_connection_1.reconnect!}.should raise_error("reconnect timed out")
212
212
  end
213
213
 
214
214
  it "should fork reset_runtime to all connections" do
215
- @master_connection.should_receive(:reset_runtime).and_return(1)
216
- @read_connection_1.should_receive(:reset_runtime).and_return(2)
217
- @read_connection_2.should_receive(:reset_runtime).and_return(3)
218
- @pool_connection.reset_runtime.should == 6
215
+ master_connection.should_receive(:reset_runtime).and_return(1)
216
+ read_connection_1.should_receive(:reset_runtime).and_return(2)
217
+ read_connection_2.should_receive(:reset_runtime).and_return(3)
218
+ pool_connection.reset_runtime.should == 6
219
219
  end
220
220
  end
221
221
 
@@ -223,135 +223,135 @@ describe "SeamlessDatabasePoolAdapter" do
223
223
  it "should proxy requests to a connection" do
224
224
  args = [:arg1, :arg2]
225
225
  block = Proc.new{}
226
- @master_connection.should_receive(:select_value).with(*args, &block)
227
- @master_connection.should_not_receive(:active?)
228
- @master_connection.should_not_receive(:reconnect!)
229
- @pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :master, *args, &block)
226
+ master_connection.should_receive(:select_value).with(*args, &block)
227
+ master_connection.should_not_receive(:active?)
228
+ master_connection.should_not_receive(:reconnect!)
229
+ pool_connection.send(:proxy_connection_method, master_connection, :select_value, :master, *args, &block)
230
230
  end
231
231
 
232
232
  it "should try to reconnect dead connections when they become available again" do
233
- @master_connection.stub!(:select_value).and_raise("SQL ERROR")
234
- @master_connection.should_receive(:active?).and_return(false, false, true)
235
- @master_connection.should_receive(:reconnect!)
233
+ master_connection.stub!(:select_value).and_raise("SQL ERROR")
234
+ master_connection.should_receive(:active?).and_return(false, false, true)
235
+ master_connection.should_receive(:reconnect!)
236
236
  now = Time.now
237
- lambda{@pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
237
+ lambda{pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
238
238
  Time.stub!(:now).and_return(now + 31)
239
- lambda{@pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
239
+ lambda{pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
240
240
  end
241
241
 
242
242
  it "should not try to reconnect live connections" do
243
243
  args = [:arg1, :arg2]
244
244
  block = Proc.new{}
245
- @master_connection.should_receive(:select_value).with(*args, &block).twice.and_raise("SQL ERROR")
246
- @master_connection.should_receive(:active?).and_return(true)
247
- @master_connection.should_not_receive(:reconnect!)
248
- lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :read, *args, &block)}.should raise_error("SQL ERROR")
245
+ master_connection.should_receive(:select_value).with(*args, &block).twice.and_raise("SQL ERROR")
246
+ master_connection.should_receive(:active?).and_return(true)
247
+ master_connection.should_not_receive(:reconnect!)
248
+ lambda{pool_connection.send(:proxy_connection_method, master_connection, :select_value, :read, *args, &block)}.should raise_error("SQL ERROR")
249
249
  end
250
250
 
251
251
  it "should not try to reconnect a connection during a retry" do
252
252
  args = [:arg1, :arg2]
253
253
  block = Proc.new{}
254
- @master_connection.should_receive(:select_value).with(*args, &block).and_raise("SQL ERROR")
255
- @master_connection.should_not_receive(:active?)
256
- @master_connection.should_not_receive(:reconnect!)
257
- lambda{@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :retry, *args, &block)}.should raise_error("SQL ERROR")
254
+ master_connection.should_receive(:select_value).with(*args, &block).and_raise("SQL ERROR")
255
+ master_connection.should_not_receive(:active?)
256
+ master_connection.should_not_receive(:reconnect!)
257
+ lambda{pool_connection.send(:proxy_connection_method, master_connection, :select_value, :retry, *args, &block)}.should raise_error("SQL ERROR")
258
258
  end
259
259
 
260
260
  it "should try to execute a read statement again after a connection error" do
261
261
  connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
262
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
263
- @read_connection_1.should_receive(:select).with('SQL').and_raise(connection_error)
264
- @read_connection_1.should_receive(:active?).and_return(true)
265
- @pool_connection.should_not_receive(:suppress_read_connection)
262
+ pool_connection.should_receive(:current_read_connection).and_return(read_connection_1)
263
+ read_connection_1.should_receive(:select).with('SQL').and_raise(connection_error)
264
+ read_connection_1.should_receive(:active?).and_return(true)
265
+ pool_connection.should_not_receive(:suppress_read_connection)
266
266
  SeamlessDatabasePool.should_not_receive(:set_persistent_read_connection)
267
- @read_connection_1.should_receive(:select).with('SQL').and_return(:results)
268
- @pool_connection.send(:select, 'SQL').should == :results
267
+ read_connection_1.should_receive(:select).with('SQL').and_return(:results)
268
+ pool_connection.send(:select, 'SQL').should == :results
269
269
  end
270
270
 
271
271
  it "should not try to execute a read statement again after a connection error if the master connection must be used" do
272
- @master_connection.should_receive(:select).with('SQL').and_raise("Fail")
273
- @pool_connection.use_master_connection do
274
- lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("Fail")
272
+ master_connection.should_receive(:select).with('SQL').and_raise("Fail")
273
+ pool_connection.use_master_connection do
274
+ lambda{pool_connection.send(:select, 'SQL')}.should raise_error("Fail")
275
275
  end
276
276
  end
277
277
 
278
278
  it "should not try to execute a read statement again after a non-connection error" do
279
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
280
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL').and_raise("SQL Error")
281
- lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("SQL Error")
279
+ pool_connection.should_receive(:current_read_connection).and_return(read_connection_1)
280
+ pool_connection.should_receive(:proxy_connection_method).with(read_connection_1, :select, :read, 'SQL').and_raise("SQL Error")
281
+ lambda{pool_connection.send(:select, 'SQL')}.should raise_error("SQL Error")
282
282
  end
283
283
 
284
284
  it "should use a different connection on a retry if the original connection could not be reconnected" do
285
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1, @read_connection_2)
286
- @read_connection_1.should_receive(:select).with('SQL').and_raise("Fail")
287
- @read_connection_1.should_receive(:active?).and_return(false)
288
- @pool_connection.should_receive(:suppress_read_connection).with(@read_connection_1, 30)
289
- SeamlessDatabasePool.should_receive(:set_persistent_read_connection).with(@pool_connection, @read_connection_2)
290
- @read_connection_2.should_receive(:select).with('SQL').and_return(:results)
291
- @pool_connection.send(:select, 'SQL').should == :results
285
+ pool_connection.should_receive(:current_read_connection).and_return(read_connection_1, read_connection_2)
286
+ read_connection_1.should_receive(:select).with('SQL').and_raise("Fail")
287
+ read_connection_1.should_receive(:active?).and_return(false)
288
+ pool_connection.should_receive(:suppress_read_connection).with(read_connection_1, 30)
289
+ SeamlessDatabasePool.should_receive(:set_persistent_read_connection).with(pool_connection, read_connection_2)
290
+ read_connection_2.should_receive(:select).with('SQL').and_return(:results)
291
+ pool_connection.send(:select, 'SQL').should == :results
292
292
  end
293
293
 
294
294
  it "should keep track of read connections that can't be reconnected for a set period" do
295
- @pool_connection.available_read_connections.should include(@read_connection_1)
296
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
297
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
295
+ pool_connection.available_read_connections.should include(read_connection_1)
296
+ pool_connection.suppress_read_connection(read_connection_1, 30)
297
+ pool_connection.available_read_connections.should_not include(read_connection_1)
298
298
  end
299
299
 
300
300
  it "should return dead connections to the pool after the timeout has expired" do
301
- @pool_connection.available_read_connections.should include(@read_connection_1)
302
- @pool_connection.suppress_read_connection(@read_connection_1, 0.2)
303
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
301
+ pool_connection.available_read_connections.should include(read_connection_1)
302
+ pool_connection.suppress_read_connection(read_connection_1, 0.2)
303
+ pool_connection.available_read_connections.should_not include(read_connection_1)
304
304
  sleep(0.3)
305
- @pool_connection.available_read_connections.should include(@read_connection_1)
305
+ pool_connection.available_read_connections.should include(read_connection_1)
306
306
  end
307
307
 
308
308
  it "should not return a connection to the pool until it can be reconnected" do
309
- @pool_connection.available_read_connections.should include(@read_connection_1)
310
- @pool_connection.suppress_read_connection(@read_connection_1, 0.2)
311
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
309
+ pool_connection.available_read_connections.should include(read_connection_1)
310
+ pool_connection.suppress_read_connection(read_connection_1, 0.2)
311
+ pool_connection.available_read_connections.should_not include(read_connection_1)
312
312
  sleep(0.3)
313
- @read_connection_1.should_receive(:reconnect!)
314
- @read_connection_1.should_receive(:active?).and_return(false)
315
- @pool_connection.available_read_connections.should_not include(@read_connection_1)
313
+ read_connection_1.should_receive(:reconnect!)
314
+ read_connection_1.should_receive(:active?).and_return(false)
315
+ pool_connection.available_read_connections.should_not include(read_connection_1)
316
316
  end
317
317
 
318
318
  it "should try all connections again if none of them can be reconnected" do
319
- stack = @pool_connection.instance_variable_get(:@available_read_connections)
319
+ stack = pool_connection.instance_variable_get(:@available_read_connections)
320
320
 
321
- available = @pool_connection.available_read_connections
322
- available.should include(@read_connection_1)
323
- available.should include(@read_connection_2)
324
- available.should include(@master_connection)
321
+ available = pool_connection.available_read_connections
322
+ available.should include(read_connection_1)
323
+ available.should include(read_connection_2)
324
+ available.should include(master_connection)
325
325
  stack.size.should == 1
326
326
 
327
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
328
- available = @pool_connection.available_read_connections
329
- available.should_not include(@read_connection_1)
330
- available.should include(@read_connection_2)
331
- available.should include(@master_connection)
327
+ pool_connection.suppress_read_connection(read_connection_1, 30)
328
+ available = pool_connection.available_read_connections
329
+ available.should_not include(read_connection_1)
330
+ available.should include(read_connection_2)
331
+ available.should include(master_connection)
332
332
  stack.size.should == 2
333
333
 
334
- @pool_connection.suppress_read_connection(@master_connection, 30)
335
- available = @pool_connection.available_read_connections
336
- available.should_not include(@read_connection_1)
337
- available.should include(@read_connection_2)
338
- available.should_not include(@master_connection)
334
+ pool_connection.suppress_read_connection(master_connection, 30)
335
+ available = pool_connection.available_read_connections
336
+ available.should_not include(read_connection_1)
337
+ available.should include(read_connection_2)
338
+ available.should_not include(master_connection)
339
339
  stack.size.should == 3
340
340
 
341
- @pool_connection.suppress_read_connection(@read_connection_2, 30)
342
- available = @pool_connection.available_read_connections
343
- available.should include(@read_connection_1)
344
- available.should include(@read_connection_2)
345
- available.should include(@master_connection)
341
+ pool_connection.suppress_read_connection(read_connection_2, 30)
342
+ available = pool_connection.available_read_connections
343
+ available.should include(read_connection_1)
344
+ available.should include(read_connection_2)
345
+ available.should include(master_connection)
346
346
  stack.size.should == 1
347
347
  end
348
348
 
349
349
  it "should not try to suppress a read connection that wasn't available in the read pool" do
350
- stack = @pool_connection.instance_variable_get(:@available_read_connections)
350
+ stack = pool_connection.instance_variable_get(:@available_read_connections)
351
351
  stack.size.should == 1
352
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
352
+ pool_connection.suppress_read_connection(read_connection_1, 30)
353
353
  stack.size.should == 2
354
- @pool_connection.suppress_read_connection(@read_connection_1, 30)
354
+ pool_connection.suppress_read_connection(read_connection_1, 30)
355
355
  stack.size.should == 2
356
356
  end
357
357
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seamless_database_pool
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease: false
4
+ hash: 25
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 6
10
- version: 1.0.6
9
+ - 7
10
+ version: 1.0.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brian Durand
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-20 00:00:00 -05:00
18
+ date: 2011-06-23 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -42,12 +42,11 @@ dependencies:
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- hash: 13
45
+ hash: 3
46
46
  segments:
47
- - 1
48
47
  - 2
49
- - 9
50
- version: 1.2.9
48
+ - 0
49
+ version: "2.0"
51
50
  type: :development
52
51
  version_requirements: *id002
53
52
  - !ruby/object:Gem::Dependency
@@ -71,6 +70,7 @@ executables: []
71
70
  extensions: []
72
71
 
73
72
  extra_rdoc_files:
73
+ - MIT-LICENSE
74
74
  - README.rdoc
75
75
  files:
76
76
  - README.rdoc
@@ -83,20 +83,21 @@ files:
83
83
  - lib/seamless_database_pool/controller_filter.rb
84
84
  - spec/connection_adapters_spec.rb
85
85
  - spec/connection_statistics_spec.rb
86
+ - spec/controller_filter_spec.rb
86
87
  - spec/database.yml
87
- - spec/filter_spec.rb
88
88
  - spec/seamless_database_pool_adapter_spec.rb
89
89
  - spec/seamless_database_pool_spec.rb
90
90
  - spec/spec_helper.rb
91
91
  - spec/test_adapter/active_record/connection_adapters/read_only_adapter.rb
92
92
  - spec/test_model.rb
93
+ - MIT-LICENSE
93
94
  has_rdoc: true
94
95
  homepage: http://github.com/bdurand/seamless_database_pool
95
96
  licenses: []
96
97
 
97
98
  post_install_message:
98
- rdoc_options:
99
- - --charset=UTF-8
99
+ rdoc_options: []
100
+
100
101
  require_paths:
101
102
  - lib
102
103
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -120,16 +121,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
121
  requirements: []
121
122
 
122
123
  rubyforge_project:
123
- rubygems_version: 1.3.7
124
+ rubygems_version: 1.5.2
124
125
  signing_key:
125
126
  specification_version: 3
126
127
  summary: Add support for master/slave database clusters in ActiveRecord to improve performance.
127
- test_files:
128
- - spec/connection_adapters_spec.rb
129
- - spec/connection_statistics_spec.rb
130
- - spec/filter_spec.rb
131
- - spec/seamless_database_pool_adapter_spec.rb
132
- - spec/seamless_database_pool_spec.rb
133
- - spec/spec_helper.rb
134
- - spec/test_adapter/active_record/connection_adapters/read_only_adapter.rb
135
- - spec/test_model.rb
128
+ test_files: []
129
+