master_slave_adapter_tcurdt 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,9 +15,11 @@ ActiveRecord::Base.class_eval do
15
15
  # ActiveRecord::Base.with_master do
16
16
  # User.count( :conditions => { :login => 'testuser' } )
17
17
  # end
18
- def with_master
19
- ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.with_master do
20
- yield
18
+ def with_master(&block)
19
+ if connection.respond_to? :with_master
20
+ connection.with_master(&block)
21
+ else
22
+ raise "no with_master"
21
23
  end
22
24
  end
23
25
 
@@ -26,9 +28,11 @@ ActiveRecord::Base.class_eval do
26
28
  # ActiveRecord::Base.with_slave do
27
29
  # User.count( :conditions => { :login => 'testuser' } )
28
30
  # end
29
- def with_slave
30
- ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.with_slave do
31
- yield
31
+ def with_slave(&block)
32
+ if connection.respond_to? :with_slave
33
+ connection.with_slave(&block)
34
+ else
35
+ raise "no with_slave"
32
36
  end
33
37
  end
34
38
 
@@ -39,11 +43,25 @@ ActiveRecord::Base.class_eval do
39
43
  # consistency = ActiveRecord::Base.with_consistency(consistency) do
40
44
  # User.count( :conditions => { :login => 'testuser' } )
41
45
  # end
42
- def with_consistency(consistency)
43
- ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.with_consistency(consistency) do
44
- yield
46
+ def with_consistency(clock, &block)
47
+ if connection.respond_to? :with_consistency
48
+ connection.with_consistency(clock, &block)
49
+ else
50
+ raise "no with_consistency"
51
+ end
52
+ end
53
+
54
+ def transaction_with_master(*args, &block)
55
+ if connection.respond_to? :transaction
56
+ connection.transaction do
57
+ transaction_without_master(*args, &block)
58
+ end
59
+ else
60
+ transaction_without_master(*args, &block)
45
61
  end
46
62
  end
63
+ alias_method_chain :transaction, :master
64
+
47
65
 
48
66
  def master_slave_connection( config )
49
67
  config = config.symbolize_keys
@@ -66,7 +84,7 @@ ActiveRecord::Base.class_eval do
66
84
 
67
85
  end
68
86
 
69
- ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.new( config )
87
+ ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.new(config)
70
88
  end
71
89
 
72
90
  def columns_with_master
@@ -74,9 +92,7 @@ ActiveRecord::Base.class_eval do
74
92
  columns_without_master
75
93
  end
76
94
  end
77
-
78
95
  alias_method_chain :columns, :master
79
96
 
80
97
  end
81
-
82
98
  end
@@ -1,13 +1,12 @@
1
1
  module ActiveRecord
2
-
3
2
  module ConnectionAdapters
4
-
5
3
  class MasterSlaveAdapter
6
4
 
7
5
  class Clock
8
6
  include Comparable
9
7
  attr_reader :file, :position
10
8
  def initialize(file, position)
9
+ raise ArgumentError, "file and postion may not be nil" if file.nil? || position.nil?
11
10
  @file, @position = file, position.to_i
12
11
  end
13
12
  def <=>(other)
@@ -19,7 +18,7 @@ module ActiveRecord
19
18
  def self.zero
20
19
  @zero ||= Clock.new('', 0)
21
20
  end
22
- end
21
+ end
23
22
 
24
23
  SELECT_METHODS = [ :select_all, :select_one, :select_rows, :select_value, :select_values ]
25
24
 
@@ -70,12 +69,6 @@ module ActiveRecord
70
69
  end
71
70
  end
72
71
 
73
- def commit_db_transaction()
74
- on_write do
75
- self.master_connection.commit_db_transaction()
76
- end
77
- end
78
-
79
72
  def reconnect!
80
73
  @active = true
81
74
  self.connections.each { |c| c.reconnect! }
@@ -102,6 +95,22 @@ module ActiveRecord
102
95
  connect_to_slave
103
96
  end
104
97
 
98
+ def current_connection=(stack)
99
+ Thread.current[:master_slave_connection] = stack
100
+ end
101
+
102
+ def current_connection
103
+ Thread.current[:master_slave_connection] || []
104
+ end
105
+
106
+ def current_clock=(stack)
107
+ Thread.current[:master_slave_clock] = stack
108
+ end
109
+
110
+ def current_clock
111
+ Thread.current[:master_slave_clock] || []
112
+ end
113
+
105
114
  def connections
106
115
  [ @master_connection, @slave_connection ].compact
107
116
  end
@@ -117,39 +126,42 @@ module ActiveRecord
117
126
  end
118
127
  end
119
128
 
