flydata 0.6.3 → 0.6.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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/bin/fdredshift +78 -0
  5. data/circle.yml +1 -1
  6. data/ext/flydata/{parser/mysql → source_mysql/parser}/.gitignore +0 -0
  7. data/ext/flydata/{parser/mysql → source_mysql/parser}/dump_parser_ext.cpp +3 -3
  8. data/ext/flydata/source_mysql/parser/extconf.rb +3 -0
  9. data/ext/flydata/{parser/mysql → source_mysql/parser}/parser.txt +0 -0
  10. data/ext/flydata/{parser/mysql → source_mysql/parser}/sql_parser.cpp +0 -0
  11. data/ext/flydata/{parser/mysql → source_mysql/parser}/sql_parser.h +0 -0
  12. data/flydata-core/lib/flydata-core/mysql/binlog_pos.rb +34 -32
  13. data/flydata-core/lib/flydata-core/mysql/compatibility_checker.rb +20 -0
  14. data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +12 -4
  15. data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +60 -6
  16. data/flydata-core/spec/mysql/binlog_pos_spec.rb +474 -0
  17. data/flydata-core/spec/table_def/mysql_table_def_spec.rb +57 -0
  18. data/flydata-core/spec/table_def/mysql_to_redshift_table_def_spec.rb +174 -20
  19. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_AUTO_INCREMENT_keyword.dump +43 -0
  20. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_not_null_keyword.dump +43 -0
  21. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_unique_keyword.dump +43 -0
  22. data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_unsigned_keyword.dump +43 -0
  23. data/flydata-core/spec/table_def/redshift_table_def_spec.rb +41 -8
  24. data/flydata.gemspec +0 -0
  25. data/lib/flydata/cli.rb +11 -5
  26. data/lib/flydata/command/base.rb +14 -1
  27. data/lib/flydata/command/exclusive_runnable.rb +42 -12
  28. data/lib/flydata/command/helper.rb +6 -6
  29. data/lib/flydata/command/sender.rb +4 -3
  30. data/lib/flydata/command/setup.rb +30 -381
  31. data/lib/flydata/command/stop.rb +1 -0
  32. data/lib/flydata/command/sync.rb +273 -301
  33. data/lib/flydata/compatibility_check.rb +24 -117
  34. data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +3 -3
  35. data/lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb +2 -2
  36. data/lib/flydata/fluent-plugins/mysql/binlog_record_handler.rb +6 -6
  37. data/lib/flydata/fluent-plugins/mysql/truncate_table_query_handler.rb +0 -1
  38. data/lib/flydata/parser.rb +14 -0
  39. data/lib/flydata/{parser_provider.rb → parser/parser_provider.rb} +6 -4
  40. data/lib/flydata/parser/source_table.rb +33 -0
  41. data/lib/flydata/source.rb +105 -0
  42. data/lib/flydata/source/component.rb +21 -0
  43. data/lib/flydata/source/errors.rb +7 -0
  44. data/lib/flydata/source/generate_source_dump.rb +72 -0
  45. data/lib/flydata/source/parse_dump_and_send.rb +52 -0
  46. data/lib/flydata/source/setup.rb +31 -0
  47. data/lib/flydata/source/source_pos.rb +45 -0
  48. data/lib/flydata/source/sync.rb +56 -0
  49. data/lib/flydata/source/sync_generate_table_ddl.rb +43 -0
  50. data/lib/flydata/source_file/setup.rb +17 -0
  51. data/lib/flydata/source_file/sync.rb +14 -0
  52. data/lib/flydata/{command → source_mysql/command}/mysql.rb +2 -1
  53. data/lib/flydata/{command → source_mysql/command}/mysql_command_base.rb +2 -4
  54. data/lib/flydata/{command → source_mysql/command}/mysqlbinlog.rb +2 -1
  55. data/lib/flydata/{command → source_mysql/command}/mysqldump.rb +2 -1
  56. data/lib/flydata/source_mysql/generate_source_dump.rb +53 -0
  57. data/lib/flydata/source_mysql/mysql_compatibility_check.rb +114 -0
  58. data/lib/flydata/source_mysql/parse_dump_and_send.rb +28 -0
  59. data/lib/flydata/{parser/mysql → source_mysql/parser}/.gitignore +0 -0
  60. data/lib/flydata/{parser/mysql → source_mysql/parser}/dump_parser.rb +32 -67
  61. data/lib/flydata/{parser/mysql → source_mysql/parser}/mysql_alter_table.treetop +0 -0
  62. data/lib/flydata/source_mysql/setup.rb +24 -0
  63. data/lib/flydata/source_mysql/source_pos.rb +21 -0
  64. data/lib/flydata/source_mysql/sync.rb +45 -0
  65. data/lib/flydata/source_mysql/sync_generate_table_ddl.rb +40 -0
  66. data/lib/flydata/{mysql → source_mysql}/table_ddl.rb +6 -17
  67. data/lib/flydata/source_zendesk/sync_generate_table_ddl.rb +30 -0
  68. data/lib/flydata/source_zendesk/zendesk_flydata_tabledefs.rb +133 -0
  69. data/lib/flydata/sync_file_manager.rb +132 -73
  70. data/lib/flydata/table_ddl.rb +18 -0
  71. data/spec/flydata/cli_spec.rb +1 -0
  72. data/spec/flydata/command/exclusive_runnable_spec.rb +19 -8
  73. data/spec/flydata/command/sender_spec.rb +1 -1
  74. data/spec/flydata/command/setup_spec.rb +4 -4
  75. data/spec/flydata/command/sync_spec.rb +97 -134
  76. data/spec/flydata/compatibility_check_spec.rb +16 -289
  77. data/spec/flydata/fluent-plugins/mysql/alter_table_query_handler_spec.rb +3 -3
  78. data/spec/flydata/fluent-plugins/mysql/dml_record_handler_spec.rb +1 -1
  79. data/spec/flydata/fluent-plugins/mysql/shared_query_handler_context.rb +4 -2
  80. data/spec/flydata/fluent-plugins/mysql/truncate_query_handler_spec.rb +1 -1
  81. data/spec/flydata/source_mysql/generate_source_dump_spec.rb +69 -0
  82. data/spec/flydata/source_mysql/mysql_compatibility_check_spec.rb +280 -0
  83. data/spec/flydata/{parser/mysql → source_mysql/parser}/alter_table_parser_spec.rb +2 -2
  84. data/spec/flydata/{parser/mysql → source_mysql/parser}/dump_parser_spec.rb +75 -70
  85. data/spec/flydata/source_mysql/sync_generate_table_ddl_spec.rb +137 -0
  86. data/spec/flydata/{mysql → source_mysql}/table_ddl_spec.rb +2 -2
  87. data/spec/flydata/source_spec.rb +140 -0
  88. data/spec/flydata/source_zendesk/sync_generate_table_ddl_spec.rb +33 -0
  89. data/spec/flydata/sync_file_manager_spec.rb +157 -77
  90. data/tmpl/redshift_mysql_data_entry.conf.tmpl +1 -1
  91. metadata +56 -23
  92. data/ext/flydata/parser/mysql/extconf.rb +0 -3
  93. data/lib/flydata/mysql/binlog_position.rb +0 -22
  94. data/spec/flydata/mysql/binlog_position_spec.rb +0 -35
