mysql-pause-adapter-ext 0.1.4

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/README ADDED
@@ -0,0 +1,100 @@
1
+ = mysql-pause
2
+
3
+ == Description
4
+
5
+ mysql-pause is a proxy server to pause a query to MySQL.
6
+
7
+ == Source Code
8
+
9
+ https://bitbucket.org/winebarrel/mysql-pause
10
+
11
+ == Dependency
12
+
13
+ * EventMachine
14
+ * RExec
15
+
16
+ == Install
17
+
18
+ gem install mysql-pause
19
+
20
+ == Example
21
+ === Start server
22
+
23
+ shell> mysql-pause start
24
+ Starting daemon...
25
+ Waiting for daemon to start...
26
+ Daemon status: running pid=56921
27
+
28
+ shell> mysql -h 127.0.0.1 -P 13306 -u scott -ptiger
29
+ mysql> select 1;
30
+ +---+
31
+ | 1 |
32
+ +---+
33
+ | 1 |
34
+ +---+
35
+ 1 row in set (0.00 sec)
36
+
37
+ === Pause
38
+
39
+ shell> mpctl pause
40
+
41
+ mysql> select 1;
42
+ (...no response...)
43
+
44
+ === Resume
45
+
46
+ shell> mpctl resume
47
+
48
+ (...resume response...)
49
+ +---+
50
+ | 1 |
51
+ +---+
52
+ | 1 |
53
+ +---+
54
+ 1 row in set (18.01 sec)
55
+
56
+ == Extend MySQL adapter
57
+ === Example code
58
+
59
+ require 'active_record'
60
+ require 'mysql-pause/adapter-ext'
61
+
62
+ ActiveRecord::Base.establish_connection(
63
+ :adapter => 'mysql2',
64
+ :host => '127.0.0.1',
65
+ :port => 13306,
66
+ :username => 'scott',
67
+ :password => 'tiger',
68
+ :database => 'employees',
69
+ :reconnect => true,
70
+ )
71
+
72
+ class Employee < ActiveRecord::Base; end
73
+
74
+ loop do
75
+ employee = Employee.new
76
+ employee.first_name = 'Taro'
77
+ employee.last_name = 'Yamada'
78
+ employee.save!
79
+ sleep 3
80
+ end
81
+
82
+ === Behavior
83
+
84
+ log> DEBUG -- : (0.6ms) BEGIN
85
+ log> DEBUG -- : SQL (0.7ms) INSERT INTO `employees` (`first_name`, `last_name`) VALUES ('Taro', 'Yamada')
86
+ log> DEBUG -- : (0.8ms) COMMIT
87
+ log> DEBUG -- : (0.6ms) BEGIN
88
+
89
+ shell> mpctl pause
90
+ shell> service mysql restart
91
+ shell> mpctl resume
92
+
93
+ log> DEBUG -- : (0.6ms) BEGIN
94
+ (...handle error and reconnect...)
95
+ log> DEBUG -- : Mysql2::Error: %MYSQL_PAUSE%;;1000;;Aborted backend connection: BEGIN
96
+ log> WARN -- : ActiveRecord::StatementInvalid: Mysql2::Error: %MYSQL_PAUSE%;;1000;;Aborted backend connection: BEGIN
97
+ log> DEBUG -- : (0.3ms) BEGIN
98
+ log> DEBUG -- : SQL (2.1ms) INSERT INTO `employees` (`first_name`, `last_name`) VALUES ('Taro', 'Yamada')
99
+ log> DEBUG -- : (0.8ms) COMMIT
100
+
@@ -0,0 +1,26 @@
1
+ require 'active_record'
2
+ require 'active_record/connection_adapters/abstract_mysql_adapter'
3
+ require 'mysql-pause/error'
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ class AbstractMysqlAdapter
8
+
9
+ alias mysql_pause_execute_orig execute
10
+
11
+ def execute(sql, name = nil)
12
+ begin
13
+ mysql_pause_execute_orig(sql, name)
14
+ rescue => e
15
+ raise(e) unless MysqlPause::Error.mysql_pause_error?(e)
16
+
17
+ message = "#{e.class.name}: #{e.message}"
18
+ @logger.warn message if @logger
19
+ reconnect!
20
+ retry
21
+ end
22
+ end
23
+
24
+ end # AbstractMysqlAdapter
25
+ end # ConnectionAdapters
26
+ end # ActiveRecord
@@ -0,0 +1,45 @@
1
+ module MysqlPause
2
+ class Error
3
+
4
+ ERROR_HEADER = '%MYSQL_PAUSE%'
5
+ ERROR_SEPARATOR = ';;'
6
+ ERROR_LIST = {}
7
+
8
+ class << self
9
+ def create_error_message(error_code, sequence_id)
10
+ # fetch error info
11
+ mysql_error_code, sql_state, message = ERROR_LIST[error_code]
12
+
13
+ # create mysql error message
14
+ message = [ERROR_HEADER, error_code, message].join(ERROR_SEPARATOR)
15
+
16
+ # create header
17
+ mysql_error_code = convert_to_chars(mysql_error_code, 2)
18
+ payload = ["\xFF", mysql_error_code, '#', sql_state, message].join
19
+ payload_length = convert_to_chars(payload.length, 3)
20
+ sequence_id = convert_to_chars(sequence_id, 1)
21
+
22
+ [payload_length, sequence_id, payload].join
23
+ end
24
+
25
+ def mysql_pause_error?(e)
26
+ /#{Regexp.escape(ERROR_HEADER)}/ =~ e.message
27
+ end
28
+
29
+ private
30
+
31
+ def convert_to_chars(number, length)
32
+ (0...length).map {|i| (number >> (8 * i)) & 0xFF }.pack("C*")
33
+ end
34
+
35
+ def define_error(name, code, values)
36
+ const_set(name, code)
37
+ ERROR_LIST[code] = values
38
+ end
39
+ end # self
40
+
41
+ # error list
42
+ define_error :ABORTED_BACKEND_CONNECTION, 1000, [2013, '08S01', 'Aborted backend connection']
43
+
44
+ end # Errot
45
+ end # MysqlPause
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mysql-pause-adapter-ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - winebarrel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-24 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description:
15
+ email: sgwr_dts@yahoo.co.jp
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README
21
+ - lib/mysql-pause/adapter-ext.rb
22
+ - lib/mysql-pause/error.rb
23
+ homepage: https://bitbucket.org/winebarrel/mysql-pause
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.23
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: mysql adapter extension for mysql-pause
47
+ test_files: []