flydata 0.3.16 → 0.3.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/flydata-core/lib/flydata-core/record/record.rb +13 -0
- data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +107 -5
- data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +62 -11
- data/flydata-core/spec/table_def/mysql_table_def_spec.rb +37 -1
- data/flydata-core/spec/table_def/mysql_to_redshift_table_def_spec.rb +120 -0
- data/flydata-core/spec/table_def/mysqldump_test_column_charset.dump +45 -0
- data/flydata-core/spec/table_def/redshift_table_def_spec.rb +70 -88
- data/flydata.gemspec +13 -8
- data/lib/flydata/command/setup.rb +4 -4
- data/lib/flydata/command/sync.rb +18 -29
- data/lib/flydata/compatibility_check.rb +2 -2
- data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +15 -10
- data/lib/flydata/fluent-plugins/mysql/binlog_record_handler.rb +6 -3
- data/lib/flydata/fluent-plugins/mysql/dml_record_handler.rb +15 -8
- data/lib/flydata/fluent-plugins/mysql/table_meta.rb +6 -34
- data/lib/flydata/{fluent-plugins/mysql → mysql}/binlog_position.rb +2 -0
- data/lib/flydata/{util → mysql}/mysql_util.rb +34 -1
- data/lib/flydata/mysql/table_ddl.rb +118 -0
- data/lib/flydata/parser/mysql/dump_parser.rb +5 -5
- data/lib/flydata/parser/mysql/mysql_alter_table.treetop +29 -5
- data/lib/flydata/sync_file_manager.rb +15 -2
- data/spec/flydata/command/sync_spec.rb +22 -1
- data/spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb +7 -2
- data/spec/flydata/fluent-plugins/mysql/dml_record_handler_spec.rb +130 -0
- data/spec/flydata/fluent-plugins/mysql/shared_query_handler_context.rb +1 -0
- data/spec/flydata/fluent-plugins/mysql/table_meta_spec.rb +14 -8
- data/spec/flydata/fluent-plugins/mysql/truncate_query_handler_spec.rb +2 -1
- data/spec/flydata/{fluent-plugins/mysql → mysql}/binlog_position_spec.rb +3 -2
- data/spec/flydata/{util → mysql}/mysql_util_spec.rb +2 -2
- data/spec/flydata/mysql/table_ddl_spec.rb +193 -0
- data/spec/flydata/parser/mysql/alter_table_parser_spec.rb +37 -9
- data/spec/flydata/sync_file_manager_spec.rb +102 -27
- metadata +12 -7
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'mysql2'
|
2
2
|
require 'flydata/command_loggable'
|
3
|
-
require 'flydata/
|
3
|
+
require 'flydata/mysql/mysql_util'
|
4
4
|
|
5
5
|
module Flydata
|
6
6
|
|
@@ -123,7 +123,7 @@ module Flydata
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def check_mysql_protocol_tcp_compat
|
126
|
-
query =
|
126
|
+
query = Mysql::MysqlUtil.generate_mysql_show_grants_cmd(@db_opts)
|
127
127
|
|
128
128
|
Open3.popen3(query) do |stdin, stdout, stderr|
|
129
129
|
stdin.close
|
@@ -9,13 +9,14 @@ lib = File.expand_path(File.join(File.dirname(__FILE__), '../../'))
|
|
9
9
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
10
10
|
require 'flydata'
|
11
11
|
require 'flydata/sync_file_manager'
|
12
|
-
require 'flydata/
|
12
|
+
require 'flydata/mysql/mysql_util'
|
13
13
|
require 'flydata/fluent-plugins/preference'
|
14
14
|
require 'flydata/fluent-plugins/mysql/binlog_position_file'
|
15
15
|
require 'flydata/fluent-plugins/mysql/binlog_record_dispatcher'
|
16
16
|
require 'flydata/fluent-plugins/mysql/context'
|
17
17
|
require 'flydata/fluent-plugins/idle_event_detector'
|
18
18
|
require 'flydata/fluent-plugins/mysql/table_meta'
|
19
|
+
require 'flydata/mysql/table_ddl'
|
19
20
|
require 'flydata-core/fluent/config_helper'
|
20
21
|
|
21
22
|
#Monkey-patch fluentd class (EngineClass) to support shutdown for input plugin.
|
@@ -75,11 +76,11 @@ class MysqlBinlogFlydataInput < MysqlBinlogInput
|
|
75
76
|
end
|
76
77
|
|
77
78
|
# Db access opts
|
78
|
-
db_opts = { host: @host, port: @port, username: @username, password: @password, database: @database, ssl_ca: @ssl_ca_path }
|
79
|
+
@db_opts = { host: @host, port: @port, username: @username, password: @password, database: @database, ssl_ca: @ssl_ca_path }
|
79
80
|
|
80
81
|
$log.info "mysql host:\"#{@host}\" port:\"#{@port}\" username:\"#{@username}\" database:\"#{@database}\" tables:\"#{@tables}\" tables_append_only:\"#{tables_append_only}\""
|
81
82
|
$log.info "mysql client version: #{`mysql -V`}"
|
82
|
-
server_version = `echo 'select version();' | #{Flydata::
|
83
|
+
server_version = `echo 'select version();' | #{Flydata::Mysql::MysqlUtil.generate_mysql_cmd(@db_opts)} 2>/dev/null`
|
83
84
|
$log.info "mysql server version: #{server_version}"
|
84
85
|
|
85
86
|
@tables = @tables.split(/,\s*/)
|
@@ -94,7 +95,7 @@ class MysqlBinlogFlydataInput < MysqlBinlogInput
|
|
94
95
|
@tables -= new_tables
|
95
96
|
$log.info "Not watching these tables: #{new_tables.join(", ")}"
|
96
97
|
|
97
|
-
table_meta = Mysql::TableMeta.new(db_opts.merge(tables: @tables))
|
98
|
+
table_meta = Flydata::Mysql::TableMeta.new(@db_opts.merge(tables: @tables))
|
98
99
|
|
99
100
|
table_revs = tables.inject({}) do |h, table_name|
|
100
101
|
h[table_name] = @sync_fm.table_rev(table_name)
|
@@ -145,6 +146,11 @@ EOS
|
|
145
146
|
|
146
147
|
def run
|
147
148
|
@context.table_meta.update
|
149
|
+
Flydata::Mysql::TableDdl.migrate_tables(@context.tables, @db_opts,
|
150
|
+
@context.sync_fm, @position_file,
|
151
|
+
@context) do |event|
|
152
|
+
@record_dispatcher.dispatch(event)
|
153
|
+
end
|
148
154
|
start_kodama(mysql_url) do |c|
|
149
155
|
c.binlog_position_file = @position_file
|
150
156
|
if @ssl_ca_path.to_s != '' && c.respond_to?(:ssl_ca=)
|
@@ -167,7 +173,7 @@ EOS
|
|
167
173
|
rescue => e
|
168
174
|
# HACK: mysql-replication-listener has a network connection leak bug which doesn't release a connection
|
169
175
|
# to MySQL. Rather than fixing the bug, restarting the fluentd process for now.
|
170
|
-
$log.warn "kodama died with an error. Restart the process after #{@retry_wait} seconds. error: #{e.class.to_s} '#{e.to_s}'"
|
176
|
+
$log.warn "kodama died with an error. Restart the process after #{@retry_wait} seconds. error: #{e.class.to_s} '#{e.to_s}'\n#{e.backtrace.join("\n")}"
|
171
177
|
sleep @retry_wait
|
172
178
|
Process.kill(:HUP, Process.ppid) # Send SIGHUP to the supervisor to restart fluentd
|
173
179
|
rescue SignalException
|
@@ -260,16 +266,15 @@ class Client
|
|
260
266
|
def rows
|
261
267
|
rs = super
|
262
268
|
# HACK
|
263
|
-
#
|
264
|
-
#
|
265
|
-
# But how?
|
269
|
+
# Set string encoding to binary because ruby-binlog has no knowledge
|
270
|
+
# about the encoding of strings.
|
266
271
|
new_rs = rs.collect {|row|
|
267
272
|
row.collect{|value|
|
268
273
|
if (value.kind_of?(Array))
|
269
274
|
# Update has two rows in it
|
270
|
-
value.collect{|val| val.force_encoding("
|
275
|
+
value.collect{|val| val.force_encoding("binary") if val.respond_to?(:force_encoding); val}
|
271
276
|
else
|
272
|
-
value.force_encoding("
|
277
|
+
value.force_encoding("binary") if value.respond_to?(:force_encoding); value
|
273
278
|
end
|
274
279
|
}
|
275
280
|
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'fluent/plugin/in_mysql_binlog'
|
2
2
|
require 'binlog'
|
3
|
-
require 'flydata/
|
3
|
+
require 'flydata/mysql/binlog_position'
|
4
|
+
require 'flydata-core/record/record'
|
4
5
|
|
5
6
|
module Mysql
|
6
7
|
class BinlogRecordHandler
|
@@ -10,6 +11,7 @@ module Mysql
|
|
10
11
|
RESPECT_ORDER = :respect_order
|
11
12
|
SRC_POS = :src_pos
|
12
13
|
TABLE_REV = :table_rev
|
14
|
+
V = :v # FlyData record format version
|
13
15
|
|
14
16
|
def initialize(context)
|
15
17
|
@context = context
|
@@ -21,7 +23,7 @@ module Mysql
|
|
21
23
|
@context.tables.each do |table_name|
|
22
24
|
table_binlog_content = @context.sync_fm.get_table_binlog_pos(table_name)
|
23
25
|
if table_binlog_content
|
24
|
-
@table_binlog_pos[table_name] = BinLogPosition.new(table_binlog_content)
|
26
|
+
@table_binlog_pos[table_name] = Flydata::Mysql::BinLogPosition.new(table_binlog_content)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -40,7 +42,7 @@ module Mysql
|
|
40
42
|
acceptable = @context.tables.include?(table)
|
41
43
|
|
42
44
|
if acceptable and @table_binlog_pos[record['table_name']]
|
43
|
-
if @table_binlog_pos[record['table_name']] >= BinLogPosition.new(
|
45
|
+
if @table_binlog_pos[record['table_name']] >= Flydata::Mysql::BinLogPosition.new(
|
44
46
|
"#{@context.current_binlog_file}\t#{record['next_position'] - record['event_length']}")
|
45
47
|
acceptable = false
|
46
48
|
else
|
@@ -84,6 +86,7 @@ module Mysql
|
|
84
86
|
r[TABLE_NAME] = table
|
85
87
|
r[SRC_POS] = "#{@context.current_binlog_file}\t#{position}"
|
86
88
|
r[TABLE_REV] = table_rev
|
89
|
+
r[V] = FlydataCore::Record::V2
|
87
90
|
end
|
88
91
|
|
89
92
|
# Use binlog's timestamp
|
@@ -49,7 +49,7 @@ module Mysql
|
|
49
49
|
row_values = { ROW => row }
|
50
50
|
row_values = yield(row) if block_given? # Give the caller a chance to generate the correct row values
|
51
51
|
row_types = row_values.keys
|
52
|
-
row_kinds = row_types.inject({}) {|m, k| m[k] = convert_to_flydata_row_format(
|
52
|
+
row_kinds = row_types.inject({}) {|m, k| m[k] = convert_to_flydata_row_format(row_values[k]); m}
|
53
53
|
encode_signless_integer(row_kinds, record["columns"], row_types)
|
54
54
|
row_kinds
|
55
55
|
end
|
@@ -57,22 +57,29 @@ module Mysql
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
def convert_to_flydata_row_format(
|
60
|
+
def convert_to_flydata_row_format(row)
|
61
61
|
row.each.with_index(1).inject({}) do |h, (v, i)|
|
62
62
|
if v.kind_of?(String)
|
63
|
-
v = encode_row_value(
|
63
|
+
v = encode_row_value(v)
|
64
|
+
if v.encoding == Encoding::BINARY
|
65
|
+
h['attrs'] ||= {}
|
66
|
+
h['attrs'][i.to_s] ||= {}
|
67
|
+
h['attrs'][i.to_s]['enc'] = 'b'
|
68
|
+
end
|
64
69
|
end
|
65
70
|
h[i.to_s] = v
|
66
71
|
h
|
67
72
|
end
|
68
73
|
end
|
69
74
|
|
70
|
-
def encode_row_value(
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
value.
|
75
|
+
def encode_row_value(value)
|
76
|
+
value.force_encoding('utf-8')
|
77
|
+
unless value.valid_encoding?
|
78
|
+
# value can't be treated as UTF-8. Convert to Flydata binary format.
|
79
|
+
value = "0x" + value.unpack('c*').collect{|c| "%02X" % (c < 0 ? c + 256 : c)}.join('')
|
80
|
+
value.force_encoding('binary') # setting to 'binary' to differentiate from UTF-8. Downstream code may rely on it.
|
75
81
|
end
|
82
|
+
value
|
76
83
|
end
|
77
84
|
|
78
85
|
def encode_signless_integer(record, column_types, row_types)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'mysql2'
|
2
|
+
require 'flydata-core/table_def/mysql_table_def'
|
2
3
|
|
4
|
+
module Flydata
|
3
5
|
module Mysql
|
4
6
|
class TableMeta
|
5
7
|
MANDATORY_OPTS = [
|
@@ -41,45 +43,14 @@ EOT
|
|
41
43
|
database: @database, tables: @tables.collect{|t| "'#{t}'"}.join(',') }
|
42
44
|
columns = conn.query(sql)
|
43
45
|
columns.collect do |col|
|
44
|
-
|
46
|
+
mysql_charset = col['character_set_name']
|
47
|
+
@table_meta[col['table_name'].to_sym][:encoding] = FlydataCore::TableDef::MysqlTableDef.ruby_encoding(mysql_charset)
|
48
|
+
@table_meta[col['table_name'].to_sym][:mysql_charset] = mysql_charset
|
45
49
|
end
|
46
50
|
ensure
|
47
51
|
conn.close rescue nil if conn
|
48
52
|
end
|
49
53
|
|
50
|
-
# Charset naming conversion rule. mysql => ruby
|
51
|
-
#
|
52
|
-
# mysql
|
53
|
-
# http://dev.mysql.com/doc/refman/5.6/en/charset-charsets.html
|
54
|
-
# mysql(supported CJK character sets)
|
55
|
-
# http://dev.mysql.com/doc/refman/5.6/en/faqs-cjk.html#qandaitem-A-11-1-1
|
56
|
-
# For ruby, you can see encoding list with "Encoding.list"
|
57
|
-
CHARSET_ENCODE_RULE = {
|
58
|
-
'ascii' => nil, # 'ASCII-8BIT', (not need to be encoded)
|
59
|
-
'utf8' => nil, # 'UTF-8', (not need to be encoded)
|
60
|
-
'utf8mb4' => nil, # 'UTF-8', (not need to be encoded)
|
61
|
-
'utf16' => 'UTF-16',
|
62
|
-
'utf32' => 'UTF-32',
|
63
|
-
'latin1' => 'ISO-8859-1',
|
64
|
-
'latin2' => 'ISO-8859-2',
|
65
|
-
'big5' => 'Big5',
|
66
|
-
'cp932' => 'CP932',
|
67
|
-
'eucjpms' => 'eucJP-ms',
|
68
|
-
'euckr' => 'EUC-KR',
|
69
|
-
'gb18030' => 'GB18030',
|
70
|
-
'gb2312' => 'GB2312',
|
71
|
-
'gbk' => 'GBK',
|
72
|
-
'sjis' => 'Shift_JIS',
|
73
|
-
'ujis' => 'EUC-JP',
|
74
|
-
}
|
75
|
-
|
76
|
-
def get_ruby_charset_name(mysql_charset)
|
77
|
-
return nil if mysql_charset.to_s.empty?
|
78
|
-
raise "Unsupported charset:#{mysql_charset}." unless CHARSET_ENCODE_RULE.has_key?(mysql_charset)
|
79
|
-
charset = CHARSET_ENCODE_RULE[mysql_charset]
|
80
|
-
return charset
|
81
|
-
end
|
82
|
-
|
83
54
|
# Return table meta
|
84
55
|
# :character_set_name
|
85
56
|
def [](table_name)
|
@@ -87,3 +58,4 @@ EOT
|
|
87
58
|
end
|
88
59
|
end
|
89
60
|
end
|
61
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'flydata-core/table_def/mysql_table_def'
|
3
|
+
|
1
4
|
module Flydata
|
2
|
-
module
|
5
|
+
module Mysql
|
3
6
|
class MysqlUtil
|
4
7
|
DEFAULT_MYSQL_CMD_OPTION = "--default-character-set=utf8 --protocol=tcp"
|
5
8
|
|
@@ -73,6 +76,36 @@ module Flydata
|
|
73
76
|
generate_mysql_cmd(opt)
|
74
77
|
end
|
75
78
|
|
79
|
+
def self.each_mysql_tabledef(tables, option)
|
80
|
+
command = generate_mysql_ddl_dump_cmd(option.merge(tables: tables))
|
81
|
+
|
82
|
+
create_opt = {}
|
83
|
+
if option.has_key?(:skip_primary_key_check)
|
84
|
+
create_opt[:skip_primary_key_check] = option[:skip_primary_key_check]
|
85
|
+
end
|
86
|
+
|
87
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
88
|
+
stdin.close
|
89
|
+
stdout.set_encoding("utf-8", "utf-8") # mysqldump output must be in UTF-8
|
90
|
+
create_flydata_ctl_table = true
|
91
|
+
while !stdout.eof?
|
92
|
+
begin
|
93
|
+
mysql_tabledef = FlydataCore::TableDef::MysqlTableDef.create(stdout, create_opt)
|
94
|
+
break if mysql_tabledef.nil?
|
95
|
+
yield(mysql_tabledef, nil)
|
96
|
+
rescue FlydataCore::TableDefError=> e
|
97
|
+
yield(nil, e)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
errors = ""
|
101
|
+
while !stderr.eof?
|
102
|
+
line = stderr.gets.gsub('mysqldump: ', '')
|
103
|
+
errors << line unless /Warning: Using a password on the command line interface can be insecure./ === line
|
104
|
+
end
|
105
|
+
raise errors unless errors.empty?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
76
109
|
private
|
77
110
|
|
78
111
|
def self.convert_keys_to_sym(hash)
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'flydata/mysql/binlog_position'
|
2
|
+
require 'flydata/mysql/mysql_util'
|
3
|
+
|
4
|
+
module Flydata
|
5
|
+
module Mysql
|
6
|
+
|
7
|
+
class TableDdl
|
8
|
+
VERSION0 = 0 # the version where no .generated_ddl file was generated.
|
9
|
+
# Therefore, this version never shows up in anywhere.
|
10
|
+
VERSION1 = 1 # the version which doesn't handle server side encoding support.
|
11
|
+
VERSION2 = 2 # the version with server side encoding support, migrated from
|
12
|
+
# the previous versions. Format/functionality-wise, it's the
|
13
|
+
# same as Version 3.
|
14
|
+
VERSION3 = 3 # the version with server side encoding support, generated by
|
15
|
+
# sync:generated_table_ddl command.
|
16
|
+
VERSION4 = 4 # the version with server side encoding support, generated by
|
17
|
+
# the auto-generated CREATE TABLE event.
|
18
|
+
VERSION = VERSION3
|
19
|
+
|
20
|
+
def self.migrate_tables(tables, mysql_opts, sync_fm, position_file, context,
|
21
|
+
&block)
|
22
|
+
migrate_to_v2(tables, mysql_opts, sync_fm, position_file, context, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
V2_TARGET_VERSION = VERSION2
|
28
|
+
EVENT_TYPE = 'Query'
|
29
|
+
ALTER_TABLE_CHARSET_SQL = <<EOS.strip
|
30
|
+
ALTER TABLE `%s`.`%s` CHARACTER SET = %s;
|
31
|
+
EOS
|
32
|
+
CHANGE_COLUMN_SQL = <<EOS.strip
|
33
|
+
CHANGE COLUMN `%s` %s
|
34
|
+
EOS
|
35
|
+
ALTER_TABLE_SQL = <<EOS.strip
|
36
|
+
ALTER TABLE `%s`.`%s` %s;
|
37
|
+
EOS
|
38
|
+
|
39
|
+
def self.migrate_to_v2(tables, mysql_opts, sync_fm, position_file, context)
|
40
|
+
database = mysql_opts[:database]
|
41
|
+
mysql_tabledefs = nil
|
42
|
+
original_binlog_file = nil
|
43
|
+
binlog_pos = nil
|
44
|
+
event_size = 0 # so that the next binlog position becomes the master binlog position
|
45
|
+
tables.each do |table|
|
46
|
+
# check the current ddl version
|
47
|
+
contents = sync_fm.load_generated_ddl([table])
|
48
|
+
version = contents.first.to_i
|
49
|
+
# return if no need to migrate
|
50
|
+
next if version >= V2_TARGET_VERSION
|
51
|
+
|
52
|
+
if mysql_tabledefs.nil?
|
53
|
+
MysqlUtil.each_mysql_tabledef(tables, mysql_opts) do |mysql_tabledef, error|
|
54
|
+
raise error if error
|
55
|
+
|
56
|
+
mysql_tabledefs ||= {}
|
57
|
+
mysql_tabledefs[mysql_tabledef.table_name] = mysql_tabledef
|
58
|
+
end
|
59
|
+
end
|
60
|
+
mysql_tabledef = mysql_tabledefs[table]
|
61
|
+
if binlog_pos.nil?
|
62
|
+
# get binlog position
|
63
|
+
binlog_pos = BinLogPosition.new(File.open(position_file){|f| f.read })
|
64
|
+
original_binlog_file = context.current_binlog_file
|
65
|
+
context.current_binlog_file = binlog_pos.file
|
66
|
+
end
|
67
|
+
# get charset
|
68
|
+
charset = mysql_tabledef.default_charset_mysql
|
69
|
+
# construct queries
|
70
|
+
# column charset
|
71
|
+
column_event = nil
|
72
|
+
at_subquery = mysql_tabledef.column_def.select{|col, coldef| /CHARACTER SET/.match(coldef) }.collect{|col, coldef| CHANGE_COLUMN_SQL % [col, coldef]}.join(",")
|
73
|
+
unless at_subquery.empty?
|
74
|
+
column_query = ALTER_TABLE_SQL % [database, table, at_subquery]
|
75
|
+
column_event = QueryEvent.new(EVENT_TYPE, database, table,
|
76
|
+
binlog_pos.pos, event_size, column_query,
|
77
|
+
Time.now.to_i)
|
78
|
+
yield column_event
|
79
|
+
end
|
80
|
+
# table charset
|
81
|
+
table_query = ALTER_TABLE_CHARSET_SQL % [database, table, charset]
|
82
|
+
# create events and yield
|
83
|
+
table_event = QueryEvent.new(EVENT_TYPE, database, table, binlog_pos.pos,
|
84
|
+
event_size, table_query, Time.now.to_i)
|
85
|
+
yield table_event
|
86
|
+
$log.info "migrating table `#{table}` from version #{version} to version #{V2_TARGET_VERSION}. Table event #{table_event} Column event #{column_event}"
|
87
|
+
|
88
|
+
# update generated_ddl
|
89
|
+
sync_fm.save_generated_ddl([table], V2_TARGET_VERSION.to_s)
|
90
|
+
end
|
91
|
+
context.current_binlog_file = original_binlog_file if binlog_pos
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# mimics RubyBinlog::QueryEvent
|
96
|
+
class QueryEvent
|
97
|
+
def initialize(event_type, database_name, event_table_name, next_position,
|
98
|
+
event_length, query, timestamp)
|
99
|
+
@event_type = event_type
|
100
|
+
@database_name = database_name
|
101
|
+
@event_table_name = event_table_name
|
102
|
+
@next_position = next_position
|
103
|
+
@event_length = event_length
|
104
|
+
@query = query
|
105
|
+
@timestamp = timestamp
|
106
|
+
end
|
107
|
+
attr_reader :event_type, :database_name, :event_table_name, :next_position,
|
108
|
+
:event_length, :query, :timestamp
|
109
|
+
|
110
|
+
def to_s
|
111
|
+
<<EOS
|
112
|
+
event_type;#{event_type} database_name:#{database_name} event_table_name:#{event_table_name} next_position:#{next_position} event_length:#{event_length} timestamp:#{timestamp} query:#{query}
|
113
|
+
EOS
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'fiber'
|
2
|
-
require 'flydata/
|
2
|
+
require 'flydata/mysql/mysql_util'
|
3
3
|
|
4
4
|
module Flydata
|
5
5
|
module Parser
|
@@ -73,16 +73,16 @@ EOS
|
|
73
73
|
|
74
74
|
begin
|
75
75
|
# create pipe for callback function
|
76
|
-
rd_io, wr_io = IO.pipe("utf-8")
|
76
|
+
rd_io, wr_io = IO.pipe("utf-8", "utf-8")
|
77
77
|
wr_io.sync = true
|
78
|
-
wr_io.set_encoding("utf-8")
|
78
|
+
wr_io.set_encoding("utf-8", "utf-8")
|
79
79
|
rd_io.extend(DumpStreamIO)
|
80
80
|
binlog_pos = nil
|
81
81
|
|
82
82
|
# start mysqldump
|
83
83
|
Open3.popen3 dump_cmd do |cmd_in, cmd_out, cmd_err, wait_thr|
|
84
84
|
cmd_in.close_write
|
85
|
-
cmd_out.set_encoding("utf-8") # mysqldump output must be in UTF-8
|
85
|
+
cmd_out.set_encoding("utf-8", "utf-8") # mysqldump output must be in UTF-8
|
86
86
|
|
87
87
|
first_line = cmd_out.gets # wait until first line comes
|
88
88
|
binfile, pos = table_locker.resume
|
@@ -135,7 +135,7 @@ EOS
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def generate_dump_cmd(conf, file_path = nil)
|
138
|
-
|
138
|
+
Flydata::Mysql::MysqlUtil.generate_mysqldump_without_master_data_cmd(conf.merge(result_file: file_path))
|
139
139
|
end
|
140
140
|
|
141
141
|
private
|