@@ -1,22 +1,11 @@
1
- require 'flydata/mysql/binlog_position'
1
+ require 'flydata/table_ddl'
2
2
  require 'flydata-core/mysql/command_generator'
3
+ require 'flydata-core/mysql/binlog_pos'
3
4
 
4
5
  module Flydata
5
- module Mysql
6
+ module SourceMysql
6
7
 
7
8
  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
9
  def self.migrate_tables(tables, mysql_opts, sync_fm, position_file, context,
21
10
  &block)
22
11
  migrate_to_v2(tables, mysql_opts, sync_fm, position_file, context, &block)
@@ -24,7 +13,7 @@ class TableDdl
24
13
 
25
14
  private
26
15
 
27
- V2_TARGET_VERSION = VERSION2
16
+ V2_TARGET_VERSION = Flydata::TableDdl::VERSION2
28
17
  EVENT_TYPE = 'Query'
29
18
  ALTER_TABLE_CHARSET_SQL = <<EOS.strip
30
19
  ALTER TABLE `%s`.`%s` CHARACTER SET = %s;
@@ -60,9 +49,9 @@ EOS
60
49
  mysql_tabledef = mysql_tabledefs[table]
61
50
  if binlog_pos.nil?
62
51
  # get binlog position
63
- binlog_pos = BinLogPosition.new(File.open(position_file){|f| f.read })
52
+ binlog_pos = FlydataCore::Mysql::BinlogPos.new(File.open(position_file){|f| f.read })
64
53
  original_binlog_file = context.current_binlog_file
65
- context.current_binlog_file = binlog_pos.file
54
+ context.current_binlog_file = binlog_pos.filename
66
55
  end
67
56
  # get charset
68
57
  charset = mysql_tabledef.default_charset_mysql
