master_slave_adapter_tcurdt 0.0.2 → 0.0.3
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.
@@ -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
|