master_slave_adapter_soundcloud 0.1.3 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  tags
2
2
  test/*
3
3
  pkg/*
4
+ .rvmrc
5
+ Gemfile.lock
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.6
@@ -47,8 +47,9 @@ module ActiveRecord
47
47
  def massage(config)
48
48
  config = config.symbolize_keys
49
49
  skip = [ :adapter, :connection_adapter, :master, :slaves ]
50
- defaults = config.reject { |k,_| skip.include?(k) }
51
- .merge(:adapter => config.fetch(:connection_adapter))
50
+ defaults = config.
51
+ reject { |k,_| skip.include?(k) }.
52
+ merge(:adapter => config.fetch(:connection_adapter))
52
53
  ([config.fetch(:master)] + config.fetch(:slaves, [])).map do |cfg|
53
54
  cfg.symbolize_keys!.reverse_merge!(defaults)
54
55
  end
@@ -142,7 +143,7 @@ module ActiveRecord
142
143
  # try random slave, else fall back to master
143
144
  slave = slave_connection!
144
145
  conn =
145
- if !open_transaction? && slave_clock(slave).try(:>=, clock)
146
+ if !open_transaction? && slave_consistent?(slave, clock)
146
147
  [ slave, :slave ]
147
148
  else
148
149
  [ master_connection, :master ]
@@ -264,8 +265,8 @@ module ActiveRecord
264
265
  :delete_sql,
265
266
  :sanitize_limit,
266
267
  :to => :master_connection
267
- delegate *ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods,
268
- :to => :master_connection
268
+ delegate *(ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods + [{
269
+ :to => :master_connection }])
269
270
  # no clear interface contract:
270
271
  delegate :tables, # commented in SchemaStatements
271
272
  :truncate_table, # monkeypatching database_cleaner gem
@@ -298,8 +299,10 @@ module ActiveRecord
298
299
  private :connection_for_read
299
300
 
300
301
  # === doesn't really matter, but must be handled by underlying adapter
301
- delegate *ActiveRecord::ConnectionAdapters::Quoting.instance_methods,
302
- :to => :current_connection
302
+ delegate *(ActiveRecord::ConnectionAdapters::Quoting.instance_methods + [{
303
+ :to => :current_connection }])
304
+ # issue #4: current_database is not supported by all adapters, though
305
+ delegate :current_database, :to => :current_connection
303
306
 
304
307
  # UTIL ==================================================================
305
308
 
@@ -340,13 +343,18 @@ module ActiveRecord
340
343
  end
341
344
  end
342
345
 
343
- def slave_clock(connection = nil)
344
- conn ||= slave_connection!
346
+ def slave_clock(conn)
345
347
  if status = conn.uncached { conn.select_one("SHOW SLAVE STATUS") }
346
- Clock.new(status['Relay_Master_Log_File'], status['Exec_Master_Log_Pos'])
348
+ Clock.new(status['Relay_Master_Log_File'], status['Exec_Master_Log_Pos']).tap do |c|
349
+ set_last_seen_slave_clock(conn, c)
350
+ end
347
351
  end
348
352
  end
349
353
 
354
+ def slave_consistent?(conn, clock)
355
+ (get_last_seen_slave_clock(conn) || slave_clock(conn)).try(:>=, clock)
356
+ end
357
+
350
358
  protected
351
359
 
352
360
  def on_write
@@ -406,6 +414,17 @@ module ActiveRecord
406
414
  def on_rollback_callbacks
407
415
  Thread.current[:on_rollback_callbacks] ||= []
408
416
  end
417
+
418
+ def get_last_seen_slave_clock(conn)
419
+ conn.instance_variable_get(:@last_seen_slave_clock)
420
+ end
421
+
422
+ def set_last_seen_slave_clock(conn, clock)
423
+ last_seen = get_last_seen_slave_clock(conn)
424
+ if last_seen.nil? || last_seen < clock
425
+ conn.instance_variable_set(:@last_seen_slave_clock, clock)
426
+ end
427
+ end
409
428
  end
410
429
  end
411
430
  end
@@ -4,7 +4,7 @@ $:.push File.expand_path("../lib", __FILE__)
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'master_slave_adapter_soundcloud'
6
6
  s.version = File.read('VERSION').to_s
7
- s.date = '2011-06-21'
7
+ s.date = '2011-08-23'
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = [ 'Mauricio Linhares', 'Torsten Curdt', 'Kim Altintop', 'Omid Aladini', 'SoundCloud' ]
10
10
  s.email = %q{kim@soundcloud.com tcurdt@soundcloud.com omid@soundcloud.com}
@@ -211,17 +211,17 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
211
211
  def slave_should_report_clock(pos)
212
212
  pos = Array(pos)
213
213
  values = pos.map { |p| { 'Relay_Master_Log_File' => '', 'Exec_Master_Log_Pos' => p } }
214
- slave_connection
215
- .should_receive('select_one').exactly(pos.length).with('SHOW SLAVE STATUS')
216
- .and_return(*values)
214
+ slave_connection.
215
+ should_receive('select_one').exactly(pos.length).with('SHOW SLAVE STATUS').
216
+ and_return(*values)
217
217
  end
218
218
 
219
219
  def master_should_report_clock(pos)
220
220
  pos = Array(pos)
221
221
  values = pos.map { |p| { 'File' => '', 'Position' => p } }
222
- master_connection
223
- .should_receive('select_one').exactly(pos.length).with('SHOW MASTER STATUS')
224
- .and_return(*values)
222
+ master_connection.
223
+ should_receive('select_one').exactly(pos.length).with('SHOW MASTER STATUS').
224
+ and_return(*values)
225
225
  end
226
226
 
227
227
  SelectMethods.each do |method|
@@ -287,26 +287,27 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
287
287
  slave_should_report_clock(0)
288
288
  master_should_report_clock([0, 1, 1])
289
289
 
290
- slave_connection
291
- .should_receive('select_all').exactly(1).times.with('testing')
292
- .and_return(true)
290
+ slave_connection.
291
+ should_receive('select_all').exactly(1).times.with('testing').
292
+ and_return(true)
293
293
 
294
- master_connection
295
- .should_receive('update').exactly(3).times.with('testing')
296
- .and_return(true)
297
- master_connection
298
- .should_receive('select_all').exactly(5).times.with('testing')
299
- .and_return(true)
294
+ master_connection.
295
+ should_receive('update').exactly(3).times.with('testing').
296
+ and_return(true)
297
+ master_connection.
298
+ should_receive('select_all').exactly(5).times.with('testing').
299
+ and_return(true)
300
300
  %w(begin_db_transaction
301
301
  commit_db_transaction
302
302
  increment_open_transactions
303
- decrement_open_transactions).each do |txstmt|
303
+ decrement_open_transactions
304
+ outside_transaction?).each do |txstmt|
304
305
  master_connection.should_receive(txstmt).exactly(1).times
305
306
  end
306
307
 
307
- master_connection
308
- .should_receive('open_transactions').exactly(13).times
309
- .and_return(
308
+ master_connection.
309
+ should_receive('open_transactions').exactly(13).times.
310
+ and_return(
310
311
  # adapter: with_consistency, select_all, update, select_all
311
312
  0, 0, 0, 0,
312
313
  # connection: transaction
@@ -341,10 +342,10 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
341
342
 
342
343
  context "with nested with_consistency" do
343
344
  it "should return the same clock if not writing and no lag" do
344
- slave_should_report_clock([ 0, 0 ])
345
- slave_connection
346
- .should_receive('select_one').exactly(3).times.with('testing')
347
- .and_return(true)
345
+ slave_should_report_clock(0) # note: tests memoizing slave clock
346
+ slave_connection.
347
+ should_receive('select_one').exactly(3).times.with('testing').
348
+ and_return(true)
348
349
 
349
350
  old_clock = zero
350
351
  new_clock = ActiveRecord::Base.with_consistency(old_clock) do
@@ -358,13 +359,15 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
358
359
  end
359
360
 
360
361
  it "requesting a newer clock should return a new clock" do
361
- slave_should_report_clock([0,0])
362
- slave_connection
363
- .should_receive('select_all').exactly(2).times.with('testing')
364
- .and_return(true)
365
- master_connection
366
- .should_receive('select_all').exactly(1).times.with('testing')
367
- .and_return(true)
362
+ adapter_connection.
363
+ should_receive('slave_consistent?').exactly(2).times.
364
+ and_return(true, false)
365
+ slave_connection.
366
+ should_receive('select_all').exactly(2).times.with('testing').
367
+ and_return(true)
368
+ master_connection.
369
+ should_receive('select_all').exactly(1).times.with('testing').
370
+ and_return(true)
368
371
 
369
372
  start_clock = zero
370
373
  inner_clock = zero
@@ -439,23 +442,24 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
439
442
  end
440
443
 
441
444
  def run_tx
442
- adapter_connection
443
- .should_receive('master_clock')
444
- .and_return(Clock.new('', 1))
445
+ adapter_connection.
446
+ should_receive('master_clock').
447
+ and_return(Clock.new('', 1))
445
448
  %w(begin_db_transaction
446
449
  commit_db_transaction
447
450
  increment_open_transactions
448
- decrement_open_transactions).each do |txstmt|
449
- master_connection
450
- .should_receive(txstmt).exactly(1).times
451
+ decrement_open_transactions
452
+ outside_transaction?).each do |txstmt|
453
+ master_connection.
454
+ should_receive(txstmt).exactly(1).times
451
455
  end
452
- master_connection
453
- .should_receive('open_transactions').exactly(4).times
454
- .and_return(0, 1, 0, 0)
456
+ master_connection.
457
+ should_receive('open_transactions').exactly(4).times.
458
+ and_return(0, 1, 0, 0)
455
459
 
456
- master_connection
457
- .should_receive('update').with('testing')
458
- .and_return(true)
460
+ master_connection.
461
+ should_receive('update').with('testing').
462
+ and_return(true)
459
463
 
460
464
  ActiveRecord::Base.transaction do
461
465
  adapter_connection.send('update', 'testing')
@@ -467,15 +471,17 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
467
471
  rollback_db_transaction
468
472
  increment_open_transactions
469
473
  decrement_open_transactions).each do |txstmt|
470
- master_connection
471
- .should_receive(txstmt).exactly(1).times
472
- end
473
- master_connection
474
- .should_receive('open_transactions').exactly(3).times
475
- .and_return(0, 1, 0)
476
- master_connection
477
- .should_receive('update').with('testing')
478
- .and_return(true)
474
+ master_connection.
475
+ should_receive(txstmt).exactly(1).times
476
+ end
477
+ master_connection.
478
+ should_receive('outside_transaction?').exactly(2).times
479
+ master_connection.
480
+ should_receive('open_transactions').exactly(3).times.
481
+ and_return(0, 1, 0)
482
+ master_connection.
483
+ should_receive('update').with('testing').
484
+ and_return(true)
479
485
 
480
486
  ActiveRecord::Base.transaction do
481
487
  adapter_connection.send('update', 'testing')
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: master_slave_adapter_soundcloud
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 3
9
- version: 0.1.3
4
+ prerelease:
5
+ version: 0.1.6
10
6
  platform: ruby
11
7
  authors:
12
8
  - Mauricio Linhares
@@ -18,7 +14,7 @@ autorequire:
18
14
  bindir: bin
19
15
  cert_chain: []
20
16
 
21
- date: 2011-06-21 00:00:00 +02:00
17
+ date: 2011-08-23 00:00:00 +02:00
22
18
  default_executable:
23
19
  dependencies:
24
20
  - !ruby/object:Gem::Dependency
@@ -29,8 +25,6 @@ dependencies:
29
25
  requirements:
30
26
  - - ">="
31
27
  - !ruby/object:Gem::Version
32
- segments:
33
- - 0
34
28
  version: "0"
35
29
  type: :development
36
30
  version_requirements: *id001
@@ -42,10 +36,6 @@ dependencies:
42
36
  requirements:
43
37
  - - "="
44
38
  - !ruby/object:Gem::Version
45
- segments:
46
- - 2
47
- - 3
48
- - 9
49
39
  version: 2.3.9
50
40
  type: :runtime
51
41
  version_requirements: *id002
@@ -82,25 +72,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
82
72
  requirements:
83
73
  - - ">="
84
74
  - !ruby/object:Gem::Version
85
- segments:
86
- - 1
87
- - 9
88
- - 2
89
75
  version: 1.9.2
90
76
  required_rubygems_version: !ruby/object:Gem::Requirement
91
77
  none: false
92
78
  requirements:
93
79
  - - ">="
94
80
  - !ruby/object:Gem::Version
95
- segments:
96
- - 1
97
- - 3
98
- - 7
99
81
  version: 1.3.7
100
82
  requirements: []
101
83
 
102
84
  rubyforge_project:
103
- rubygems_version: 1.3.7
85
+ rubygems_version: 1.5.0
104
86
  signing_key:
105
87
  specification_version: 3
106
88
  summary: Replication Aware Master/Slave Database Adapter for Rails/ActiveRecord