@@ -0,0 +1,30 @@
1
+ require 'flydata/source/sync_generate_table_ddl'
2
+ require 'flydata/source_zendesk/zendesk_flydata_tabledefs'
3
+
4
+ module Flydata
5
+ module SourceZendesk
6
+
7
+ class SyncGenerateTableDdl < Source::SyncGenerateTableDdl
8
+ def run_compatibility_check
9
+ #TODO Check version "Zendesk v2 API"
10
+ end
11
+
12
+ def generate_flydata_tabledef(tables, options)
13
+ flydata_tabledefs = []
14
+ error_list = []
15
+ zendesk_resource_names = ZENDESK_FLYDATA_TABLEDEFS.keys.join(" ")
16
+
17
+ tables.each do |tablename|
18
+ flydata_tabledef = ZENDESK_FLYDATA_TABLEDEFS[tablename]
19
+ if !flydata_tabledef
20
+ error_list << { error: "Invalid Zendesk resource name specified. Flydata supports following Zendesk resources: #{zendesk_resource_names}", table: tablename }
21
+ next
22
+ end
23
+ flydata_tabledefs << flydata_tabledef
24
+ end
25
+ [flydata_tabledefs, error_list]
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,133 @@
1
+ module Flydata
2
+ module SourceZendesk
3
+
4
+ class SyncGenerateTableDdl < Source::SyncGenerateTableDdl
5
+ ZENDESK_FLYDATA_TABLEDEFS =
6
+ {"tickets"=>
7
+ {:table_name=>"tickets",
8
+ :columns=>
9
+ [{:column=>"id", :type=>"int8(20)", :not_null=>true, :primary_key=>true},
10
+ {:column=>"url", :type=>"varchar(8000)", :default=>nil},#RFC7231 8000 octets
11
+ {:column=>"external_id", :type=>"varchar(2047)", :default=>nil},
12
+ {:column=>"type", :type=>"varchar(24)", :default=>nil},
13
+ {:column=>"subject", :type=>"text"},
14
+ {:column=>"raw_subject", :type=>"text"},
15
+ {:column=>"description", :type=>"text"},
16
+ {:column=>"priority", :type=>"varchar(24)", :default=>nil},
17
+ {:column=>"status", :type=>"varchar(24)", :default=>nil},
18
+ {:column=>"recipient", :type=>"varchar(762)", :default=>nil},#email
19
+ {:column=>"requester_id", :type=>"int8(20)", :default=>nil},
20
+ {:column=>"submitter_id", :type=>"int8(20)", :default=>nil},
21
+ {:column=>"assignee_id", :type=>"int8(20)", :default=>nil},
22
+ {:column=>"organization_id", :type=>"int8(20)", :default=>nil},
23
+ {:column=>"group_id", :type=>"int8(20)", :default=>nil},
24
+ {:column=>"collaborator_ids", :type=>"text"},
25
+ {:column=>"forum_topic_id", :type=>"int8(20)", :default=>nil},
26
+ {:column=>"problem_id", :type=>"int8(20)", :default=>nil},
27
+ {:column=>"has_incidents", :type=>"int1(1)", :default=>nil},
28
+ {:column=>"due_at", :type=>"datetime", :default=>nil},
29
+ {:column=>"tags", :type=>"text"},
30
+ {:column=>"via", :type=>"text"},
31
+ {:column=>"custom_fields", :type=>"text"},
32
+ {:column=>"satisfaction_rating", :type=>"text"},
33
+ {:column=>"sharing_agreement_ids", :type=>"text"},
34
+ {:column=>"followup_ids", :type=>"text"},
35
+ {:column=>"ticket_form_id", :type=>"int8(20)", :default=>nil},
36
+ {:column=>"brand_id", :type=>"int8(20)", :default=>nil},
37
+ {:column=>"created_at", :type=>"datetime", :default=>nil},
38
+ {:column=>"updated_at", :type=>"datetime", :default=>nil}],
39
+ :default_charset=>"UTF_8",
40
+ :src_ddl=> '{"version":"Zendesk v2 API","url":"https://developer.zendesk.com/rest_api/docs/core/tickets”}'
41
+ },
42
+ "ticket_comments"=>
43
+ {:table_name=>"ticket_comments",
44
+ :columns=>
45
+ [{:column=>"id", :type=>"int8(20)", :not_null=>true, :primary_key=>true},
46
+ {:column=>"type", :type=>"varchar(24)", :default=>nil},
47
+ {:column=>"body", :type=>"text"},
48
+ {:column=>"html_body", :type=>"text"},
49
+ {:column=>"public", :type=>"int1(1)", :default=>nil},
50
+ {:column=>"author_id", :type=>"int8(20)", :default=>nil},
51
+ {:column=>"attachments", :type=>"text"},
52
+ {:column=>"via", :type=>"text"},
53
+ {:column=>"metadata", :type=>"text"},
54
+ {:column=>"created_at", :type=>"datetime", :default=>nil}],
55
+ :default_charset=>"UTF_8",
56
+ :src_ddl=> '{"version":"Zendesk v2 API","url":"https://developer.zendesk.com/rest_api/docs/core/ticket_comments”}'
57
+ },
58
+ "ticket_audits"=>
59
+ {:table_name=>"ticket_audits",
60
+ :columns=>
61
+ [{:column=>"id", :type=>"int8(20)", :not_null=>true, :primary_key=>true},
62
+ {:column=>"ticket_id", :type=>"int8(20)", :default=>nil},
63
+ {:column=>"metadata", :type=>"text"},
64
+ {:column=>"via", :type=>"text"},
65
+ {:column=>"created_at", :type=>"datetime", :default=>nil},
66
+ {:column=>"author_id", :type=>"int8(20)", :default=>nil},
67
+ {:column=>"events", :type=>"text"}],
68
+ :default_charset=>"UTF_8",
69
+ :src_ddl=> '{"version":"Zendesk v2 API","url":"https://developer.zendesk.com/rest_api/docs/core/ticket_audits”}'
70
+ },
71
+ "users"=>
72
+ {:table_name=>"users",
73
+ :columns=>
74
+ [{:column=>"id", :type=>"int8(20)", :not_null=>true, :primary_key=>true},
75
+ {:column=>"url", :type=>"varchar(8000)", :default=>nil},#RFC 7230 recommendation (8000 octets)
76
+ {:column=>"name", :type=>"varchar(6141)", :default=>nil},
77
+ {:column=>"external_id", :type=>"varchar(2047)", :default=>nil},
78
+ {:column=>"alias", :type=>"varchar(6141)", :default=>nil},
79
+ {:column=>"created_at", :type=>"datetime", :default=>nil},
80
+ {:column=>"updated_at", :type=>"datetime", :default=>nil},
81
+ {:column=>"active", :type=>"int1(1)", :default=>nil},
82
+ {:column=>"verified", :type=>"int1(1)", :default=>nil},
83
+ {:column=>"shared", :type=>"int1(1)", :default=>nil},
84
+ {:column=>"shared_agent", :type=>"int1(1)", :default=>nil},
85
+ {:column=>"locale", :type=>"varchar(765)", :default=>nil},
86
+ {:column=>"locale_id", :type=>"int4(11)", :default=>nil},
87
+ {:column=>"time_zone", :type=>"varchar(765)", :default=>nil},
88
+ {:column=>"last_login_at", :type=>"datetime", :default=>nil},
89
+ {:column=>"two_factor_auth_enabled", :type=>"int1(1)", :default=>nil},
90
+ {:column=>"email", :type=>"varchar(762)", :default=>nil},
91
+ {:column=>"phone", :type=>"varchar(765)", :default=>nil},
92
+ {:column=>"signature", :type=>"text"},
93
+ {:column=>"details", :type=>"text"},
94
+ {:column=>"notes", :type=>"text"},
95
+ {:column=>"organization_id", :type=>"int8(20)", :default=>nil},
96
+ {:column=>"role", :type=>"varchar(24)", :default=>nil},
97
+ {:column=>"custom_role_id", :type=>"int8(20)", :default=>nil},
98
+ {:column=>"moderator", :type=>"int1(1)", :default=>nil},
99
+ {:column=>"ticket_restriction", :type=>"varchar(24)", :default=>nil},
100
+ {:column=>"only_private_comments", :type=>"int1(1)", :default=>nil},
101
+ {:column=>"tags", :type=>"text"},
102
+ {:column=>"suspended", :type=>"int1(1)", :default=>nil},
103
+ {:column=>"restricted_agent", :type=>"int1(1)", :default=>nil},
104
+ {:column=>"photo", :type=>"text"},
105
+ {:column=>"user_fields", :type=>"text"}],
106
+ :default_charset=>"UTF_8",
107
+ :src_ddl=> '{"version":"Zendesk v2 API","url":"https://developer.zendesk.com/rest_api/docs/core/users”}'
108
+ },
109
+ "organizations"=>
110
+ {:table_name=>"organizations",
111
+ :columns=>
112
+ [{:column=>"id", :type=>"int8(20)", :not_null=>true, :primary_key=>true},
113
+ {:column=>"url", :type=>"varchar(8000)", :default=>nil},
114
+ {:column=>"external_id", :type=>"varchar(2047)", :default=>nil},
115
+ {:column=>"name", :type=>"varchar(6141)", :default=>nil},
116
+ {:column=>"created_at", :type=>"datetime", :default=>nil},
117
+ {:column=>"updated_at", :type=>"datetime", :default=>nil},
118
+ {:column=>"domain_names", :type=>"text"},
119
+ {:column=>"details", :type=>"text"},
120
+ {:column=>"notes", :type=>"text"},
121
+ {:column=>"group_id", :type=>"int8(20)", :default=>nil},
122
+ {:column=>"shared_tickets", :type=>"int1(1)", :default=>nil},
123
+ {:column=>"shared_comments", :type=>"int1(1)", :default=>nil},
124
+ {:column=>"tags", :type=>"text"},
125
+ {:column=>"organization_fields", :type=>"text"}],
126
+ :default_charset=>"UTF_8",
127
+ :src_ddl=> '{"version":"Zendesk v2 API","url":"https://developer.zendesk.com/rest_api/docs/core/organizations”}'
128
+ }
129
+ }
130
+ end
131
+
132
+ end
133
+ end
@@ -1,6 +1,9 @@
1
- require 'mysql2'
2
1
  require 'flydata-core/query_job'
