seamless_database_pool 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  spec = Gem::Specification.new do |s|
24
24
  s.name = "seamless_database_pool"
25
- s.version = "1.0.2"
25
+ s.version = "1.0.3"
26
26
  s.author = "Brian Durand"
27
27
  s.platform = Gem::Platform::RUBY
28
28
  s.summary = "Support for master/slave database clusters in ActiveRecord"
@@ -31,9 +31,14 @@ module ActiveRecord
31
31
  end
32
32
  end if config[:read_pool]
33
33
 
34
-
35
- klass = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
36
- klass.new(nil, logger, master_connection, read_connections, pool_weights)
34
+ @seamless_database_pool_classes ||= {}
35
+ klass = @seamless_database_pool_classes[master_connection.class]
36
+ unless klass
37
+ klass = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(master_connection)
38
+ @seamless_database_pool_classes[master_connection.class] = klass
39
+ end
40
+
41
+ return klass.new(nil, logger, master_connection, read_connections, pool_weights)
37
42
  end
38
43
 
39
44
  def self.establish_adapter (adapter)
@@ -66,18 +71,6 @@ module ActiveRecord
66
71
  end
67
72
  alias_method_chain(:reload, :seamless_database_pool)
68
73
  end
69
-
70
- module Associations
71
- class AssociationProxy
72
- # Force reload to use the master connection since it's probably being called for a reason.
73
- def reload_with_seamless_database_pool
74
- SeamlessDatabasePool.use_master_connection do
75
- reload_without_seamless_database_pool
76
- end
77
- end
78
- alias_method_chain(:reload, :seamless_database_pool)
79
- end
80
- end
81
74
 
82
75
  module ConnectionAdapters
83
76
  class SeamlessDatabasePoolAdapter < AbstractAdapter
@@ -87,13 +80,11 @@ module ActiveRecord
87
80
  # Create an anonymous class that extends this one and proxies methods to the pool connections.
88
81
  def self.adapter_class (master_connection)
89
82
  # Define methods to proxy to the appropriate pool
90
- read_only_methods = [:select_one, :select_all, :select_value, :select_values, :select_rows, :select]
91
- connection_methods = [:adapter_name, :active?, :reconnect!, :disconnect!, :reset!, :verify!, :reset_runtime]
83
+ read_only_methods = [:select_one, :select_all, :select_value, :select_values, :select_rows]
92
84
  master_methods = master_connection.public_methods(false) + master_connection.protected_methods(false) + master_connection.private_methods(false)
93
- master_methods -= public_methods(false) + protected_methods(false) + private_methods(false)
85
+ master_methods -= public_instance_methods(false) + protected_instance_methods(false) + private_instance_methods(false)
94
86
  master_methods = master_methods.collect{|m| m.to_sym}
95
87
  master_methods -= read_only_methods
96
- master_methods -= connection_methods
97
88
  master_methods.delete(:transaction)
98
89
 
99
90
  klass = Class.new(self)
@@ -108,29 +99,6 @@ module ActiveRecord
108
99
  end
109
100
  ))
110
101
  end
