ar_mysql_flexmaster 0.6.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ar_mysql_flexmaster.gemspec +3 -1
- data/bin/master_cut +14 -17
- data/test/ar_flexmaster_test.rb +13 -0
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b32c2b9162fc4959df4858f60552cbfd4fbfdff
|
4
|
+
data.tar.gz: 1e5f07d3984485add95bb95af4b8e690660746c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc8509dfa2ab7a83421f483a68c533e41804519ad93f4e07dd89f98a0b5e4d5f4958faae57f159235c3c4201dc4f542bfd58d6411894b3522e4108124d48f4a8
|
7
|
+
data.tar.gz: 1f4328dec6136634e150ed7fdc47e907fc91a7b463d1ab42a568aee67ec1644cc844fdc7f6ae83c912052a364d90b63313e6913303a9ff799cfe561f9cdf404b
|
data/ar_mysql_flexmaster.gemspec
CHANGED
@@ -12,13 +12,15 @@ 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.
|
15
|
+
gem.version = "1.0.0"
|
16
16
|
|
17
17
|
gem.add_runtime_dependency("mysql2")
|
18
18
|
gem.add_runtime_dependency("activerecord")
|
19
19
|
gem.add_runtime_dependency("activesupport")
|
20
20
|
gem.add_development_dependency("wwtd")
|
21
21
|
gem.add_development_dependency("minitest")
|
22
|
+
gem.add_development_dependency("mocha", "~> 1.1.0")
|
22
23
|
gem.add_development_dependency("bump")
|
24
|
+
gem.add_development_dependency("pry")
|
23
25
|
gem.add_development_dependency("mysql_isolated_server", "~> 0.5")
|
24
26
|
end
|
data/bin/master_cut
CHANGED
@@ -35,8 +35,8 @@ def usage
|
|
35
35
|
end
|
36
36
|
|
37
37
|
$old_master, $new_master, $username = *ARGV
|
38
|
-
unless $old_master && $new_master && $username
|
39
|
-
usage
|
38
|
+
unless $old_master && $new_master && $username
|
39
|
+
usage
|
40
40
|
end
|
41
41
|
|
42
42
|
|
@@ -47,11 +47,11 @@ def open_cx(host)
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def set_rw(cx)
|
50
|
-
cx.query("SET GLOBAL READ_ONLY=0")
|
50
|
+
cx.query("SET GLOBAL READ_ONLY=0")
|
51
51
|
end
|
52
52
|
|
53
53
|
def set_ro(cx)
|
54
|
-
cx.query("SET GLOBAL READ_ONLY=1")
|
54
|
+
cx.query("SET GLOBAL READ_ONLY=1")
|
55
55
|
end
|
56
56
|
|
57
57
|
$swapped_ok = false
|
@@ -85,20 +85,20 @@ def preflight_check
|
|
85
85
|
slave_info = slave_cx.query("show slave status").first
|
86
86
|
fail("no slave configured!") if slave_info.nil?
|
87
87
|
fail("slave is stopped!") unless slave_info['Slave_IO_Running'] == 'Yes' && slave_info['Slave_SQL_Running'] == 'Yes'
|
88
|
-
fail("slave is delayed") if slave_info['Seconds_Behind_Master'].nil? || slave_info['Seconds_Behind_Master'] > 0
|
88
|
+
fail("slave is delayed") if slave_info['Seconds_Behind_Master'].nil? || slave_info['Seconds_Behind_Master'] > 0
|
89
89
|
|
90
90
|
masters_slave_info = cx.query("show slave status").first
|
91
91
|
if $rehome_master && (masters_slave_info.nil? || masters_slave_info['Master_User'] == 'test')
|
92
92
|
fail("I can't rehome the original master -- it has no slave user or password.")
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
master_ip, slave_master_ip = [$old_master, slave_info['Master_Host']].map do |h|
|
96
96
|
h = h.split(':').first
|
97
|
-
Socket.gethostbyname(h)[3].unpack("CCCC")
|
97
|
+
Socket.gethostbyname(h)[3].unpack("CCCC")
|
98
98
|
end
|
99
99
|
|
100
100
|
if master_ip != slave_master_ip
|
101
|
-
fail("slave does not appear to be replicating off master! (master: #{master_ip.join('.')}, slave's master: #{slave_master_ip.join('.')})")
|
101
|
+
fail("slave does not appear to be replicating off master! (master: #{master_ip.join('.')}, slave's master: #{slave_master_ip.join('.')})")
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
@@ -122,24 +122,24 @@ end
|
|
122
122
|
|
123
123
|
def kill_query!(cx, id)
|
124
124
|
begin
|
125
|
-
cx.query("kill #{id}")
|
125
|
+
cx.query("kill #{id}")
|
126
126
|
rescue Mysql2::Error => e
|
127
127
|
raise e unless e.errno == 1094 # unknown thread id error
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
131
|
def swap_thread
|
132
|
-
Thread.new do
|
132
|
+
Thread.new do
|
133
133
|
master = open_cx($old_master)
|
134
134
|
slave = open_cx($new_master)
|
135
135
|
set_ro(master)
|
136
|
-
slave.query("
|
136
|
+
slave.query("STOP SLAVE")
|
137
137
|
new_master_info = slave.query("show master status").first
|
138
138
|
set_rw(slave)
|
139
139
|
$swapped_ok = true
|
140
140
|
puts "Swapped #{$old_master} and #{$new_master}"
|
141
141
|
puts "New master information at time of swap: "
|
142
|
-
pp new_master_info
|
142
|
+
pp new_master_info
|
143
143
|
if $rehome_master
|
144
144
|
rehome_master(new_master_info, $start_slave)
|
145
145
|
end
|
@@ -153,18 +153,15 @@ def rehome_master(info, start_slave)
|
|
153
153
|
port_clause = port ? "master_port = #{port}," : ""
|
154
154
|
cx = open_cx($old_master)
|
155
155
|
cx.query("change master to master_host='#{host}', #{port_clause} master_log_file = '#{info['File']}', master_log_pos=#{info['Position']}")
|
156
|
-
cx.query("
|
156
|
+
cx.query("START SLAVE") if start_slave
|
157
157
|
end
|
158
158
|
|
159
159
|
ask_for_password
|
160
160
|
preflight_check
|
161
161
|
|
162
162
|
threads = []
|
163
|
-
threads << process_kill_thread
|
164
163
|
threads << swap_thread
|
164
|
+
threads << process_kill_thread
|
165
165
|
threads.each(&:join)
|
166
166
|
|
167
167
|
rehome_master
|
168
|
-
|
169
|
-
|
170
|
-
|
data/test/ar_flexmaster_test.rb
CHANGED
@@ -2,6 +2,7 @@ require 'bundler/setup'
|
|
2
2
|
require 'ar_mysql_flexmaster'
|
3
3
|
require 'active_record'
|
4
4
|
require 'minitest/autorun'
|
5
|
+
require 'mocha/mini_test'
|
5
6
|
|
6
7
|
if !defined?(Minitest::Test)
|
7
8
|
Minitest::Test = MiniTest::Unit::TestCase
|
@@ -286,6 +287,18 @@ class TestArFlexmaster < Minitest::Test
|
|
286
287
|
$mysql_slave_2.up!
|
287
288
|
end
|
288
289
|
|
290
|
+
def test_connection_multiple_attempts
|
291
|
+
# We're simulating connection timeout, so mocha's Expectation#times doesn't register the calls
|
292
|
+
attempts = 0
|
293
|
+
null_logger = Logger.new('/dev/null')
|
294
|
+
config = { hosts: ['localhost'], connection_timeout: 0.01, connection_attempts: 5 }
|
295
|
+
|
296
|
+
Mysql2::Client.stubs(:new).with { attempts += 1; sleep 1 }
|
297
|
+
assert_raises(ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter::NoServerAvailableException) do
|
298
|
+
ActiveRecord::ConnectionAdapters::MysqlFlexmasterAdapter.new(null_logger, config)
|
299
|
+
end
|
300
|
+
assert_equal 5, attempts
|
301
|
+
end
|
289
302
|
|
290
303
|
private
|
291
304
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar_mysql_flexmaster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Osheroff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mysql2
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mocha
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.1.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.1.0
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: bump
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: mysql_isolated_server
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
196
|
version: '0'
|
169
197
|
requirements: []
|
170
198
|
rubyforge_project:
|
171
|
-
rubygems_version: 2.
|
199
|
+
rubygems_version: 2.4.5.1
|
172
200
|
signing_key:
|
173
201
|
specification_version: 4
|
174
202
|
summary: select a master at runtime from a list
|