master_slave_adapter 1.0.0.beta2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: master_slave_adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta2
5
- prerelease: 6
4
+ version: 1.0.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Mauricio Linhares
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2012-06-20 00:00:00.000000000 Z
18
+ date: 2012-07-24 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activerecord
@@ -25,7 +25,7 @@ dependencies:
25
25
  - - ! '>='
26
26
  - !ruby/object:Gem::Version
27
27
  version: 2.3.9
28
- - - <=
28
+ - - <
29
29
  - !ruby/object:Gem::Version
30
30
  version: '4.0'
31
31
  type: :runtime
@@ -36,7 +36,7 @@ dependencies:
36
36
  - - ! '>='
37
37
  - !ruby/object:Gem::Version
38
38
  version: 2.3.9
39
- - - <=
39
+ - - <
40
40
  - !ruby/object:Gem::Version
41
41
  version: '4.0'
42
42
  - !ruby/object:Gem::Dependency
@@ -72,7 +72,7 @@ dependencies:
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0'
74
74
  description: (MySQL) Replication Aware Master/Slave Database Adapter for ActiveRecord
75
- email: kim@soundcloud.com tcurdt@soundcloud.com ts@soundcloud
75
+ email: tiago@soundcloud.com ts@soundcloud.com
76
76
  executables: []
77
77
  extensions: []
78
78
  extra_rdoc_files: []
@@ -94,17 +94,19 @@ files:
94
94
  - lib/master_slave_adapter.rb
95
95
  - master_slave_adapter.gemspec
96
96
  - spec/all.sh
97
- - spec/circuit_breaker_spec.rb
97
+ - spec/common/circuit_breaker_spec.rb
98
+ - spec/common/master_slave_adapter_spec.rb
99
+ - spec/common/mysql2_master_slave_adapter_spec.rb
100
+ - spec/common/mysql_master_slave_adapter_spec.rb
101
+ - spec/common/support/connection_setup_helper.rb
102
+ - spec/common/support/mysql_consistency_examples.rb
98
103
  - spec/gemfiles/activerecord2.3
99
104
  - spec/gemfiles/activerecord3.0
100
105
  - spec/gemfiles/activerecord3.2
101
- - spec/integration/helpers/mysql_helper.rb
102
- - spec/integration/helpers/shared_mysql_examples.rb
103
106
  - spec/integration/mysql2_master_slave_adapter_spec.rb
104
107
  - spec/integration/mysql_master_slave_adapter_spec.rb
105
- - spec/master_slave_adapter_spec.rb
106
- - spec/mysql2_master_slave_adapter_spec.rb
107
- - spec/mysql_master_slave_adapter_spec.rb
108
+ - spec/integration/support/mysql_setup_helper.rb
109
+ - spec/integration/support/shared_mysql_examples.rb
108
110
  homepage: http://github.com/soundcloud/master_slave_adapter
109
111
  licenses: []
110
112
  post_install_message:
@@ -131,14 +133,16 @@ specification_version: 3
131
133
  summary: Replication Aware Master/Slave Database Adapter for ActiveRecord
132
134
  test_files:
133
135
  - spec/all.sh
134
- - spec/circuit_breaker_spec.rb
136
+ - spec/common/circuit_breaker_spec.rb
137
+ - spec/common/master_slave_adapter_spec.rb
138
+ - spec/common/mysql2_master_slave_adapter_spec.rb
139
+ - spec/common/mysql_master_slave_adapter_spec.rb
140
+ - spec/common/support/connection_setup_helper.rb
141
+ - spec/common/support/mysql_consistency_examples.rb
135
142
  - spec/gemfiles/activerecord2.3
136
143
  - spec/gemfiles/activerecord3.0
137
144
  - spec/gemfiles/activerecord3.2
138
- - spec/integration/helpers/mysql_helper.rb
139
- - spec/integration/helpers/shared_mysql_examples.rb
140
145
  - spec/integration/mysql2_master_slave_adapter_spec.rb
141
146
  - spec/integration/mysql_master_slave_adapter_spec.rb