2
+ require 'flydata/parser/source_table' # Required for Marshal.load
3
+ require 'flydata/parser'
3
4
  require 'set'
5
+ require 'flydata/source'
6
+ require 'flydata/source/source_pos'
4
7
 
5
8
  module Flydata
6
9
  class SyncFileManager
@@ -9,12 +12,17 @@ module Flydata
9
12
  TABLE_POSITIONS_DIR = ENV['FLYDATA_TABLE_POSITIONS'] || File.join(FLYDATA_HOME, 'positions')
10
13
  SYNC_TABLE_POSITIONS = 0
11
14
 
12
- def initialize(data_entry)
15
+ def initialize(data_entry, source = nil)
13
16
  @data_entry = data_entry
17
+ @source = source #for Source dependent objects
14
18
  @table_position_files = {} # File objects keyed by table name
15
19
  @sync_table_positions_count = SYNC_TABLE_POSITIONS
16
20
  end
17
21
 
22
+ def source
23
+ @source
24
+ end
25
+
18
26
  def close
19
27
  @table_position_files.values.each {|f| f.close }
20
28
  @table_position_files = {}
@@ -29,21 +37,19 @@ module Flydata
29
37
  dump_file_path + ".pos"
30
38
  end
31
39
 
32
- def save_dump_pos(status, table_name, last_pos, binlog_pos, state = nil, substate = nil)
40
+ def save_dump_pos(status, table_name, last_pos, source_pos, state = nil, substate = nil)
33
41
  File.open(dump_pos_path, 'w') do |f|
