theworkinggroup-mysql-replication-helper 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
- :minor: 1
3
+ :minor: 2
4
4
  :patch: 0
@@ -1,6 +1,10 @@
1
+ require 'rubygems'
2
+ require 'mysql'
3
+
1
4
  module MysqlReplicationHelper
2
5
  # == Autoloads ============================================================
3
6
 
7
+ autoload(:Agent, 'mysql_replication_helper/agent')
4
8
  autoload(:ErrorHandler, 'mysql_replication_helper/error_handler')
5
9
  autoload(:Daemon, 'mysql_replication_helper/daemon')
6
10
  end
@@ -0,0 +1,51 @@
1
+ module MysqlReplicationHelper
2
+ class Agent
3
+ autoload(:Master, 'mysql_replication_helper/agent/master')
4
+ autoload(:Slave, 'mysql_replication_helper/agent/slave')
5
+
6
+ DEFAULT_OPTIONS = {
7
+ :host => 'localhost',
8
+ :user => 'root',
9
+ :master_socket => '/local/db/mysql.sock',
10
+ :slave_socket => '/ebs/db/mysql.sock'
11
+ }
12
+
13
+ def initialize(options)
14
+ @options = with_default_options(options)
15
+ end
16
+
17
+ def connection
18
+ @connection ||=
19
+ Mysql.real_connect(
20
+ @options[:host],
21
+ user_name,
22
+ @options[:password],
23
+ @options[:db],
24
+ @options[:port],
25
+ socket_name
26
+ )
27
+ end
28
+
29
+ def user_name
30
+ @options[:user]
31
+ end
32
+
33
+ def socket_name
34
+ @options[:socket]
35
+ end
36
+
37
+ def with_default_options(options)
38
+ DEFAULT_OPTIONS.merge(options)
39
+ end
40
+
41
+ def execute(statement)
42
+ STDERR.puts(statement)
43
+ connection.real_query(statement)
44
+ end
45
+
46
+ def query(statement)
47
+ STDERR.puts(statement)
48
+ connection.query(statement)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ module MysqlReplicationHelper
2
+ class Agent
3
+ class Master < Agent
4
+ def poll!
5
+ # Nothing yet
6
+ end
7
+
8
+ def master_status
9
+ row = query("SHOW MASTER STATUS").fetch_row
10
+
11
+ return unless (row)
12
+
13
+ {
14
+ :master_log_file => row[0],
15
+ :master_log_position => row[1].to_i
16
+ }
17
+ end
18
+
19
+ def user_name
20
+ @options[:master_user] or super
21
+ end
22
+
23
+ def socket_name
24
+ @options[:master_socket] or super
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,68 @@
1
+ module MysqlReplicationHelper
2
+ class Agent
3
+ class Slave < Agent
4
+ include MysqlReplicationHelper::ErrorHandler
5
+
6
+ def poll!
7
+ if (configured?)
8
+ if (error_message = slave_error)
9
+ if (statements = sql_to_recover_from(error_message))
10
+ statements.each do |sql|
11
+ connection.real_query(sql)
12
+ end
13
+ else
14
+ # Unrecoverable error?
15
+ end
16
+ end
17
+ else
18
+ assign_master(@options[:master])
19
+ start!
20
+ end
21
+ end
22
+
23
+ def configured?
24
+ !!query("SHOW SLAVE STATUS").fetch_row
25
+ end
26
+
27
+ def slave_error
28
+ row = query("SHOW SLAVE STATUS").fetch_row
29
+
30
+ row and row[19]
31
+ end
32
+
33
+ def assign_master(master)
34
+ master_status = master.master_status
35
+
36
+ master_options =
37
+ {
38
+ 'MASTER_HOST' => 'localhost',
39
+ 'MASTER_USER' => master.user_name,
40
+ 'MASTER_PORT' => 3306,
41
+ 'MASTER_LOG_FILE' => master_status[:master_log_file],
42
+ 'MASTER_LOG_POS' => master_status[:master_log_position]
43
+ }.collect do |k, v|
44
+ case (v)
45
+ when String:
46
+ "#{k}='#{Mysql.quote(v)}'"
47
+ else
48
+ "#{k}=#{v}"
49
+ end
50
+ end
51
+
52
+ execute("CHANGE MASTER TO #{master_options * ', '}")
53
+ end
54
+
55
+ def start!
56
+ execute("START SLAVE")
57
+ end
58
+
59
+ def user_name
60
+ @options[:slave_user] or super
61
+ end
62
+
63
+ def socket_name
64
+ @options[:slave_socket] or super
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ module MysqlReplicationHelper
2
+ class Daemon
3
+ def initialize(options)
4
+ @options = options
5
+
6
+ @options[:master] = @master = Agent::Master.new(options)
7
+ @options[:slave] = @slave = Agent::Slave.new(options)
8
+ end
9
+
10
+ def run!
11
+ while (true)
12
+ @master.poll!
13
+ @slave.poll!
14
+ sleep(10)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Daemonize module
4
+ #
5
+
6
+ require 'rubygems'
7
+ require 'yaml'
8
+ require 'optparse'
9
+
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
11
+
12
+ require 'mysql_replication_helper'
13
+
14
+ # == Constants ==============================================================
15
+
16
+ CONFIG_FILE_LOCATIONS = [
17
+ "/etc/replication-helper.conf",
18
+ "/etc/replication-helper/config",
19
+ "~/.replication-helper/config"
20
+ ].collect { |p| File.expand_path(p) }.freeze
21
+
22
+ DEFAULT_CONFIG = {
23
+ }
24
+
25
+ # == Options ================================================================
26
+
27
+ op = OptionParser.new
28
+ options = { }
29
+ config = { }
30
+ config_file = nil
31
+
32
+ op.on("--master-socket=s") { |socket| options[:master_socket] = socket }
33
+ op.on("--master-data=s") { |dir| options[:master_data] = dir }
34
+ op.on("--master-user=s") { |name| options[:master_user] = name }
35
+
36
+ op.on("--slave-socket=s") { |socket| options[:slave_socket] = socket }
37
+ op.on("--slave-data=s") { |dir| options[:slave_data] = dir }
38
+ op.on("--slave-user=s") { |name| options[:slave_user] = name }
39
+
40
+ op.on("-c", "--config=s") { |path| config_file = path }
41
+ op.on("-v", "--verbose") { options[:verbose] = true }
42
+ op.on("-d", "--daemon") { options[:daemon] = true }
43
+ op.on("-h", "--help") { show_help }
44
+
45
+ args = op.parse(*ARGV)
46
+
47
+ # == Configuration ==========================================================
48
+
49
+ if (config_file)
50
+ if (File.exist?(config_file))
51
+ config = YAML.load(open(config_file))
52
+ end
53
+ end
54
+
55
+ config = DEFAULT_CONFIG.merge(config).merge(options)
56
+
57
+ # == Main ===================================================================
58
+
59
+ MysqlReplicationHelper::Daemon.new(config).run!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: theworkinggroup-mysql-replication-helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Tadman
@@ -9,10 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-24 00:00:00 -07:00
12
+ date: 2009-04-26 00:00:00 -07:00
13
13
  default_executable: replication-helper
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: daemons
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
16
25
  description:
17
26
  email: github@tadman.ca
18
27
  executables:
@@ -27,6 +36,11 @@ files:
27
36
  - VERSION.yml
28
37
  - bin/replication-helper
29
38
  - lib/mysql_replication_helper.rb
39
+ - lib/mysql_replication_helper/agent.rb
40
+ - lib/mysql_replication_helper/agent/master.rb
41
+ - lib/mysql_replication_helper/agent/slave.rb
42
+ - lib/mysql_replication_helper/daemon.rb
43
+ - lib/mysql_replication_helper/daemon_launcher.rb
30
44
  - lib/mysql_replication_helper/error_handler.rb
31
45
  - test/mysql_replication_helper/error_handler_test.rb
32
46
  - test/mysql_replication_helper_test.rb
@@ -55,7 +69,7 @@ requirements: []
55
69
  rubyforge_project:
56
70
  rubygems_version: 1.2.0
57
71
  signing_key:
58
- specification_version: 3
72
+ specification_version: 2
59
73
  summary: MySQL Replication Helper
60
74
  test_files:
61
75
  - test/mysql_replication_helper/error_handler_test.rb