flydata 0.3.16 → 0.3.17
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.
- 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
|