34
- f.write(dump_pos_content(status, table_name, last_pos, binlog_pos, state, substate))
42
+ f.write(dump_pos_content(status, table_name, last_pos, source_pos, state, substate))
35
43
  end
36
44
  end
37
45
 
38
46
  def load_dump_pos
39
47
  path = dump_pos_path
40
48
  return {} unless File.exists?(path)
41
- items = File.open(path, 'r').readline.split("\t")
42
- raise "Invalid dump.pos file: #{path}" unless items.length >= 5 && items.length <= 7
43
- mysql_table = load_mysql_table_marshal_dump
44
- { status: items[0], table_name: items[1], last_pos: items[2].to_i,
45
- binlog_pos: {binfile: items[3], pos: items[4].to_i},
46
- state: items[5], substate: items[6], mysql_table: mysql_table}
49
+ content = File.open(path, 'r').readline
50
+ source_table = load_source_table_marshal_dump
51
+
52
+ dump_pos_content_to_hash(content).merge( { source_table: source_table} )
47
53
  end
48
54
 
49
55
  def load_generated_ddl(tables)
@@ -79,60 +85,73 @@ module Flydata
79
85
  new_tables
80
86
  end
81
87
 
82
- # MysqlTable marshal file
83
- def mysql_table_marshal_dump_path
84
- dump_file_path + ".mysql_table"
88
+ SOURCE_TABLE_EXT = "mysql_table"
89
+
90
+ # SourceTable marshal file
91
+ def source_table_marshal_dump_path
92
+ dump_file_path + ".#{SOURCE_TABLE_EXT}"
85
93
  end
86
94
 
87
- def save_mysql_table_marshal_dump(mysql_table)
88
- File.open(mysql_table_marshal_dump_path, 'w') do |f|
89
- f.write Marshal.dump(mysql_table)
95
+ def save_source_table_marshal_dump(source_table)
96
+ File.open(source_table_marshal_dump_path, 'w') do |f|
97
+ f.write Marshal.dump(source_table)
90
98
  end
91
99
  end
92
100
 
93
101
  # master binlog.pos file