142
- - spec/master_slave_adapter_spec.rb
143
- - spec/mysql2_master_slave_adapter_spec.rb
144
- - spec/mysql_master_slave_adapter_spec.rb
147
+ - spec/integration/support/mysql_setup_helper.rb
148
+ - spec/integration/support/shared_mysql_examples.rb
@@ -1,372 +0,0 @@
1
- $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
- require 'rspec'
4
- require 'logger'
5
- require 'active_record/connection_adapters/mysql2_master_slave_adapter'
6
-
7
- module ActiveRecord
8
- class Base
9
- cattr_accessor :master_mock, :slave_mock
10
- def self.mysql2_connection(config)
11
- config[:database] == 'slave' ? slave_mock : master_mock
12
- end
13
- end
14
- end
15
-
16
- describe ActiveRecord::ConnectionAdapters::Mysql2MasterSlaveAdapter do
17
- let(:database_setup) do
18
- {
19
- :adapter => 'master_slave',
20
- :username => 'root',
21
- :database => 'slave',
22
- :connection_adapter => 'mysql2',
23
- :master => { :username => 'root', :database => 'master' },
24
- :slaves => [{ :database => 'slave' }],
25
- }
26
- end
27
-
28
- let(:mocked_methods) do
29
- {
30
- :reconnect! => true,
31
- :disconnect! => true,
32
- :active? => true,
33
- }
34
- end
35
-
36
- let!(:master_connection) do
37
- mock(
38
- 'master connection',
39
- mocked_methods.merge(:open_transactions => 0)
40
- ).tap do |conn|
41
- conn.stub!(:uncached).and_yield
42
- ActiveRecord::Base.master_mock = conn
43
- end
44
- end
45
-
46
- let!(:slave_connection) do
47
- mock('slave connection', mocked_methods).tap do |conn|
48
- conn.stub!(:uncached).and_yield
49
- ActiveRecord::Base.slave_mock = conn
50
- end
51
- end
52
-
53
- def adapter_connection
54
- ActiveRecord::Base.connection
55
- end
56
-
57
- SelectMethods = [ :select_all, :select_one, :select_rows, :select_value, :select_values ] unless defined?(SelectMethods)
58
- Clock = ActiveRecord::ConnectionAdapters::MasterSlaveAdapter::Clock unless defined?(Clock)
59
-
60
- before do
61
- ActiveRecord::Base.establish_connection(database_setup)
62
- end
63
-
64
- after do
65
- ActiveRecord::Base.connection_handler.clear_all_connections!
66
- end
67
-
68
- describe 'consistency' do
69
- def zero
70
- Clock.zero
71
- end
72
-
73
- def master_position(pos)
74
- Clock.new('', pos)
75
- end
76
-
77
- def select_method
78
- :select_one
79
- end
80
-
81
- def should_report_clock(pos, connection, log_file, log_pos, sql)
82
- pos = Array(pos)
83
- values = pos.map { |p| { log_file => '', log_pos => p } }
84
-
85
- connection.
86
- should_receive(select_method).exactly(pos.length).times.
87
- with(sql).
88
- and_return(*values)
89
- end
90
-
91
- def slave_should_report_clock(pos)
92
- should_report_clock(pos, slave_connection, 'Relay_Master_Log_File', 'Exec_Master_Log_Pos', 'SHOW SLAVE STATUS')
93
- end
94
-
95
- def master_should_report_clock(pos)
96
- should_report_clock(pos, master_connection, 'File', 'Position', 'SHOW MASTER STATUS')
97
- end
98
-
99
- SelectMethods.each do |method|
100
- it "should send the method '#{method}' to the slave if nil is given" do
101
- slave_should_report_clock(0)
102
- slave_connection.should_receive(method).with('testing').and_return(true)
103
- new_clock = ActiveRecord::Base.with_consistency(nil) do
104
- adapter_connection.send(method, 'testing')
105
- end
106
- new_clock.should be_a(Clock)
107
- new_clock.should equal(zero)
108
- end
109
-
110
- it "should send the method '#{method}' to the slave if clock.zero is given" do
111
- slave_should_report_clock(0)
112
- slave_connection.should_receive(method).with('testing').and_return(true)
113
- old_clock = zero
114
- new_clock = ActiveRecord::Base.with_consistency(old_clock) do
115
- adapter_connection.send(method, 'testing')
116
- end
117
- new_clock.should be_a(Clock)
118
- new_clock.should equal(old_clock)
119
- end
120
-
121
- it "should send the method '#{method}' to the master if slave hasn't cought up to required clock yet" do
122
- slave_should_report_clock(0)
123
- master_connection.should_receive(method).with('testing').and_return(true)
124
- old_clock = master_position(1)
125
- new_clock = ActiveRecord::Base.with_consistency(old_clock) do
126
- adapter_connection.send(method, 'testing' )
127
- end
128
- new_clock.should be_a(Clock)
129
- new_clock.should equal(old_clock)
130
- end
131
-
132
- it "should send the method '#{method}' to the master connection if there are open transactions" do
133
- master_connection.stub!(:open_transactions).and_return(1)
134
- master_connection.should_receive(method).with('testing').and_return(true)
135
- old_clock = zero
136
- new_clock = ActiveRecord::Base.with_consistency(old_clock) do
137
- adapter_connection.send(method, 'testing')
138
- end
139
- new_clock.should be_a(Clock)
140
- new_clock.should equal(zero)
141
- end
142
-
143
- it "should send the method '#{method}' to the master after a write operation" do
144
- slave_should_report_clock(0)
145
- master_should_report_clock(2)
146
- slave_connection.should_receive(method).with('testing').and_return(true)
147
- master_connection.should_receive(:update).with('testing').and_return(true)
148
- master_connection.should_receive(method).with('testing').and_return(true)
149
- old_clock = zero
150
- new_clock = ActiveRecord::Base.with_consistency(old_clock) do
151
- adapter_connection.send(method, 'testing') # slave
152
- adapter_connection.send(:update, 'testing') # master
153
- adapter_connection.send(method, 'testing') # master
154
- end
155
- new_clock.should be_a(Clock)
156
- new_clock.should > old_clock
157
- end
158
- end
159
-
160
- it "should update the clock after a transaction" do
161
- slave_should_report_clock(0)
162
- master_should_report_clock([0, 1, 1])
163
-
164
- slave_connection.
165
- should_receive(:select_all).exactly(1).times.with('testing').
166
- and_return(true)
167
-
168
- master_connection.
169
- should_receive(:update).exactly(3).times.with('testing').
170
- and_return(true)
171
- master_connection.
172
- should_receive(:select_all).exactly(5).times.with('testing').
173
- and_return(true)
174
- %w(begin_db_transaction
175
- commit_db_transaction
176
- increment_open_transactions
177
- decrement_open_transactions
178
- outside_transaction?).each do |txstmt|
179
- master_connection.should_receive(txstmt).exactly(1).times
180
- end
181
-
182
- master_connection.
183
- should_receive('open_transactions').exactly(13).times.
184
- and_return(
185
- # adapter: with_consistency, select_all, update, select_all
186
- 0, 0, 0, 0,
187
- # connection: transaction
188
- 0,
189
- # adapter: select_all, update, select_all, commit_db_transaction
190
- 1, 1, 1, 0,
191
- # connection: transaction (ensure)
192
- 0,
193
- # adapter: select_all, update, select_all
194
- 0, 0, 0
195
- )
196
-
197
- old_clock = zero
198
- new_clock = ActiveRecord::Base.with_consistency(old_clock) do
199
- adapter_connection.send(:select_all, 'testing') # slave s=0 m=0
200
- adapter_connection.send(:update, 'testing') # master s=0 m=1
201
- adapter_connection.send(:select_all, 'testing') # master s=0 m=1
202
-
203
- ActiveRecord::Base.transaction do
204
- adapter_connection.send(:select_all, 'testing') # master s=0 m=1
205
- adapter_connection.send(:update, 'testing') # master s=0 m=1
206
- adapter_connection.send(:select_all, 'testing') # master s=0 m=1
207
- end
208
-
209
- adapter_connection.send(:select_all, 'testing') # master s=0 m=2
210
- adapter_connection.send(:update, 'testing') # master s=0 m=3
211
- adapter_connection.send(:select_all, 'testing') # master s=0 m=3
212
- end
213
-
214
- new_clock.should > old_clock
215
- end
216
-
217
- context "with nested with_consistency" do
218
- it "should return the same clock if not writing and no lag" do
219
- slave_should_report_clock(0)
220
- slave_connection.
221
- should_receive(:select_one).exactly(3).times.with('testing').
222
- and_return(true)
223
-
224
- old_clock = zero
225
- new_clock = ActiveRecord::Base.with_consistency(old_clock) do
226
- adapter_connection.send(:select_one, 'testing')
227
- ActiveRecord::Base.with_consistency(old_clock) do
228
- adapter_connection.send(:select_one, 'testing')
229
- end
230
- adapter_connection.send(:select_one, 'testing')
231
- end
232
- new_clock.should equal(old_clock)
233
- end
234
-
235
- it "requesting a newer clock should return a new clock" do
236
- adapter_connection.
237
- should_receive('slave_consistent?').exactly(2).times.
238
- and_return(true, false)
239
- slave_connection.
240
- should_receive(:select_all).exactly(2).times.with('testing').
241
- and_return(true)
242
- master_connection.
243
- should_receive(:select_all).exactly(1).times.with('testing').
244
- and_return(true)
245
-
246
- start_clock = zero
247
- inner_clock = zero
248
- outer_clock = ActiveRecord::Base.with_consistency(start_clock) do
249
- adapter_connection.send(:select_all, 'testing') # slave
250
- inner_clock = ActiveRecord::Base.with_consistency(master_position(1)) do
251
- adapter_connection.send(:select_all, 'testing') # master
252
- end
253
- adapter_connection.send(:select_all, 'testing') # slave
254
- end
255
-
256
- start_clock.should equal(outer_clock)
257
- inner_clock.should > start_clock
258
- end
259
- end
260
-
261
- it "should do the right thing when nested inside with_master" do
262
- slave_should_report_clock(0)
263
- slave_connection.should_receive(:select_all).exactly(1).times.with('testing').and_return(true)
264
- master_connection.should_receive(:select_all).exactly(2).times.with('testing').and_return(true)
265
- ActiveRecord::Base.with_master do
266
- adapter_connection.send(:select_all, 'testing') # master
267
- ActiveRecord::Base.with_consistency(zero) do
268
- adapter_connection.send(:select_all, 'testing') # slave
269
- end
270
- adapter_connection.send(:select_all, 'testing') # master
271
- end
272
- end
273
-
274
- it "should do the right thing when nested inside with_slave" do
275
- slave_should_report_clock(0)
276
- slave_connection.should_receive(:select_all).exactly(3).times.with('testing').and_return(true)
277
- ActiveRecord::Base.with_slave do
278
- adapter_connection.send(:select_all, 'testing') # slave
279
- ActiveRecord::Base.with_consistency(zero) do
280
- adapter_connection.send(:select_all, 'testing') # slave
281
- end
282
- adapter_connection.send(:select_all, 'testing') # slave
283
- end
284
- end
285
-
286
- it "should do the right thing when wrapping with_master" do
287
- slave_should_report_clock(0)
288
- slave_connection.should_receive(:select_all).exactly(2).times.with('testing').and_return(true)
289
- master_connection.should_receive(:select_all).exactly(1).times.with('testing').and_return(true)
290
- ActiveRecord::Base.with_consistency(zero) do
291
- adapter_connection.send(:select_all, 'testing') # slave
292
- ActiveRecord::Base.with_master do
293
- adapter_connection.send(:select_all, 'testing') # master
294
- end
295
- adapter_connection.send(:select_all, 'testing') # slave
296
- end
297
- end
298
-
299
- it "should do the right thing when wrapping with_slave" do
300
- slave_should_report_clock(0)
301
- slave_connection.should_receive(:select_all).exactly(1).times.with('testing').and_return(true)
302
- master_connection.should_receive(:select_all).exactly(2).times.with('testing').and_return(true)
303
- ActiveRecord::Base.with_consistency(master_position(1)) do
304
- adapter_connection.send(:select_all, 'testing') # master
305
- ActiveRecord::Base.with_slave do
306
- adapter_connection.send(:select_all, 'testing') # slave
307
- end
308
- adapter_connection.send(:select_all, 'testing') # master
309
- end
310
- end
311
-
312
- it "should accept clock as string" do
313
- slave_should_report_clock(0)
314
- slave_connection.should_receive(:select_all).with('testing')
315
-
316
- ActiveRecord::Base.with_consistency("@0") do
317
- adapter_connection.send(:select_all, 'testing')
318
- end
319
- end
320
- end # /with_consistency
321
-
322
- describe "connection error detection" do
323
- {
324
- 2002 => "query: not connected",
325
- 2003 => "Can't connect to MySQL server on 'localhost' (3306)",
326
- 2006 => "MySQL server has gone away",
327
- 2013 => "Lost connection to MySQL server during query",
328
- }.each do |errno, description|
329
- it "raises MasterUnavailable for '#{description}' during query execution" do
330
- master_connection.stub_chain(:raw_connection, :errno).and_return(errno)
331
- master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql2::Error: #{description}: INSERT 42"))
332
-
333
- expect do
334
- adapter_connection.insert("INSERT 42")
335
- end.to raise_error(ActiveRecord::MasterUnavailable)
336
- end
337
-
338
- it "doesn't raise anything for '#{description}' during connection" do
339
- error = Mysql2::Error.new(description)
340
- error.stub(:errno).and_return(errno)
341
- ActiveRecord::Base.should_receive(:mysql2_connection).twice do |config|
342
- if config[:name] == :master
343
- raise error
344
- else
345
- slave_connection
346
- end
347
- end
348
-
349
- expect do
350
- ActiveRecord::Base.connection_handler.clear_all_connections!
351
- ActiveRecord::Base.connection
352
- end.to_not raise_error
353
- end
354
- end
355
-
356
- it "raises MasterUnavailable for 'closed MySQL connection' during query execution" do
357
- master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql2::Error: closed MySQL connection: INSERT 42"))
358
-
359
- expect do
360
- adapter_connection.insert("INSERT 42")
361
- end.to raise_error(ActiveRecord::MasterUnavailable)
362
- end
363
-
364
- it "raises StatementInvalid for other errors" do
365
- master_connection.should_receive(:insert).and_raise(ActiveRecord::StatementInvalid.new("Mysql2::Error: Query execution was interrupted: INSERT 42"))
366
-
367
- expect do
368
- adapter_connection.insert("INSERT 42")
369
- end.to raise_error(ActiveRecord::StatementInvalid)
370
- end
371
- end
372
- end