111
-
112
- read_only_methods.each do |method_name|
113
- klass.class_eval(%Q(
114
- def #{method_name}(*args, &block)
115
- connection = current_read_connection
116
- begin
117
- proxy_connection_method(connection, :#{method_name}, :read, *args, &block)
118
- rescue DatabaseConnectionError => e
119
- unless block or using_master_connection?
120
- # Try again with a different connection if needed unless it could have a side effect
121
- unless connection.active?
122
- suppress_read_connection(connection, 30)
123
- connection = current_read_connection
124
- SeamlessDatabasePool.set_persistent_read_connection(self, connection)
125
- end
126
- proxy_connection_method(connection, :#{method_name}, :retry, *args, &block)
127
- else
128
- raise e.wrapped_exception
129
- end
130
- end
131
- end
132
- ))
133
- end
134
102
 
135
103
  return klass
136
104
  end
@@ -162,6 +130,10 @@ module ActiveRecord
162
130
  return @weighted_read_connections.select{|conn| conn == connection}.size
163
131
  end
164
132
 
133
+ def requires_reloading?
134
+ false
135
+ end
136
+
165
137
  def active?
166
138
  active = true
167
139
  all_connections.each{|conn| active &= conn.active?}
@@ -212,6 +184,21 @@ module ActiveRecord
212
184
  end
213
185
  end
214
186
 
187
+ # Returns the last auto-generated ID from the affected table.
188
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
189
+ master_connection.insert(sql, name, pk, id_value, sequence_name)
190
+ end
191
+
192
+ # Executes the update statement and returns the number of rows affected.
193
+ def update(sql, name = nil)
194
+ master_connection.update(sql, name)
195
+ end
196
+
197
+ # Executes the delete statement and returns the number of rows affected.
198
+ def delete(sql, name = nil)
199
+ master_connection.delete(sql, name)
200
+ end
201
+
215
202
  def using_master_connection?
216
203
  !!@use_master
217
204
  end
@@ -290,6 +277,27 @@ module ActiveRecord
290
277
  end
291
278
  end
292
279
 
280
+ protected
281
+
282
+ def select (sql, name = nil)
283
+ connection = current_read_connection
284
+ begin
285
+ proxy_connection_method(connection, :select, :read, *[sql, name])
286
+ rescue DatabaseConnectionError => e
287
+ unless using_master_connection?
288
+ # Try again with a different connection if needed unless it could have a side effect
289
+ unless connection.active?
290
+ suppress_read_connection(connection, 30)
291
+ connection = current_read_connection
292
+ SeamlessDatabasePool.set_persistent_read_connection(self, connection)
293
+ end
294
+ proxy_connection_method(connection, :select, :retry, *[sql, name])
295
+ else
296
+ raise e.wrapped_exception
297
+ end
298
+ end
299
+ end
300
+
293
301
  private
294
302
 
295
303
  def proxy_connection_method (connection, method, proxy_type, *args, &block)
@@ -118,16 +118,16 @@ describe "SeamlessDatabasePoolAdapter" do
118
118
  connection_class = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.adapter_class(@master_connection)
119
119
  connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1], {@read_connection_1 => 1})
120
120
  @master_connection.should_receive(:transaction).with(true).and_yield
121
- @master_connection.should_receive(:select_one).with('Transaction SQL')
122
- @read_connection_1.should_receive(:select_one).with('SQL 1')
123
- @read_connection_1.should_receive(:select_one).with('SQL 2')
121
+ @master_connection.should_receive(:select).with('Transaction SQL', nil)
122
+ @read_connection_1.should_receive(:select).with('SQL 1', nil)
123
+ @read_connection_1.should_receive(:select).with('SQL 2', nil)
124
124
 
125
125
  SeamlessDatabasePool.use_persistent_read_connection do
126
- connection.select_one('SQL 1')
126
+ connection.send(:select, 'SQL 1', nil)
127
127
  connection.transaction do
128
- connection.select_one('Transaction SQL')
128
+ connection.send(:select, 'Transaction SQL', nil)
129
129
  end
130
- connection.select_one('SQL 2')
130
+ connection.send(:select, 'SQL 2', nil)
131
131
  end
132
132
  end
133
133
 
@@ -135,58 +135,23 @@ describe "SeamlessDatabasePoolAdapter" do
135
135
 
136
136
  it "should proxy select methods to a read connection" do
137
137
  @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