94
- def save_binlog(binlog_pos)
95
- path = binlog_path
102
+ def save_source_pos(source_pos)
103
+ path = source_pos_path
96
104
  File.open(path, 'w') do |f|
97
- f.write(binlog_content(binlog_pos))
105
+ f.write(source_pos.to_s)
98
106
  end
99
107
  end
100
108
 
101
- def load_binlog(file_path = binlog_path)
109
+ def load_source_pos(file_path = source_pos_path)
102
110
  return nil unless File.exists?(file_path)
103
- f, pos = IO.read(file_path).strip.split("\t")
104
- return nil if f.nil? || f.empty? || pos.nil?
105
- { binfile: f, pos: pos.to_i }
111
+
112
+ source_pos_str = IO.read(file_path).strip
113
+ begin
114
+ context = source.source_pos
115
+ source_pos = context.create_source_pos(source_pos_str)
116
+ rescue RuntimeError
117
+ return nil
118
+ end
119
+ source_pos
106
120
  end
107
121
 
108
- def binlog_path
122
+ def source_pos_path
109
123
  File.join(FLYDATA_HOME, @data_entry['name'] + ".binlog.pos")
110
124
  end
111
125
 
112
- # sent binlog.pos file
113
- def save_sent_binlog(binlog_pos)
114
- File.open(sent_binlog_path, 'w') do |f|
115
- f.write(binlog_content(binlog_pos))
126
+ # sent source pos file (binlog.pos)
127
+ def save_sent_source_pos(source_pos)
128
+ File.open(sent_source_pos_path, 'w') do |f|
129
+ f.write(source_pos.to_s)
116
130
  end
117
131
  end
118
132
 
119
- def load_sent_binlog(file_path = sent_binlog_path)
133
+ def load_sent_source_pos(file_path = sent_source_pos_path)
120
134
  return nil unless File.exists?(file_path)
121
- f, pos = IO.read(file_path).strip.split("\t")
122
- return nil if f.nil? || f.empty? || pos.nil?
123
- { binfile: f, pos: pos.to_i }
135
+
136
+ source_pos_str = IO.read(file_path).strip
137
+ begin
138
+ source_pos = source.source_pos.create_source_pos(source_pos_str)
139
+ rescue RuntimeError
140
+ return nil
141
+ end
142
+ source_pos
124
143
  end
125
144
 
126
- def sent_binlog_path(master_binlog_path = binlog_path)
127
- validate_master_binlog_path(master_binlog_path)
128
- "#{master_binlog_path[0..-5]}.sent.pos"
145
+ def sent_source_pos_path(master_source_pos_path = source_pos_path)
146
+ validate_master_source_pos_path(master_source_pos_path)
147
+ "#{master_source_pos_path[0..-5]}.sent.pos"
129
148
  end
130
149
 
131
150
  # ssl_ca file path
132
- def ssl_ca_path(master_binlog_path = binlog_path)
133
- validate_master_binlog_path(master_binlog_path)
151
+ def ssl_ca_path(master_source_pos_path = source_pos_path)
152
+ validate_master_source_pos_path(master_source_pos_path)
134
153
  # <data-entry-name>.ssl_ca.pem
135
- "#{master_binlog_path[0..-12]}.ssl_ca.pem"
154
+ "#{master_source_pos_path[0..-12]}.ssl_ca.pem"
136
155
  end
137
156
 
138
157
  def save_ssl_ca(ssl_ca_content, path = ssl_ca_path)
@@ -142,10 +161,10 @@ module Flydata
142
161
  end
143
162
 
144
163
  # ssl_cipher file path
145
- def ssl_cipher_path(master_binlog_path = binlog_path)
146
- validate_master_binlog_path(master_binlog_path)
164
+ def ssl_cipher_path(master_source_pos_path = source_pos_path)
165
+ validate_master_source_pos_path(master_source_pos_path)
147
166
  # <data-entry-name>.ssl_cipher
148
- "#{master_binlog_path[0..-12]}.ssl_cipher"
167
+ "#{master_source_pos_path[0..-12]}.ssl_cipher"
149
168
  end
150
169
 
151
170
  def save_ssl_cipher(ssl_cipher_content, path = ssl_cipher_path)
@@ -176,12 +195,12 @@ module Flydata
176
195
  tables.map{|table| File.join(table_positions_dir_path, table + '.generated_ddl')}
177
196
  end
178
197
 
179
- def table_binlog_pos_paths(*tables)
198
+ def table_source_pos_paths(*tables)
180
199
  tables.empty? ? Dir.glob(File.join(table_positions_dir_path, '*.binlog.pos')) :