120
- class << self
121
-
122
- def with_master
123
- Thread.current[:master_slave_select_connection] = [ :master ] + (Thread.current[:master_slave_select_connection]||[])
124
- result = yield
125
- Thread.current[:master_slave_select_connection] = Thread.current[:master_slave_select_connection].drop(1)
126
- result
127
- end
128
-
129
- def with_slave
130
- Thread.current[:master_slave_select_connection] = [ :slave ] + (Thread.current[:master_slave_select_connection]||[])
131
- result = yield
132
- Thread.current[:master_slave_select_connection] = Thread.current[:master_slave_select_connection].drop(1)
133
- result
134
- end
135
-
129
+ def with_master
130
+ self.current_connection = [ :master ] + self.current_connection
131
+ result = yield
132
+ self.current_connection = self.current_connection.drop(1)
133
+ result
134
+ end
136
135
 
137
- def with_consistency(clock)
138
- raise ArgumentError, "consistency cannot be nil" if !clock
136
+ def with_slave
137
+ self.current_connection = [ :slave ] + self.current_connection
138
+ result = yield
139
+ self.current_connection = self.current_connection.drop(1)
140
+ result
141
+ end
139
142
 
140
- Thread.current[:master_slave_select_connection] = [ nil ] + (Thread.current[:master_slave_select_connection]||[])
141
- Thread.current[:master_slave_clock] = [ clock || Clock::zero ] + (Thread.current[:master_slave_clock]||[])
143
+ def with_consistency(clock)
144
+ raise ArgumentError, "consistency cannot be nil" if clock.nil?
145
+ self.current_connection = [ nil ] + self.current_connection
146
+ self.current_clock = [ clock ] + self.current_clock
147
+ yield
148
+ result = current_clock[0]
149
+ self.current_clock = self.current_clock.drop(1)
150
+ self.current_connection = self.current_connection.drop(1)
151
+ result
152
+ end
142
153
 
143
- yield
144
- result = Thread.current[:master_slave_clock][0]
154
+ def transaction(*args)
155
+ puts "<transaction"
156
+ yield
157
+ puts "</transaction"
158
+ update_clock
159
+ end
145
160
 
146
- Thread.current[:master_slave_clock] = Thread.current[:master_slave_clock].drop(1)
147
- Thread.current[:master_slave_select_connection] = Thread.current[:master_slave_select_connection].drop(1)
148
- result
149
- end
161
+ class << self
150
162
 
151
163
  def reset!
152
- Thread.current[:master_slave_select_connection] = nil
164
+ Thread.current[:master_slave_connection] = nil
153
165
  Thread.current[:master_slave_clock] = nil
154
166
  end
155
167
 
@@ -162,8 +174,8 @@ module ActiveRecord
162
174
  end
163
175
 
164
176
  def using_master?
165
- if Thread.current[:master_slave_select_connection]
166
- Thread.current[:master_slave_select_connection][0] == :master
177
+ if Thread.current[:master_slave_connection]
178
+ Thread.current[:master_slave_connection][0] == :master
167
179
  else
168
180
  # there is no wrapper so selects go to slave by default
169
181
  false
@@ -175,11 +187,12 @@ module ActiveRecord
175
187
  private
176
188
 
177
189
  def update_clock
190
+ puts " update clock"
178
191
  # update the clock, if there was problem keep using the old one
179
- Thread.current[:master_slave_clock][0] = master_clock || Thread.current[:master_slave_clock][0]
192
+ self.current_clock[0] = master_clock || self.current_clock[0]
180
193
  # it's a write so from now on we use the master connection
181
194
  # as replication is not likely to be that fast
182
- Thread.current[:master_slave_select_connection][0] = :master
195
+ self.current_connection[0] = :master
183
196
  end
184
197
 
185
198
  def on_write
@@ -213,13 +226,14 @@ module ActiveRecord
213
226
  end
214
227
 
215
228
  def select_connection
216
- connection_stack = Thread.current[:master_slave_select_connection] ||= []
217
- clock_stack = Thread.current[:master_slave_clock] ||= []
229
+ connection_stack = self.current_connection
230
+ clock_stack = self.current_clock
218
231
 
219
232
  # pick the right connection
220
233
  if MasterSlaveAdapter.master_forced? || @master_connection.open_transactions > 0
221
234
  connection_stack[0] = :master
222
235
  end
236
+
223
237
  connection_stack[0] ||= connection_for_clock(clock_stack[0])
224
238
 
225
239
  # return the current connection
@@ -231,13 +245,17 @@ module ActiveRecord
231
245
  end
232
246
 
233
247
  def master_clock
234
- if status = connect_to_master.select_one("SHOW MASTER STATUS")
248
+ puts " master clock"
249
+ connection = connect_to_master
250
+ if status = connection.uncached { connection.select_one("SHOW MASTER STATUS") }
235
251
  Clock.new(status['File'], status['Position'])
236
252
  end
237
253
  end
238
254
 
239
255
  def slave_clock
