master_slave_adapter_soundcloud 0.1.3 → 0.1.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/.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