181
200
  tables.map{|table| File.join(table_positions_dir_path, table + '.binlog.pos')}
182
201
  end
183
202
 
184
- def table_binlog_pos_init_paths(*tables)
203
+ def table_source_pos_init_paths(*tables)
185
204
  tables.empty? ? Dir.glob(File.join(table_positions_dir_path, '*.binlog.pos.init')) :
186
205
  tables.map{|table| File.join(table_positions_dir_path, table + '.binlog.pos.init')}
187
206
  end
@@ -262,10 +281,11 @@ module Flydata
262
281
  tables: items[1].split(" ") }
263
282
  end
264
283
 
265
- def get_table_binlog_pos_init(table_name)
284
+ def get_table_source_pos_init(table_name)
266
285
  file = File.join(table_positions_dir_path, table_name + ".binlog.pos.init")
267
286
  return nil unless File.exists?(file)
268
- File.open(file, 'r').readline
287
+
288
+ source.source_pos.create_source_pos( File.open(file, 'r').readline )
269
289
  end
270
290
 
271
291
  def table_rev_file_path(table_name)
@@ -302,8 +322,8 @@ module Flydata
302
322
  def delete_table_control_files(*tables)
303
323
  files_to_delete = [
304
324
  table_position_file_paths(*tables),
305
- table_binlog_pos_paths(*tables),
306
- table_binlog_pos_init_paths(*tables),
325
+ table_source_pos_paths(*tables),
326
+ table_source_pos_init_paths(*tables),
307
327
  table_rev_file_paths(*tables),
308
328
  table_ddl_file_paths(*tables)
309
329
  ]
@@ -327,7 +347,7 @@ module Flydata
327
347
  files_to_delete = [
328
348
  dump_file_path,
329
349
  dump_pos_path,
330
- mysql_table_marshal_dump_path,
350
+ source_table_marshal_dump_path,
331
351
  sync_info_file,
332
352
  stats_path
333
353
  ]
@@ -338,8 +358,8 @@ module Flydata
338
358
 
339
359
  def delete_master_position_files
340
360
  files_to_delete = [
341
- binlog_path,
342
- sent_binlog_path,
361
+ source_pos_path,
362
+ sent_source_pos_path,
343
363
  lock_pid_file,
344
364
  ]
345
365
  files_to_delete.flatten.each do |file_to_delete|
@@ -348,7 +368,7 @@ module Flydata
348
368
  end
349
369
 
350
370
 
351
- def delete_table_binlog_pos(table_name)
371
+ def delete_table_source_pos(table_name)
352
372
  file = File.join(table_positions_dir_path, table_name + ".binlog.pos")
353
373
  if File.exists?(file)
354
374
  FileUtils.rm(file, :force => true)
@@ -357,7 +377,7 @@ module Flydata
357
377
  end
358
378
  end
359
379
 
360
- def save_table_binlog_pos(tables, binlog_pos, options = {})
380
+ def save_table_source_pos(tables, source_pos, options = {})
361
381
  dest_dir = case options[:destination]
362
382
  when :positions; table_positions_dir_path
363
383
  when :dump; dump_dir
@@ -368,18 +388,28 @@ module Flydata
368
388
  tables.each do |table_name|
369
389
  file = File.join(dest_dir, table_name + ".binlog.pos")
370
390
  File.open(file, "w") do |f|
371
- f.write(binlog_content(binlog_pos))
391
+ f.write(source_pos.to_s)
372
392
  end
373
393
  end
374
394
  end
375
395
 
376
- def get_table_binlog_pos(table_name)
396
+ def get_table_source_pos(table_name)
397
+ source_pos_str = get_table_source_raw_pos(table_name)
398
+ return nil unless source_pos_str
399
+
400
+ source.source_pos.create_source_pos( source_pos_str )
401
+ end
402
+
403
+ def get_table_source_raw_pos(table_name) #returns String. interface for fluentd
377
404
  file = File.join(table_positions_dir_path, table_name + ".binlog.pos")
378
405
  return nil unless File.exists?(file)
406
+
379
407
  File.open(file, 'r').readline
380
408
  end
381
409
 
382
- def install_table_binlog_files(tables)
410
+
411
+
412
+ def install_table_source_pos_files(tables)
383
413
  FileUtils.mkdir_p(table_positions_dir_path) unless Dir.exists?(table_positions_dir_path)
384
414
  tables.each do |table_name|
385
415
  file_name = table_name + ".binlog.pos"
@@ -403,7 +433,7 @@ module Flydata
403
433
  FileUtils.mkdir_p(backup_dir) unless Dir.exists?(backup_dir)
404
434
  dest_dir = File.join(backup_dir, Time.now.strftime("%Y%m%d%H%M%S"))