138
- @read_connection_1.should_receive(:select_one).with('SQL').and_return(:retval)
139
- @pool_connection.select_one('SQL').should == :retval
140
- end
141
-
142
- it "should proxy select methods to a read connection" do
143
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
144
- @read_connection_1.should_receive(:select_all).with('SQL').and_return(:retval)
145
- @pool_connection.select_all('SQL').should == :retval
146
- end
147
-
148
- it "should proxy select methods to a read connection" do
149
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
150
- @read_connection_1.should_receive(:select_value).with('SQL').and_return(:retval)
151
- @pool_connection.select_value('SQL').should == :retval
152
- end
153
-
154
- it "should proxy select methods to a read connection" do
155
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
156
- @read_connection_1.should_receive(:select_values).with('SQL').and_return(:retval)
157
- @pool_connection.select_values('SQL').should == :retval
158
- end
159
-
160
- it "should proxy select methods to a read connection" do
161
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
162
- @read_connection_1.should_receive(:select_rows).with('SQL').and_return(:retval)
163
- @pool_connection.select_rows('SQL').should == :retval
164
- end
165
-
166
- it "should proxy select methods to a read connection" do
167
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
168
- @read_connection_1.should_receive(:select).with('SQL', 'name').and_return(:retval)
169
- @pool_connection.send(:select, 'SQL', 'name').should == :retval
138
+ @read_connection_1.should_receive(:select).with('SQL', nil).and_return(:retval)
139
+ @pool_connection.send(:select, 'SQL').should == :retval
170
140
  end
171
141
 
172
142
  # Master connection methods
173
143
 
174
- it "should proxy quote method to the master connection" do
175
- @master_connection.should_receive(:insert).with('SQL').and_return(:retval)
144
+ it "should proxy insert method to the master connection" do
145
+ @master_connection.should_receive(:insert).with('SQL', nil, nil, nil, nil).and_return(:retval)
176
146
  @pool_connection.insert('SQL').should == :retval
177
147
  end
178
148
 
179
- it "should proxy quote method to the master connection" do
180
- @master_connection.should_receive(:update).with('SQL').and_return(:retval)
149
+ it "should proxy update method to the master connection" do
150
+ @master_connection.should_receive(:update).with('SQL', nil).and_return(:retval)
181
151
  @pool_connection.update('SQL').should == :retval
182
152
  end
183
153
 
184
- it "should proxy quote method to the master connection" do
185
- @master_connection.should_receive(:execute).with('SQL').and_return(:retval)
186
- @pool_connection.execute('SQL').should == :retval
187
- end
188
-
189
- it "should proxy quote method to the master connection" do
154
+ it "should proxy columns method to the master connection" do
190
155
  @master_connection.should_receive(:columns).with(:table).and_return(:retval)
191
156
  @pool_connection.columns(:table).should == :retval
192
157
  end
@@ -282,48 +247,40 @@ describe "SeamlessDatabasePoolAdapter" do
282
247
  connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
283
248
  connection_error.wrapped_exception = StandardError.new("Error")
284
249
  @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
285
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select_value, :read, 'SQL').and_raise(connection_error)
250
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL', nil).and_raise(connection_error)
286
251
  @read_connection_1.should_receive(:active?).and_return(true)
287
252
  @pool_connection.should_not_receive(:suppress_read_connection)
288
253
  SeamlessDatabasePool.should_not_receive(:set_persistent_read_connection)
289
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select_value, :retry, 'SQL').and_return(:results)
290
- @pool_connection.select_value('SQL').should == :results
254
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :retry, 'SQL', nil).and_return(:results)
255
+ @pool_connection.send(:select, 'SQL').should == :results
291
256
  end
292
257
 
293
258
  it "should not try to execute a read statement again after a connection error if the master connection must be used" do
294
259
  connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
295
260
  connection_error.wrapped_exception = StandardError.new("Error")
296
261
  @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
297
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select_value, :read, 'SQL').and_raise(connection_error)
262
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL', nil).and_raise(connection_error)
298
263
  @pool_connection.use_master_connection do
299
- lambda{@pool_connection.select_value('SQL')}.should raise_error("Error")
264
+ lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("Error")
300
265
  end
301
266
  end
302
267
 
