seamless_database_pool 1.0.5 → 1.0.6
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 +52 -4
- data/lib/active_record/connection_adapters/seamless_database_pool_adapter.rb +116 -125
- data/lib/seamless_database_pool/arel_compiler.rb +27 -0
- data/lib/seamless_database_pool.rb +80 -77
- data/spec/connection_adapters_spec.rb +212 -0
- data/spec/database.yml +35 -0
- data/spec/seamless_database_pool_adapter_spec.rb +236 -258
- data/spec/spec_helper.rb +4 -3
- data/spec/test_adapter/active_record/connection_adapters/read_only_adapter.rb +51 -0
- data/spec/test_model.rb +46 -0
- metadata +53 -23
- data/MIT-LICENSE +0 -20
- data/VERSION +0 -1
- data/init.rb +0 -2
- data/seamless_database_pool.gemspec +0 -69
- data/spec/test_models.rb +0 -35
@@ -48,9 +48,9 @@ describe "SeamlessDatabasePoolAdapter ActiveRecord::Base extension" do
|
|
48
48
|
logger = ActiveRecord::Base.logger
|
49
49
|
weights = {master_connection => 1, read_connection_1 => 1, read_connection_2 => 2}
|
50
50
|
|
51
|
-
ActiveRecord::Base.should_receive(:writer_connection).with(
|
52
|
-
ActiveRecord::Base.should_receive(:reader_connection).with(
|
53
|
-
ActiveRecord::Base.should_receive(:reader_connection).with(
|
51
|
+
ActiveRecord::Base.should_receive(:writer_connection).with('adapter' => 'writer', 'host' => 'master_host', 'username' => 'user', 'pool_weight' => 1).and_return(master_connection)
|
52
|
+
ActiveRecord::Base.should_receive(:reader_connection).with('adapter' => 'reader', 'host' => 'read_host_1', 'username' => 'user', 'pool_weight' => 1).and_return(read_connection_1)
|
53
|
+
ActiveRecord::Base.should_receive(:reader_connection).with('adapter' => 'reader', 'host' => 'read_host_2', 'username' => 'user', 'pool_weight' => 2).and_return(read_connection_2)
|
54
54
|
|
55
55
|
klass = mock(:class)
|
56
56
|
ActiveRecord::ConnectionAdapters::SeamlessDatabasePoolAdapter.should_receive(:adapter_class).with(master_connection).and_return(klass)
|
@@ -78,303 +78,281 @@ describe "SeamlessDatabasePoolAdapter" do
|
|
78
78
|
@pool_connection = connection_class.new(nil, mock(:logger), @master_connection, [@read_connection_1, @read_connection_2], weights)
|
79
79
|
end
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
context "selecting a connection from the pool" do
|
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
|
89
|
+
end
|
89
90
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
94
|
+
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
it "should select a random read connection" do
|
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
|
101
|
+
end
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
106
|
+
end
|
106
107
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
112
|
+
connection.use_master_connection do
|
113
|
+
connection.random_read_connection.should == @master_connection
|
114
|
+
end
|
115
|
+
connection.random_read_connection.should == @read_connection_1
|
113
116
|
end
|
114
|
-
connection.random_read_connection.should == @read_connection_1
|
115
|
-
end
|
116
117
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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)
|
124
125
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
SeamlessDatabasePool.use_persistent_read_connection do
|
127
|
+
connection.send(:select, 'SQL 1', nil)
|
128
|
+
connection.transaction do
|
129
|
+
connection.send(:select, 'Transaction SQL', nil)
|
130
|
+
end
|
131
|
+
connection.send(:select, 'SQL 2', nil)
|
129
132
|
end
|
130
|
-
connection.send(:select, 'SQL 2', nil)
|
131
133
|
end
|
132
134
|
end
|
133
|
-
|
134
|
-
# Read methods
|
135
|
-
|
136
|
-
it "should proxy select methods to a read connection" do
|
137
|
-
@pool_connection.should_receive(:current_read_connection).and_return(@read_connection_1)
|
138
|
-
@read_connection_1.should_receive(:select).with('SQL').and_return(:retval)
|
139
|
-
@pool_connection.send(:select, 'SQL').should == :retval
|
140
|
-
end
|
141
|
-
|
142
|
-
it "should proxy execute 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(:execute).with('SQL').and_return(:retval)
|
145
|
-
@pool_connection.execute('SQL').should == :retval
|
146
|
-
end
|
147
|
-
|
148
|
-
it "should proxy select_rows 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_rows).with('SQL').and_return(:retval)
|
151
|
-
@pool_connection.select_rows('SQL').should == :retval
|
152
|
-
end
|
153
135
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
136
|
+
context "read connection methods" do
|
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
|
141
|
+
end
|
160
142
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
147
|
+
end
|
165
148
|
|
166
|
-
|
167
|
-
|
168
|
-
|
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
|
153
|
+
end
|
169
154
|
end
|
170
155
|
|
171
|
-
|
156
|
+
context "master connection methods" do
|
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
|
160
|
+
end
|
172
161
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
@pool_connection.active?.should == true
|
178
|
-
end
|
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
|
165
|
+
end
|
179
166
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
@pool_connection.active?.should == false
|
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
|
170
|
+
end
|
185
171
|
end
|
186
172
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
173
|
+
context "fork to all connections" do
|
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
|
179
|
+
end
|
193
180
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
186
|
+
end
|
200
187
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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)
|
193
|
+
end
|
207
194
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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!
|
200
|
+
end
|
212
201
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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!
|
207
|
+
end
|
219
208
|
|
220
|
-
|
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")
|
212
|
+
end
|
221
213
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
@pool_connection.send(:proxy_connection_method, @master_connection, :select_value, :master, *args, &block)
|
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
|
219
|
+
end
|
229
220
|
end
|
221
|
+
|
222
|
+
context "reconnection" do
|
223
|
+
it "should proxy requests to a connection" do
|
224
|
+
args = [:arg1, :arg2]
|
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)
|
230
|
+
end
|
230
231
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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!)
|
236
|
+
now = Time.now
|
237
|
+
lambda{@pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
|
238
|
+
Time.stub!(:now).and_return(now + 31)
|
239
|
+
lambda{@pool_connection.select_value("SQL")}.should raise_error("SQL ERROR")
|
240
|
+
end
|
239
241
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
242
|
+
it "should not try to reconnect live connections" do
|
243
|
+
args = [:arg1, :arg2]
|
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")
|
249
|
+
end
|
248
250
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
251
|
+
it "should not try to reconnect a connection during a retry" do
|
252
|
+
args = [:arg1, :arg2]
|
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")
|
258
|
+
end
|
257
259
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
260
|
+
it "should try to execute a read statement again after a connection error" do
|
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)
|
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
|
269
|
+
end
|
269
270
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
@pool_connection.use_master_connection do
|
276
|
-
lambda{@pool_connection.send(:select, 'SQL')}.should raise_error("Error")
|
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")
|
275
|
+
end
|
277
276
|
end
|
278
|
-
end
|
279
277
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
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")
|
282
|
+
end
|
285
283
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
@pool_connection.send(:select, 'SQL').should == :results
|
296
|
-
end
|
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
|
292
|
+
end
|
297
293
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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)
|
298
|
+
end
|
303
299
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
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)
|
304
|
+
sleep(0.3)
|
305
|
+
@pool_connection.available_read_connections.should include(@read_connection_1)
|
306
|
+
end
|
311
307
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
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)
|
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)
|
316
|
+
end
|
321
317
|
|
322
|
-
|
323
|
-
|
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)
|
324
320
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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
|
+
stack.size.should == 1
|
330
326
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
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
|
+
stack.size.should == 2
|
337
333
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
@pool_connection.suppress_read_connection(@read_connection_2, 30)
|
346
|
-
available = @pool_connection.available_read_connections
|
347
|
-
available.should include(@read_connection_1)
|
348
|
-
available.should include(@read_connection_2)
|
349
|
-
available.should include(@master_connection)
|
350
|
-
stack.size.should == 1
|
351
|
-
end
|
352
|
-
|
353
|
-
it "should not try to suppress a read connection that wasn't available in the read pool" do
|
354
|
-
stack = @pool_connection.instance_variable_get(:@available_read_connections)
|
355
|
-
stack.size.should == 1
|
356
|
-
@pool_connection.suppress_read_connection(@read_connection_1, 30)
|
357
|
-
stack.size.should == 2
|
358
|
-
@pool_connection.suppress_read_connection(@read_connection_1, 30)
|
359
|
-
stack.size.should == 2
|
360
|
-
end
|
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
|
+
stack.size.should == 3
|
361
340
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
end
|
370
|
-
|
371
|
-
after(:all) do
|
372
|
-
SeamlessDatabasePool::Test.drop_tables
|
373
|
-
end
|
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
|
+
stack.size.should == 1
|
347
|
+
end
|
374
348
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
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)
|
351
|
+
stack.size.should == 1
|
352
|
+
@pool_connection.suppress_read_connection(@read_connection_1, 30)
|
353
|
+
stack.size.should == 2
|
354
|
+
@pool_connection.suppress_read_connection(@read_connection_1, 30)
|
355
|
+
stack.size.should == 2
|
356
|
+
end
|
379
357
|
end
|
380
358
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
-
active_record_version = ENV["ACTIVE_RECORD_VERSION"] || [">= 2.2.2"
|
3
|
+
active_record_version = ENV["ACTIVE_RECORD_VERSION"] || [">= 2.2.2"]
|
4
4
|
active_record_version = [active_record_version] unless active_record_version.is_a?(Array)
|
5
5
|
gem 'activerecord', *active_record_version
|
6
6
|
|
7
|
-
require 'spec'
|
8
7
|
require 'active_record'
|
9
8
|
puts "Testing Against ActiveRecord #{ActiveRecord::VERSION::STRING}" if defined?(ActiveRecord::VERSION)
|
10
9
|
|
11
10
|
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'seamless_database_pool'))
|
12
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '
|
11
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_model'))
|
12
|
+
|
13
|
+
$LOAD_PATH << File.expand_path("../test_adapter", __FILE__)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
def self.read_only_connection (config)
|
4
|
+
real_adapter = config.delete("real_adapter")
|
5
|
+
connection = send("#{real_adapter}_connection", config.merge("adapter" => real_adapter))
|
6
|
+
ConnectionAdapters::ReadOnlyAdapter.new(connection)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ConnectionAdapters
|
11
|
+
class ReadOnlyAdapter < AbstractAdapter
|
12
|
+
%w(select_one select_all select_value select_values select select_rows execute tables columns).each do |read_method|
|
13
|
+
class_eval <<-EOS
|
14
|
+
def #{read_method} (*args, &block)
|
15
|
+
raise "Not Connected" unless @connected
|
16
|
+
result = @connection.send(:#{read_method}, *args, &block)
|
17
|
+
def result.read_only?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end
|
22
|
+
EOS
|
23
|
+
|
24
|
+
%w(update insert delete reload create_table drop_table add_index remove_index transaction).each do |write_method|
|
25
|
+
class_eval <<-EOS
|
26
|
+
def #{write_method} (*args, &block)
|
27
|
+
raise NotImplementedError.new("Master method '#{write_method}' called on read only connection")
|
28
|
+
end
|
29
|
+
EOS
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize (connection)
|
34
|
+
@connection = connection
|
35
|
+
@connected = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def reconnect!
|
39
|
+
@connected = true
|
40
|
+
end
|
41
|
+
|
42
|
+
def disconnect!
|
43
|
+
@connected = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def active?
|
47
|
+
@connected
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|