ar_mysql_flexmaster 0.2.1 → 0.2.2
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/ar_mysql_flexmaster.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |gem|
|
|
12
12
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
13
|
gem.name = "ar_mysql_flexmaster"
|
14
14
|
gem.require_paths = ["lib"]
|
15
|
-
gem.version = "0.2.
|
15
|
+
gem.version = "0.2.2"
|
16
16
|
|
17
17
|
gem.add_runtime_dependency("mysql2")
|
18
18
|
gem.add_runtime_dependency("activerecord")
|
@@ -25,6 +25,8 @@ module ActiveRecord
|
|
25
25
|
module ConnectionAdapters
|
26
26
|
class MysqlFlexmasterAdapter < Mysql2Adapter
|
27
27
|
class NoActiveMasterException < Exception; end
|
28
|
+
class TooManyMastersException < Exception; end
|
29
|
+
class NoServerAvailableException < Exception; end
|
28
30
|
|
29
31
|
CHECK_EVERY_N_SELECTS = 10
|
30
32
|
DEFAULT_CONNECT_TIMEOUT = 5
|
@@ -36,8 +38,10 @@ module ActiveRecord
|
|
36
38
|
@is_master = !config[:slave]
|
37
39
|
@tx_hold_timeout = @config[:tx_hold_timeout] || DEFAULT_TX_HOLD_TIMEOUT
|
38
40
|
@connection_timeout = @config[:connection_timeout] || DEFAULT_CONNECT_TIMEOUT
|
41
|
+
|
39
42
|
connection = find_correct_host
|
40
|
-
|
43
|
+
|
44
|
+
raise_no_server_available! unless connection
|
41
45
|
super(connection, logger, [], config)
|
42
46
|
end
|
43
47
|
|
@@ -69,7 +73,26 @@ module ActiveRecord
|
|
69
73
|
raise NoActiveMasterException unless @connection
|
70
74
|
end
|
71
75
|
|
76
|
+
def raise_no_server_available!
|
77
|
+
raise NoServerAvailableException.new(errors_to_message)
|
78
|
+
end
|
79
|
+
|
80
|
+
def collected_errors
|
81
|
+
@collected_errors ||= []
|
82
|
+
end
|
83
|
+
|
84
|
+
def clear_collected_errors!
|
85
|
+
@collected_errors = []
|
86
|
+
end
|
87
|
+
|
88
|
+
def errors_to_message
|
89
|
+
"Errors encountered while trying #{@config[:hosts].inspect}: " +
|
90
|
+
collected_errors.map { |e| "#{e.class.name}: #{e.message}" }.uniq.join(",")
|
91
|
+
end
|
92
|
+
|
72
93
|
def refind_correct_host(tries = nil, sleep_interval = nil)
|
94
|
+
clear_collected_errors!
|
95
|
+
|
73
96
|
tries ||= @tx_hold_timeout.to_f / 0.1
|
74
97
|
sleep_interval ||= 0.1
|
75
98
|
tries.to_i.times do
|
@@ -80,7 +103,7 @@ module ActiveRecord
|
|
80
103
|
end
|
81
104
|
sleep(sleep_interval)
|
82
105
|
end
|
83
|
-
|
106
|
+
raise_no_server_available!
|
84
107
|
end
|
85
108
|
|
86
109
|
def hosts_and_ports
|
@@ -106,6 +129,12 @@ module ActiveRecord
|
|
106
129
|
else
|
107
130
|
# nothing read-write, or too many read-write
|
108
131
|
# (should we manually close the connections?)
|
132
|
+
if correct_cxs.size > 1
|
133
|
+
collected_errors << TooManyMastersException.new("found #{correct_cxs.size} read-write servers")
|
134
|
+
else
|
135
|
+
collected_errors << NoActiveMasterException.new("no read-write servers found")
|
136
|
+
end
|
137
|
+
|
109
138
|
chosen_cx = nil
|
110
139
|
end
|
111
140
|
else
|
@@ -128,8 +157,12 @@ module ActiveRecord
|
|
128
157
|
cx.query_options.merge!(:as => :array)
|
129
158
|
end
|
130
159
|
end
|
131
|
-
rescue Mysql2::Error
|
132
|
-
|
160
|
+
rescue Mysql2::Error => e
|
161
|
+
collected_errors << e
|
162
|
+
nil
|
163
|
+
rescue Timeout::Error => e
|
164
|
+
collected_errors << e
|
165
|
+
nil
|
133
166
|
end
|
134
167
|
end
|
135
168
|
|
data/test/ar_flexmaster_test.rb
CHANGED
@@ -38,13 +38,15 @@ end
|
|
38
38
|
# $mysql_master and $mysql_slave are separate references to the master and slave that we
|
39
39
|
# use to send control-channel commands on
|
40
40
|
|
41
|
+
$original_master_port = $mysql_master.port
|
42
|
+
|
41
43
|
class TestArFlexmaster < Test::Unit::TestCase
|
42
44
|
def setup
|
43
45
|
ActiveRecord::Base.establish_connection("test")
|
44
46
|
|
45
|
-
$mysql_master.set_rw(true)
|
46
|
-
$mysql_slave.set_rw(false)
|
47
|
-
$mysql_slave_2.set_rw(false)
|
47
|
+
$mysql_master.set_rw(true) if $mysql_master
|
48
|
+
$mysql_slave.set_rw(false) if $mysql_slave
|
49
|
+
$mysql_slave_2.set_rw(false) if $mysql_slave_2
|
48
50
|
end
|
49
51
|
|
50
52
|
def test_should_raise_without_a_rw_master
|
@@ -52,9 +54,11 @@ class TestArFlexmaster < Test::Unit::TestCase
|
|
52
54
|
m.set_rw(false)
|
53
55
|
end
|
54
56
|
|
55
|
-
assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::
|
57
|
+
e = assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoServerAvailableException) do
|
56
58
|
ActiveRecord::Base.connection
|
57
59
|
end
|
60
|
+
|
61
|
+
assert e.message =~ /NoActiveMasterException/
|
58
62
|
end
|
59
63
|
|
60
64
|
def test_should_select_the_master_on_boot
|
@@ -66,7 +70,7 @@ class TestArFlexmaster < Test::Unit::TestCase
|
|
66
70
|
|
67
71
|
$mysql_master.set_rw(false)
|
68
72
|
start_time = Time.now.to_i
|
69
|
-
assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::
|
73
|
+
e = assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoServerAvailableException) do
|
70
74
|
User.create(:name => "foo")
|
71
75
|
end
|
72
76
|
end_time = Time.now.to_i
|
@@ -150,7 +154,10 @@ class TestArFlexmaster < Test::Unit::TestCase
|
|
150
154
|
|
151
155
|
def test_yyy_shooting_the_master_in_the_head
|
152
156
|
User.create!
|
153
|
-
|
157
|
+
|
158
|
+
$mysql_master.kill!
|
159
|
+
$mysql_master = nil
|
160
|
+
|
154
161
|
sleep 1
|
155
162
|
$mysql_slave.set_rw(true)
|
156
163
|
User.connection.reconnect!
|
@@ -163,7 +170,10 @@ class TestArFlexmaster < Test::Unit::TestCase
|
|
163
170
|
# note that by the time this test runs, the 'yyy' test has already killed the master
|
164
171
|
def test_zzz_shooting_the_other_slave_in_the_head
|
165
172
|
$mysql_slave.set_rw(true)
|
173
|
+
|
166
174
|
$mysql_slave_2.kill!
|
175
|
+
$mysql_slave_2 = nil
|
176
|
+
|
167
177
|
UserSlave.connection.reconnect!
|
168
178
|
assert port_for_class(UserSlave) == $mysql_slave.port
|
169
179
|
end
|
@@ -177,6 +187,6 @@ class TestArFlexmaster < Test::Unit::TestCase
|
|
177
187
|
|
178
188
|
def main_connection_is_original_master?
|
179
189
|
port = port_for_class(ActiveRecord::Base)
|
180
|
-
port == $
|
190
|
+
port == $original_master_port
|
181
191
|
end
|
182
192
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_mysql_flexmaster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mysql2
|
@@ -140,18 +140,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
140
|
- - ! '>='
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '0'
|
143
|
-
segments:
|
144
|
-
- 0
|
145
|
-
hash: -961261778755012131
|
146
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
144
|
none: false
|
148
145
|
requirements:
|
149
146
|
- - ! '>='
|
150
147
|
- !ruby/object:Gem::Version
|
151
148
|
version: '0'
|
152
|
-
segments:
|
153
|
-
- 0
|
154
|
-
hash: -961261778755012131
|
155
149
|
requirements: []
|
156
150
|
rubyforge_project:
|
157
151
|
rubygems_version: 1.8.24
|