303
- it "should not try to execute a read statement again after a connection error if there is a block" do
304
- connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
305
- connection_error.wrapped_exception = StandardError.new("Error")
306
- @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
307
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select_value, :read, 'SQL').and_raise(connection_error)
308
- lambda{@pool_connection.select_value('SQL'){}}.should raise_error("Error")
309
- end
310
-
311
268
  it "should not try to execute a read statement again after a non-connection error" do
312
269
  @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
313
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select_value, :read, 'SQL').and_raise("SQL Error")
314
- lambda{@pool_connection.select_value('SQL')}.should raise_error("SQL Error")
270
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL', nil).and_raise("SQL Error")
271
+ lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("SQL Error")
315
272
  end
316
273
 
317
274
  it "should use a different connection on a retry if the original connection could not be reconnected" do
318
275
  connection_error = ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter::DatabaseConnectionError.new
319
276
  connection_error.wrapped_exception = StandardError.new("Error")
320
277
  @pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1, @read_connection_2)
321
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select_value, :read, 'SQL').and_raise(connection_error)
278
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_1, :select, :read, 'SQL', nil).and_raise(connection_error)
322
279
  @read_connection_1.should_receive(:active?).and_return(false)
323
280
  @pool_connection.should_receive(:suppress_read_connection).with(@read_connection_1, 30)
324
281
  SeamlessDatabasePool.should_receive(:set_persistent_read_connection).with(@pool_connection, @read_connection_2)
325
- @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_2, :select_value, :retry, 'SQL').and_return(:results)
326
- @pool_connection.select_value('SQL').should == :results
282
+ @pool_connection.should_receive(:proxy_connection_method).with(@read_connection_2, :select, :retry, 'SQL', nil).and_return(:results)
283
+ @pool_connection.send(:select, 'SQL').should == :results
327
284
  end
328
285
 
329
286
  it "should keep track of read connections that can't be reconnected for a set period" do
@@ -427,11 +384,4 @@ describe "Reload extensions" do
427
384
  @record.should_receive(:reload_without_seamless_database_pool).with(:options)
428
385
  @record.reload(:options)
429
386
  end
430
-
431
- it "should force the master connection on reload of an association" do
432
- association = @record.seamless_database_pool_test_things
433
- SeamlessDatabasePool.should_receive(:use_master_connection).and_yield
434
- association.should_receive(:reload_without_seamless_database_pool)
435
- @record.seamless_database_pool_test_things(true)
436
- end
437
387
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seamless_database_pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-06 00:00:00 -05:00
12
+ date: 2009-05-26 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -22,10 +22,7 @@ extensions: []
22
22
  extra_rdoc_files:
23
23
  - README
24
24
  files:
25
- - lib/active_record
26
- - lib/active_record/connection_adapters
27
25
  - lib/active_record/connection_adapters/seamless_database_pool_adapter.rb
28
- - lib/seamless_database_pool
29
26
  - lib/seamless_database_pool/connect_timeout.rb
30
27
  - lib/seamless_database_pool/connection_statistics.rb
31
28
  - lib/seamless_database_pool/controller_filter.rb
@@ -36,6 +33,8 @@ files:
36
33
  - README
37
34
  has_rdoc: true
38
35
  homepage: http://seamlessdbpool.rubyforge.org
36
+ licenses: []
37
+
39
38
  post_install_message:
40
39
  rdoc_options:
41
40
  - --title
@@ -61,9 +60,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
60
  requirements:
62
61
  - rspec 1.0.8 or higher is needed to run the tests
63
62
  rubyforge_project: seamlessdbpool
64
- rubygems_version: 1.3.1
63
+ rubygems_version: 1.3.3
65
64
  signing_key:
66
- specification_version: 2
65
+ specification_version: 3
67
66
  summary: Support for master/slave database clusters in ActiveRecord
68
67
  test_files:
69
68
  - spec/connection_statistics_spec.rb