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
|
-
|
20
|
-
|
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
|
-
|
31
|
-
|
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(
|
43
|
-
|
44
|
-
|
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(
|
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
|
-
|
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
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
138
|
-
|
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
|
-
|
141
|
-
|
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
|
-
|
144
|
-
|
154
|
+
def transaction(*args)
|
155
|
+
puts "<transaction"
|
156
|
+
yield
|
157
|
+
puts "</transaction"
|
158
|
+
update_clock
|
159
|
+
end
|
145
160
|
|
146
|
-
|
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[:
|
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[:
|
166
|
-
Thread.current[:
|
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
|
-
|
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
|
-
|
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 =
|
217
|
-
clock_stack =
|
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
|
-
|
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
|
-
|
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
|
data/specs/specs.rb
CHANGED
@@ -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| { '
|
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
|
-
-
|
9
|
-
version: 0.0.
|
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-
|
18
|
+
date: 2011-06-06 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|