seamless_database_pool 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.
|
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 =
|
36
|
-
klass
|
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
|
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 -=
|
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(:
|
122
|
-
@read_connection_1.should_receive(:
|
123
|
-
@read_connection_1.should_receive(:
|
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.
|
126
|
+
connection.send(:select, 'SQL 1', nil)
|
127
127
|
connection.transaction do
|
128
|
-
connection.
|
128
|
+
connection.send(:select, 'Transaction SQL', nil)
|
129
129
|
end
|
130
|
-
connection.
|
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(:
|
139
|
-
@pool_connection.
|
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
|
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
|
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
|
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, :
|
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, :
|
290
|
-
@pool_connection.
|
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, :
|
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.
|
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, :
|
314
|
-
lambda{@pool_connection.
|
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, :
|
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, :
|
326
|
-
@pool_connection.
|
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.
|
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-
|
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.
|
63
|
+
rubygems_version: 1.3.3
|
65
64
|
signing_key:
|
66
|
-
specification_version:
|
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
|