405
435
  FileUtils.mkdir(dest_dir)
406
- %w(info pos stats mysql_table).each do |ext|
436
+ ['info', 'pos', 'stats', SOURCE_TABLE_EXT].each do |ext|
407
437
  FileUtils.mv(Dir.glob("#{dump_dir}/*.#{ext}"), dest_dir)
408
438
  end
409
439
  end
@@ -435,29 +465,58 @@ module Flydata
435
465
  end
436
466
  end
437
467
 
438
- def dump_pos_content(status, table_name, last_pos, binlog_pos, state = nil, substate = nil)
439
- [status, table_name, last_pos, binlog_content(binlog_pos), state, substate].join("\t")
468
+ def dump_pos_content(status, table_name, last_pos, source_pos, state = nil, substate = nil)
469
+ [status, table_name, last_pos, source_pos.to_s, state, substate].join("\t")
440
470
  end
441
471
 
442
- def binlog_content(binlog_pos)
443
- binlog_pos.kind_of?(Hash) ?
444
- [binlog_pos[:binfile], binlog_pos[:pos]].join("\t")
445
- : binlog_pos
472
+ def dump_pos_content_to_hash(content)
473
+ items = content.split("\t",-1) # -1 means,(1) there is no limit to the number of fields returned
474
+ # (2) trailing null fields are not suppressed.
475
+ raise "Invalid dump.pos file: #{path}" unless items.length >= 6
476
+
477
+ status = items[0]
478
+ table_name = items[1]
479
+ last_pos = items[2].to_i
480
+
481
+ source_pos_str = items[3..-3].join("\t")
482
+ context = source.source_pos
483
+ source_pos = context.create_source_pos(source_pos_str)
484
+
485
+ state = get_parse_state(items[-2])
486
+ substate = get_parse_state(items[-1])
487
+
488
+ { status: status, table_name: table_name, last_pos: last_pos,
489
+ source_pos: source_pos,
490
+ state: state, substate: substate }
491
+ end
492
+
493
+ def get_parse_state(state)
494
+ state.empty? ? nil : state
446
495
  end
447
496
 
448
- def load_mysql_table_marshal_dump
449
- path = mysql_table_marshal_dump_path
497
+ def load_source_table_marshal_dump
498
+ path = source_table_marshal_dump_path
450
499
  return nil unless File.exists?(path)
451
500
  Marshal.load(File.open(path, 'r'))
452
501
  end
453
502
 
503
+ OLD_DUMP_DIR_PROPERTY = 'mysqldump_dir'
504
+ DUMP_DIR_PROPERTY = 'dump_dir'
454
505
  def dump_dir
455
506
  pref = @data_entry['mysql_data_entry_preference']
456
- dump_dir = if pref and pref['mysqldump_dir']
457
- pref['mysqldump_dir']
458
- else
459
- nil
460
- end
507
+ dump_dir = nil
508
+ dump_dir_property = DUMP_DIR_PROPERTY
509
+
510
+ if pref
511
+ # check the old property for backward compatibility
512
+ [DUMP_DIR_PROPERTY, OLD_DUMP_DIR_PROPERTY].each do |prop|
513
+ if pref[prop]
514
+ dump_dir_property = prop
515
+ dump_dir = pref[prop]
516
+ break
517
+ end
518
+ end
519
+ end
461
520
  if dump_dir
462
521
  dump_dir = dump_dir.dup
463
522
  dump_dir[0] = ENV['HOME'] if dump_dir.match(/^~$|^~\//)
@@ -465,15 +524,15 @@ module Flydata
465
524
  dump_dir = DUMP_DIR.dup
466
525
  end
467
526
  if File.exists?(dump_dir) and not Dir.exists?(dump_dir)
468
- raise "'mysqldump_dir'(#{dump_dir}) must be a directory."
527
+ raise "'#{dump_dir_property}'(#{dump_dir}) must be a directory."
469
528
  end
470
529
  FileUtils.mkdir_p(dump_dir) unless Dir.exists?(dump_dir)
471
530
  dump_dir
472
531
  end
473
532
 
474
- def validate_master_binlog_path(master_binlog_path)
475
- unless master_binlog_path && master_binlog_path.end_with?('binlog.pos')
476
- raise ArgumentError.new("Invalid binlog path. binlog path needs to end with 'binlog.pos'")
533
+ def validate_master_source_pos_path(master_source_pos_path)
534
+ unless master_source_pos_path && master_source_pos_path.end_with?('binlog.pos')
535
+ raise ArgumentError.new("Invalid source position path. Source position path needs to end with 'binlog.pos'")
477
536
  end
478
537
  end
479
538
  end