240
- if status = connect_to_slave.select_one("SHOW SLAVE STATUS")
256
+ puts " slave clock"
257
+ connection = connect_to_slave
258
+ if status = connection.uncached { connection.select_one("SHOW SLAVE STATUS") }
241
259
  Clock.new(status['Relay_Master_Log_File'], status['Exec_Master_Log_Pos'])
242
260
  end
243
261
  end
@@ -251,7 +269,5 @@ module ActiveRecord
251
269
  end
252
270
 
253
271
  end
254
-
255
272
  end
256
-
257
273
  end
@@ -1,3 +1,3 @@
1
1
  module MasterSlaveAdapter
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -42,6 +42,13 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
42
42
  @master_connection = ActiveRecord::Base._master
43
43
  @slave_connection = ActiveRecord::Base._slave
44
44
 
45
+ @master_connection.stub!(:uncached) do |block|
46
+ block.call
47
+ end
48
+ @slave_connection.stub!(:uncached) do |block|
49
+ block.call
50
+ end
51
+
45
52
  end
46
53
 
47
54
  after do
@@ -50,7 +57,6 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
50
57
 
51
58
  describe 'with common configuration' do
52
59
 
53
-
54
60
  before do
55
61
 
56
62
  @database_setup = {
@@ -241,7 +247,7 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
241
247
  if pos.instance_of? Fixnum
242
248
  pos = [ pos ]
243
249
  end
244
- values = pos.map { |p| { 'Master_Log_File' => '', 'Exec_Master_Log_Pos' => p } }
250
+ values = pos.map { |p| { 'Relay_Master_Log_File' => '', 'Exec_Master_Log_Pos' => p } }
245
251
  @slave_connection.should_receive('select_one').exactly(pos.length).with('SHOW SLAVE STATUS').and_return(*values)
246
252
  end
247
253
 
@@ -307,9 +313,9 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
307
313
  @master_connection.should_receive(method).with('testing').and_return(true)
308
314
  old_clock = zero
309
315
  new_clock = ActiveRecord::Base.with_consistency(old_clock) do
310
- ActiveRecord::Base.connection.send(method, 'testing')
311
- ActiveRecord::Base.connection.send('update', 'testing')
312
- ActiveRecord::Base.connection.send(method, 'testing')
316
+ ActiveRecord::Base.connection.send(method, 'testing') # slave
317
+ ActiveRecord::Base.connection.send('update', 'testing') # master
318
+ ActiveRecord::Base.connection.send(method, 'testing') # master
313
319
  end
314
320
  new_clock.should be_a(zero.class)
315
321
  new_clock.should > old_clock
@@ -317,6 +323,42 @@ describe ActiveRecord::ConnectionAdapters::MasterSlaveAdapter do
317
323
 
318
324
  end
319
325
 
326
+ it "should update the clock after a transaction" do
327
+ ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.reset!
328
+ slave_should_report_clock(0)
329
+ master_should_report_clock([0, 1, 1, 1, 1])
330
+ @slave_connection.should_receive('select_all').exactly(1).times.with('testing').and_return(true)
331
+ @master_connection.should_receive('update').exactly(3).times.with('testing').and_return(true)
332
+ # @master_connection.should_receive('transaction').and_return(true)
333
+ @master_connection.should_receive('select_all').exactly(5).times.with('testing').and_return(true)
334
+
335
+ old_clock = zero
336
+ new_clock = ActiveRecord::Base.with_consistency(old_clock) do
337
+ puts "slave: select"
338
+ ActiveRecord::Base.connection.send('select_all', 'testing') # slave s=0 m=0
339
+ puts "master: update"
340
+ ActiveRecord::Base.connection.send('update', 'testing') # master s=0 m=1
341
+ puts "master: select"
342
+ ActiveRecord::Base.connection.send('select_all', 'testing') # master s=0 m=1
343
+
344
+ ActiveRecord::Base.transaction do
345
+ puts "master: select"
346
+ ActiveRecord::Base.connection.send('select_all', 'testing') # master s=0 m=1
347
+ puts "master: update"
348
+ ActiveRecord::Base.connection.send('update', 'testing') # master s=0 m=1
349
+ puts "master: select"
350
+ ActiveRecord::Base.connection.send('select_all', 'testing') # master s=0 m=1
351
+ end
352
+
353
+ puts "master: select"
354
+ ActiveRecord::Base.connection.send('select_all', 'testing') # master s=0 m=2
355
+ puts "master: update"
356
+ ActiveRecord::Base.connection.send('update', 'testing') # master s=0 m=3
357
+ puts "master: select"
358
+ ActiveRecord::Base.connection.send('select_all', 'testing') # master s=0 m=3
359
+ end
360
+ end
361
+
320
362
  it "should do the right thing when nested inside with_consistency" do
321
363
  ActiveRecord::ConnectionAdapters::MasterSlaveAdapter.reset!
322
364
  slave_should_report_clock([ 0, 0 ])
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mauricio Linhares
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-30 00:00:00 +02:00
18
+ date: 2011-06-06 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency