flydata 0.2.30 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: acad4ae7202b7fc525478de91925ef4ee0a24fdd
4
- data.tar.gz: 63cf3ac658afa5be37ed7b2a85be476de280c56f
3
+ metadata.gz: 68f311d20207752e80dd5fb47b905b085e840520
4
+ data.tar.gz: 6bfa38fa63a7db7e1f4b7109324017e99c82c117
5
5
  SHA512:
6
- metadata.gz: fb7391185d4f9797817f0628ec46f5b9cce0ef1680fb843d0181f97dd18450c059d6b6614b7ef98e8ee88dfac171933561e448a2ca1b403665563b27b5d005a8
7
- data.tar.gz: 7407fd538bbd7678ae19d5ddaa9dcc5b13159555b8c7b82a788c821fb70855594f49848eb141ec7a44982eb164dd63738e63a9714ed132b5b02ff2caab948d4f
6
+ metadata.gz: 01469b9c9b268bc8dad0bda81a3dbcc3a98a55901108cac17b50a6688313485f1d7cdd8a01b26ea20cbea0d8fa6f4c096055394f55cea58ee59a949acb2963fe
7
+ data.tar.gz: cde53114405b00f034e7444fd0b9ba9df9519a2cd3979eade6a99d48e80e326615a1ba16fb0d5c014c51d23272ca5cf2257b2f318135ad6efef858f4d6d4479b
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.30
1
+ 0.3.0
@@ -8,4 +8,9 @@ require 'flydata'
8
8
 
9
9
  args = ARGV.dup
10
10
  ARGV.clear # for 'gets'
11
- Flydata::Cli.new(args).run
11
+ begin
12
+ Flydata::Cli.new(args).run
13
+ rescue Interrupt
14
+ # Suppress stacktrace upon Ctrl-C quit
15
+ puts
16
+ end
@@ -28,37 +28,37 @@ class MysqlTableDef
28
28
  end
29
29
 
30
30
  TYPE_MAP_M2F = {
31
- 'bigint' => {type: 'int8'},
32
- 'binary' => {type: 'binary', override: PROC_override_varbinary},
33
- 'bit' => {type: 'bit'},
31
+ 'bigint' => {type: 'int8', def_width: '20'},
32
+ 'binary' => {type: 'binary', def_width: '1', override: PROC_override_varbinary},
33
+ 'bit' => {type: 'bit', def_width: '1'},
34
34
  'blob' => {type: 'varbinary(65535)'},
35
- 'bool' => {type: 'int1'},
36
- 'boolean' => {type: 'int1'},
37
- 'char' => {type: 'varchar', override: PROC_override_varchar},
35
+ 'bool' => {type: 'int1', def_width: '1'},
36
+ 'boolean' => {type: 'int1', def_width: '1'},
37
+ 'char' => {type: 'varchar', def_width: '1', override: PROC_override_varchar},
38
38
  'date' => {type: 'date'},
39
39
  'datetime' => {type: 'datetime'},
40
- 'dec' => {type: 'numeric'},
41
- 'decimal' => {type: 'numeric'},
40
+ 'dec' => {type: 'numeric', def_width: '10,0'},
41
+ 'decimal' => {type: 'numeric', def_width: '10,0'},
42
42
  'double' => {type: 'float8'},
43
43
  'double precision' => {type: 'float8'},
44
44
  'enum' => {type: 'enum'},
45
- 'fixed' => {type: 'numeric'},
45
+ 'fixed' => {type: 'numeric', def_width: '10,0'},
46
46
  'float' => {type: 'float4'},
47
- 'int' => {type: 'int4'},
48
- 'integer' => {type: 'int4'},
47
+ 'int' => {type: 'int4', def_width: '11'},
48
+ 'integer' => {type: 'int4', def_width: '11'},
49
49
  'longblob' => {type: 'varbinary(4294967295)'},
50
50
  'longtext' => {type: 'text'},
51
51
  'mediumblob' => {type: 'varbinary(16777215)'},
52
- 'mediumint' => {type: 'int3'},
52
+ 'mediumint' => {type: 'int3', def_width: '9'},
53
53
  'mediumtext' => {type: 'text'},
54
- 'numeric' => {type: 'numeric'},
54
+ 'numeric' => {type: 'numeric', def_width: '10,0'},
55
55
  'set' => {type: 'set'},
56
- 'smallint' => {type: 'int2'},
56
+ 'smallint' => {type: 'int2', def_width: '6'},
57
57
  'text' => {type: 'text'},
58
58
  'time' => {type: 'time'},
59
59
  'timestamp' => {type: 'datetime'},
60
60
  'tinyblob' => {type: 'varbinary(255)'},
61
- 'tinyint' => {type: 'int1'},
61
+ 'tinyint' => {type: 'int1', def_width: '4'},
62
62
  'tinytext' => {type: 'text'},
63
63
  'varbinary' => {type: 'varbinary', override: PROC_override_varbinary},
64
64
  'varchar' => {type: 'varchar', override: PROC_override_varchar},
@@ -69,6 +69,9 @@ class MysqlTableDef
69
69
  flydata_type = type_hash[:type]
70
70
  if /^#{mysql_type}\(|^#{mysql_type}$/.match(type)
71
71
  ret_type = type.gsub(/^#{mysql_type}/, flydata_type)
72
+ if type_hash.has_key?(:def_width) && !/\(.+\)/.match(ret_type)
73
+ ret_type += "(#{type_hash[:def_width]})"
74
+ end
72
75
  if type_hash[:override]
73
76
  ret_type = type_hash[:override].call(ret_type, mysql_type, flydata_type)
74
77
  end
@@ -199,6 +199,138 @@ describe MysqlTableDef do
199
199
  end
200
200
  end
201
201
  end
202
+
203
+ describe '.convert_to_flydata_type' do
204
+ subject { described_class.convert_to_flydata_type(mysql_type) }
205
+ shared_examples "converting the mysql data type to the expected flydata type" do
206
+ # Use the context description as the value of "mysql_type"
207
+ # RSpec.current_example.meatadata[:example_group] => the shared_examples "converting the mysql data type to the expected flydata type"
208
+ # [:parent_example_group] => the context including the shared examples (e.g. context "bigint")
209
+ # [:description] => the name of the example group (e.g. "bigint")
210
+ let(:mysql_type) { RSpec.current_example.metadata[:example_group][:parent_example_group][:description] }
211
+ it do
212
+ expect(subject).to eq flydata_type
213
+ end
214
+ end
215
+ context "with no-width mysql data type" do
216
+ context "bigint" do
217
+ let(:flydata_type) { 'int8(20)' }
218
+ it_behaves_like "converting the mysql data type to the expected flydata type"
219
+ end
220
+ context "binary" do
221
+ let(:flydata_type) { 'binary(4)' }
222
+ it_behaves_like "converting the mysql data type to the expected flydata type"
223
+ end
224
+ context "bit" do
225
+ let(:flydata_type) { 'bit(1)' }
226
+ it_behaves_like "converting the mysql data type to the expected flydata type"
227
+ end
228
+ context "blob" do
229
+ let(:flydata_type) { 'varbinary(65535)' }
230
+ it_behaves_like "converting the mysql data type to the expected flydata type"
231
+ end
232
+ context "bool" do
233
+ let(:flydata_type) { 'int1(1)' }
234
+ it_behaves_like "converting the mysql data type to the expected flydata type"
235
+ end
236
+ context "boolean" do
237
+ let(:flydata_type) { 'int1(1)' }
238
+ it_behaves_like "converting the mysql data type to the expected flydata type"
239
+ end
240
+ context "char" do
241
+ let(:flydata_type) { 'varchar(3)' }
242
+ it_behaves_like "converting the mysql data type to the expected flydata type"
243
+ end
244
+ context "date" do
245
+ let(:flydata_type) { 'date' }
246
+ it_behaves_like "converting the mysql data type to the expected flydata type"
247
+ end
248
+ context "datetime" do
249
+ let(:flydata_type) { 'datetime' }
250
+ it_behaves_like "converting the mysql data type to the expected flydata type"
251
+ end
252
+ context "dec" do
253
+ let(:flydata_type) { 'numeric(10,0)' }
254
+ it_behaves_like "converting the mysql data type to the expected flydata type"
255
+ end
256
+ context "decimal" do
257
+ let(:flydata_type) { 'numeric(10,0)' }
258
+ it_behaves_like "converting the mysql data type to the expected flydata type"
259
+ end
260
+ context "double" do
261
+ let(:flydata_type) { 'float8' }
262
+ it_behaves_like "converting the mysql data type to the expected flydata type"
263
+ end
264
+ context "fixed" do
265
+ let(:flydata_type) { 'numeric(10,0)' }
266
+ it_behaves_like "converting the mysql data type to the expected flydata type"
267
+ end
268
+ context "float" do
269
+ let(:flydata_type) { 'float4' }
270
+ it_behaves_like "converting the mysql data type to the expected flydata type"
271
+ end
272
+ context "int" do
273
+ let(:flydata_type) { 'int4(11)' }
274
+ it_behaves_like "converting the mysql data type to the expected flydata type"
275
+ end
276
+ context "integer" do
277
+ let(:flydata_type) { 'int4(11)' }
278
+ it_behaves_like "converting the mysql data type to the expected flydata type"
279
+ end
280
+ context "longblob" do
281
+ let(:flydata_type) { 'varbinary(4294967295)' }
282
+ it_behaves_like "converting the mysql data type to the expected flydata type"
283
+ end
284
+ context "longtext" do
285
+ let(:flydata_type) { 'text' }
286
+ it_behaves_like "converting the mysql data type to the expected flydata type"
287
+ end
288
+ context "mediumblob" do
289
+ let(:flydata_type) { 'varbinary(16777215)' }
290
+ it_behaves_like "converting the mysql data type to the expected flydata type"
291
+ end
292
+ context "mediumint" do
293
+ let(:flydata_type) { 'int3(9)' }
294
+ it_behaves_like "converting the mysql data type to the expected flydata type"
295
+ end
296
+ context "mediumtext" do
297
+ let(:flydata_type) { 'text' }
298
+ it_behaves_like "converting the mysql data type to the expected flydata type"
299
+ end
300
+ context "numeric" do
301
+ let(:flydata_type) { 'numeric(10,0)' }
302
+ it_behaves_like "converting the mysql data type to the expected flydata type"
303
+ end
304
+ context "smallint" do
305
+ let(:flydata_type) { 'int2(6)' }
306
+ it_behaves_like "converting the mysql data type to the expected flydata type"
307
+ end
308
+ context "text" do
309
+ let(:flydata_type) { 'text' }
310
+ it_behaves_like "converting the mysql data type to the expected flydata type"
311
+ end
312
+ context "time" do
313
+ let(:flydata_type) { 'time' }
314
+ it_behaves_like "converting the mysql data type to the expected flydata type"
315
+ end
316
+ context "timestamp" do
317
+ let(:flydata_type) { 'datetime' }
318
+ it_behaves_like "converting the mysql data type to the expected flydata type"
319
+ end
320
+ context "tinyblob" do
321
+ let(:flydata_type) { 'varbinary(255)' }
322
+ it_behaves_like "converting the mysql data type to the expected flydata type"
323
+ end
324
+ context "tinyint" do
325
+ let(:flydata_type) { 'int1(4)' }
326
+ it_behaves_like "converting the mysql data type to the expected flydata type"
327
+ end
328
+ context "tinytext" do
329
+ let(:flydata_type) { 'text' }
330
+ it_behaves_like "converting the mysql data type to the expected flydata type"
331
+ end
332
+ end
333
+ end
202
334
  end
203
335
 
204
336
  end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: flydata 0.2.30 ruby lib
5
+ # stub: flydata 0.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "flydata"
9
- s.version = "0.2.30"
9
+ s.version = "0.3.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Koichi Fujikawa", "Masashi Miyazaki", "Matthew Luu", "Mak Inada", "Sriram NS"]
14
- s.date = "2015-01-26"
14
+ s.date = "2015-02-11"
15
15
  s.description = "FlyData Agent"
16
16
  s.email = "sysadmin@flydata.com"
17
17
  s.executables = ["fdmysqldump", "flydata", "serverinfo"]
@@ -93,6 +93,7 @@ Gem::Specification.new do |s|
93
93
  "lib/flydata/compatibility_check.rb",
94
94
  "lib/flydata/credentials.rb",
95
95
  "lib/flydata/cron.rb",
96
+ "lib/flydata/errors.rb",
96
97
  "lib/flydata/fluent-plugins/idle_event_detector.rb",
97
98
  "lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb",
98
99
  "lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb",
@@ -149,7 +150,7 @@ Gem::Specification.new do |s|
149
150
  ]
150
151
  s.homepage = "http://flydata.com/"
151
152
  s.licenses = ["All right reserved."]
152
- s.rubygems_version = "2.2.2"
153
+ s.rubygems_version = "2.4.3"
153
154
  s.summary = "FlyData Agent"
154
155
 
155
156
  if s.respond_to? :specification_version then
@@ -1,5 +1,6 @@
1
1
  require 'slop'
2
2
  require_relative 'command_logger'
3
+ require_relative 'errors'
3
4
 
4
5
  module Flydata
5
6
  class Cli
@@ -42,15 +43,16 @@ module Flydata
42
43
  cmd_obj = cmd_cls.new(options)
43
44
  sub_cmd ? cmd_obj.send(sub_cmd,*@args) : cmd_obj.run(*@args)
44
45
  else
45
- $stderr.puts usage_text(false)
46
+ $stderr.puts usage_text
46
47
  return
47
48
  end
48
49
  rescue => e
49
50
  #raise e
50
- $stderr.puts "! #{e.to_s}"
51
51
  $stderr.puts
52
52
  $stderr.puts
53
- $stderr.puts usage_text
53
+ $stderr.puts "!! #{e.to_s}"
54
+ $stderr.puts
55
+ $stderr.puts e.respond_to?(:description) ? e.description : AgentError.description
54
56
  log_error_with_backtrace('Error occured during command.', {error: e, args: @args})
55
57
  raise e if FLYDATA_DEBUG
56
58
  exit 1
@@ -93,8 +93,13 @@ What's next?
93
93
  elsif has_registered_redshift_mysql_data_entries?
94
94
  de = retrieve_data_entries.first
95
95
  if File.exists?(Flydata::FileUtil::SyncFileManager.new(de).binlog_path)
96
- Flydata::Command::Sender.new.stop(quiet: true)
97
- true
96
+ sender = Flydata::Command::Sender.new
97
+ if sender.process_exist?
98
+ sender.stop(quiet: true)
99
+ true
100
+ else
101
+ false
102
+ end
98
103
  else
99
104
  last_message = INITIAL_SYNC_MESSAGE_TEMPLATE
100
105
  false
@@ -13,9 +13,11 @@ require 'flydata-core/table_def'
13
13
 
14
14
  module Flydata
15
15
  module Command
16
+
16
17
  class Sync < Base
17
18
  include Helpers
18
19
  INSERT_PROGRESS_INTERVAL = 1000
20
+ SERVER_DATA_PROCESSING_TIMEOUT = 600 # seconds
19
21
 
20
22
  # for dump.pos file
21
23
  STATUS_PARSING = 'PARSING'
@@ -102,8 +104,21 @@ module Flydata
102
104
  de = retrieve_sync_data_entry unless de
103
105
  de = load_sync_info(de,tables)
104
106
  validate_initial_sync_status(de, tables)
105
- flush_buffer_and_stop unless @initial_sync
106
- sync_mysql_to_redshift(de)
107
+ begin
108
+ flush_buffer_and_stop unless @initial_sync
109
+ sync_mysql_to_redshift(de)
110
+ rescue ServerDataProcessingTimeout => e
111
+ ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
112
+ ee.description = <<EOS
113
+ Data processing is taking more than expected. Please contact support@flydata.com to check the system status.
114
+ Once checked, you can resume sync with the following command.
115
+
116
+ flydata start
117
+
118
+ EOS
119
+ ee.set_backtrace e.backtrace
120
+ raise ee
121
+ end
107
122
  complete
108
123
  end
109
124
 
@@ -114,7 +129,17 @@ module Flydata
114
129
  end
115
130
 
116
131
  def flush
117
- flush_buffer_and_stop
132
+ begin
133
+ flush_buffer_and_stop
134
+ rescue ServerDataProcessingTimeout => e
135
+ ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
136
+ ee.description = <<EOS
137
+ Data processing is taking more than expected. Please contact support@flydata.com to check the system status.
138
+
139
+ EOS
140
+ ee.set_backtrace e.backtrace
141
+ raise ee
142
+ end
118
143
  log_info_stdout("Buffers have been flushed and the sender process has been stopped.")
119
144
  end
120
145
 
@@ -136,7 +161,20 @@ module Flydata
136
161
  all_tables = de['mysql_data_entry_preference']['tables']
137
162
  verify_input_tables(tables, all_tables)
138
163
 
139
- wait_for_server_buffer
164
+ begin
165
+ wait_for_server_buffer(SERVER_DATA_PROCESSING_TIMEOUT)
166
+ rescue ServerDataProcessingTimeout => e
167
+ ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
168
+ ee.description = <<EOS
169
+ Data processing is taking more than expected. Please contact support@flydata.com to check the system status.
170
+ Once checked, you can continue sync reset with the following command
171
+
172
+ flydata sync:reset #{tables.empty? ? '' : tables.join(" ")}
173
+
174
+ EOS
175
+ ee.set_backtrace e.backtrace
176
+ raise ee
177
+ end
140
178
  cleanup_sync_server(de, tables) unless opts.client?
141
179
  sync_fm = Flydata::FileUtil::SyncFileManager.new(de)
142
180
  delete_files = [
@@ -158,25 +196,41 @@ module Flydata
158
196
  log_info_stdout("Reset completed successfully.")
159
197
  end
160
198
 
161
- def wait_for_server_buffer
199
+ def wait_for_server_buffer(timeout = 0)
200
+ start_time = Time.now
162
201
  log_info_stdout("Waiting for the server buffer to get empty.")
202
+ prev_message =nil
163
203
  while (status = check) && (status['state'] == 'processing')
204
+ prev_message = status['message']
205
+ if timeout > 0 && Time.now - start_time > timeout
206
+ raise ServerDataProcessingTimeout.new
207
+ end
164
208
  print_progress(status)
165
209
  sleep 10
166
210
  end
167
211
  end
168
212
 
169
- def wait_for_server_data_processing
213
+ def wait_for_server_data_processing(timeout = 0)
170
214
  state = :PROCESS
215
+ start_time = Time.now
171
216
  log_info_stdout("Uploading data to Redshift...")
172
217
  sleep 10
173
218
  status = nil
219
+ prev_message =nil
174
220
  while (status = check)
175
221
  if state == :PROCESS && status['state'] == 'uploading'
176
222
  log_info_stdout(" -> Done")
177
223
  state = :UPLOAD
178
224
  log_info_stdout("Finishing data upload...")
179
225
  end
226
+ if status['message'] != prev_message
227
+ # making some progress. Reset timer
228
+ start_time = Time.now
229
+ end
230
+ prev_message = status['message']
231
+ if timeout > 0 && Time.now - start_time > timeout
232
+ raise ServerDataProcessingTimeout.new
233
+ end
180
234
  print_progress(status)
181
235
  sleep 10
182
236
  end
@@ -606,7 +660,7 @@ EOM
606
660
  return unless dump_pos_info[:status] == STATUS_WAITING
607
661
  binlog_pos = dump_pos_info[:binlog_pos]
608
662
 
609
- wait_for_server_data_processing
663
+ wait_for_server_data_processing(SERVER_DATA_PROCESSING_TIMEOUT)
610
664
  tables = de['mysql_data_entry_preference']['tables']
611
665
  sync_fm.save_table_binlog_pos(tables, binlog_pos)
612
666
  sync_fm.save_dump_pos(STATUS_COMPLETE, '', -1, binlog_pos)
@@ -670,7 +724,7 @@ Thank you for using FlyData!
670
724
  def flush_buffer_and_stop
671
725
  sender = Flydata::Command::Sender.new
672
726
  sender.flush_client_buffer
673
- wait_for_server_data_processing
727
+ wait_for_server_data_processing(SERVER_DATA_PROCESSING_TIMEOUT)
674
728
  sender.stop(quiet: true)
675
729
  end
676
730
  end
@@ -137,8 +137,8 @@ module Flydata
137
137
  end
138
138
  end
139
139
 
140
- def check_mysql_row_mode_compat
141
- sys_var_to_check = {'@@binlog_format'=>'ROW', '@@binlog_checksum'=>'NONE', '@@log_bin_use_v1_row_events'=>1}
140
+ def check_mysql_parameters_compat
141
+ sys_var_to_check = {'@@binlog_format'=>'ROW', '@@binlog_checksum'=>'NONE', '@@log_bin_use_v1_row_events'=>1, '@@log_slave_updates'=>1}
142
142
  errors={}
143
143
 
144
144
  client = Mysql2::Client.new(@db_opts)
@@ -0,0 +1,34 @@
1
+ module Flydata
2
+
3
+ class AgentError < StandardError
4
+ def self.description
5
+ text = <<-EOM
6
+ Fix the issue and try again. If the problem continues, please contact support@flydata.com
7
+
8
+ EOM
9
+
10
+ flydata_log = File.join(FLYDATA_HOME, 'flydata.log')
11
+ if File.exists?(flydata_log)
12
+ text += <<-EOM
13
+ Also check the Agent log.
14
+ Log path: #{flydata_log}
15
+ EOM
16
+ end
17
+ text
18
+ end
19
+
20
+ def description
21
+ if instance_variable_defined?(:@description) && @description
22
+ @description
23
+ else
24
+ self.class.description
25
+ end
26
+ end
27
+
28
+ attr_writer :description
29
+ end
30
+
31
+ class ServerDataProcessingTimeout < AgentError
32
+ end
33
+
34
+ end
@@ -3,6 +3,7 @@ require_relative 'binlog_record_handler'
3
3
  module Mysql
4
4
  class DmlRecordHandler < BinlogRecordHandler
5
5
  ROW = :row
6
+ OLD = :old
6
7
  INTEGER_TYPES = {'TINY' => 1,
7
8
  'SHORT' => 2,
8
9
  'INT24' => 3,
@@ -36,7 +37,8 @@ module Mysql
36
37
 
37
38
  def emit_update(record)
38
39
  emit_rows(:update, record) do |row|
39
- row.last # For update, row has two arrays (old and new values) Use new values
40
+ # For update, row has two arrays (old and new values)
41
+ { OLD => row.first, ROW => row.last }
40
42
  end
41
43
  end
42
44
 
@@ -44,10 +46,13 @@ module Mysql
44
46
  emit_record(type, record) do |opt|
45
47
  table_name = record['table_name']
46
48
  records = record["rows"].collect do |row|
47
- row = yield(row) if block_given? # Give the caller a chance to generate the correct row
48
- { ROW => convert_to_flydata_row_format(table_name, row) }
49
+ row_values = { ROW => row }
50
+ row_values = yield(row) if block_given? # Give the caller a chance to generate the correct row values
51
+ row_types = row_values.keys
52
+ row_kinds = row_types.inject({}) {|m, k| m[k] = convert_to_flydata_row_format(table_name, row_values[k]); m}
53
+ encode_signless_integer(row_kinds, record["columns"], row_types)
54
+ row_kinds
49
55
  end
50
- encode_signless_integer(records, record["columns"])
51
56
  records
52
57
  end
53
58
  end
@@ -70,19 +75,19 @@ module Mysql
70
75
  end
71
76
  end
72
77
 
73
- def encode_signless_integer(records, column_types)
74
- records.each do |record|
75
- record[ROW].keys.each do |position|
78
+ def encode_signless_integer(record, column_types, row_types)
79
+ row_types.each do |row_type|
80
+ record[row_type].keys.each do |position|
76
81
  index = position.to_i - 1
77
82
  column_type = column_types[index]
78
83
  if INTEGER_TYPES.keys.include?(column_type)
79
84
  # It's a signless integer.
80
- intval = record[ROW][position]
85
+ intval = record[row_type][position]
81
86
  next unless (intval.kind_of?(Numeric) || intval =~ /^-?[\d]+$/)
82
87
  width = INTEGER_TYPES[column_type] * 2 # * 2 because a single byte requires two characters (e.g. ff)
83
88
  signless_val = SIGNLESS_INTEGER_PREFIX
84
89
  signless_val += sprintf("%0#{width}x", intval).gsub(/\.\.f/, 'f' * width).slice(-width..-1)
85
- record[ROW][position] = signless_val
90
+ record[row_type][position] = signless_val
86
91
  end
87
92
  end
88
93
  end
@@ -12,25 +12,9 @@ module Flydata
12
12
  [klass, method]
13
13
  end
14
14
 
15
- def usage_text(err = true)
15
+ def usage_text
16
16
  text = ""
17
17
 
18
- if err
19
- text += <<-EOM
20
- Fix the issue and try again. If the problem continues, please contact support@flydata.com
21
-
22
- EOM
23
-
24
- flydata_log = File.join(FLYDATA_HOME, 'flydata.log')
25
- if File.exists?(flydata_log)
26
- text += <<-EOM
27
- Also check the Agent log.
28
- Log path: #{flydata_log}
29
- EOM
30
- end
31
- end
32
-
33
- text += ""
34
18
  text += '-' * 64
35
19
  text += "\n"
36
20
  text += <<-EOM
@@ -27,7 +27,7 @@ module Flydata
27
27
  context 'with options' do
28
28
  let(:options) { %w(-a --host-name localhost) }
29
29
  it 'returns with an error' do
30
- expect($stderr).to receive(:puts).with('! Unknown options -a, --host-name').once
30
+ expect($stderr).to receive(:puts).with('!! Unknown options -a, --host-name').once
31
31
  allow($stderr).to receive(:puts)
32
32
 
33
33
  expect{ subject.run }.to terminate.with_code(1)
@@ -62,7 +62,7 @@ module Flydata
62
62
  context 'with optionss' do
63
63
  let(:options) { %w(-a --host-name localhost) }
64
64
  it 'returns an error' do
65
- expect($stderr).to receive(:puts).with('! Unknown options -a, --host-name').once
65
+ expect($stderr).to receive(:puts).with('!! Unknown options -a, --host-name').once
66
66
  allow($stderr).to receive(:puts)
67
67
 
68
68
  expect{ subject.run }.to terminate.with_code(1)
@@ -164,9 +164,10 @@ EOT
164
164
  rows = [rows] unless rows.kind_of?(Array)
165
165
  @seq ||= TEST_SEQUENCE_NUM
166
166
  records = rows.collect do |row|
167
+ record = row.kind_of?(Hash) && row.keys.include?(:row) ? row : { row: row }
167
168
  @seq += 1
168
- { :type=>type, :table_name=>table, :respect_order=>true, :seq=>@seq,
169
- :src_pos=>"#{binlog_file}\t#{position}", :table_rev=>1, :row=>row }
169
+ record.merge({ :type=>type, :table_name=>table, :respect_order=>true,
170
+ :seq=>@seq, :src_pos=>"#{binlog_file}\t#{position}", :table_rev=>1 })
170
171
  end
171
172
  expect_emitted_records(event, records)
172
173
  end
@@ -289,21 +290,30 @@ EOT
289
290
  context 'when received update event' do
290
291
  it do
291
292
  expect_emitted_records_with_rows(update_event, :update, TEST_TABLE, 2528, "mysql-bin.000048",
292
- [{"1"=>"0SL00000001", "2"=>"wow"}, {"1"=>"0SL00000003", "2"=>"fuga"}])
293
+ [{old:{"1"=>"0SL00000001", "2"=>"foo"},
294
+ row:{"1"=>"0SL00000001", "2"=>"wow"}},
295
+ {old:{"1"=>"0SL00000003", "2"=>"hoge"},
296
+ row:{"1"=>"0SL00000003", "2"=>"fuga"}}])
293
297
  end
294
298
  end
295
299
 
296
300
  context 'when received update event with two byte utf8 chars' do
297
301
  it do
298
302
  expect_emitted_records_with_rows(update_two_byte_event, :update, TEST_TABLE, 2528, "mysql-bin.000048",
299
- [{"1"=>"0SL00000001", "2"=>"∑ø∑"}, {"1"=>"0SL00000003", "2"=>"fügå"}])
303
+ [{old:{"1"=>"0SL00000001", "2"=>"føø"},
304
+ row:{"1"=>"0SL00000001", "2"=>"∑ø∑"}},
305
+ {old:{"1"=>"0SL00000003", "2"=>"høgé"},
306
+ row:{"1"=>"0SL00000003", "2"=>"fügå"}}])
300
307
  end
301
308
  end
302
309
 
303
310
  context 'when received update event with three byte utf8 chars' do
304
311
  it do
305
312
  expect_emitted_records_with_rows(update_three_byte_event, :update, TEST_TABLE, 2528, "mysql-bin.000048",
306
- [{"1"=>"0SL00000001", "2"=>"很兴奋"}, {"1"=>"0SL00000003", "2"=>"興奮虎"}])
313
+ [{old:{"1"=>"0SL00000001", "2"=>"富无无"},
314
+ row:{"1"=>"0SL00000001", "2"=>"很兴奋"}},
315
+ {old:{"1"=>"0SL00000003", "2"=>"切实切实"},
316
+ row:{"1"=>"0SL00000003", "2"=>"興奮虎"}}])
307
317
  end
308
318
  end
309
319
 
@@ -317,7 +327,7 @@ EOT
317
327
  table_rev: 2, # increment revision
318
328
  seq: 2,
319
329
  actions: [{
320
- action: :add_column, column: "sum", :type=>'int4', :query=>'add column sum integer'}],
330
+ action: :add_column, column: "sum", :type=>'int4(11)', :query=>'add column sum integer'}],
321
331
  })
322
332
  end
323
333
  end
@@ -395,7 +405,10 @@ EOT
395
405
  it 'logs a warning and emits FET with a blank binlog file name, when it receives an update event' do
396
406
  expect($log).to receive(:warn).with("Binlog file name is empty. Rotate event not received!").once
397
407
  expect_emitted_records_with_rows(update_event, :update, TEST_TABLE, 2528, "",
398
- [{"1"=>"0SL00000001", "2"=>"wow"}, {"1"=>"0SL00000003", "2"=>"fuga"}])
408
+ [{old:{"1"=>"0SL00000001", "2"=>"foo"},
409
+ row:{"1"=>"0SL00000001", "2"=>"wow"}},
410
+ {old:{"1"=>"0SL00000003", "2"=>"hoge"},
411
+ row:{"1"=>"0SL00000003", "2"=>"fuga"}}])
399
412
  end
400
413
 
401
414
  it 'logs a warning emits FET with a blank binlog file name, when it receives a delete event' do
@@ -409,7 +422,10 @@ EOT
409
422
  expect_emitted_records_with_rows(insert_event, :insert, TEST_TABLE, 628, "",
410
423
  [{"1"=>"0SL00000001", "2"=>"foo"}, {"1"=>"0SL00000002", "2"=>"var"}, {"1"=>"0SL00000003", "2"=>"hoge"}])
411
424
  expect_emitted_records_with_rows(update_event, :update, TEST_TABLE, 2528, "",
412
- [{"1"=>"0SL00000001", "2"=>"wow"}, {"1"=>"0SL00000003", "2"=>"fuga"}])
425
+ [{old:{"1"=>"0SL00000001", "2"=>"foo"},
426
+ row:{"1"=>"0SL00000001", "2"=>"wow"}},
427
+ {old:{"1"=>"0SL00000003", "2"=>"hoge"},
428
+ row:{"1"=>"0SL00000003", "2"=>"fuga"}}])
413
429
  expect_emitted_records_with_rows(insert_event, :insert, TEST_TABLE, 628, "",
414
430
  [{"1"=>"0SL00000001", "2"=>"foo"}, {"1"=>"0SL00000002", "2"=>"var"}, {"1"=>"0SL00000003", "2"=>"hoge"}])
415
431
  expect_emitted_records_with_rows(delete_event, :delete, TEST_TABLE, 5324, "",
@@ -475,7 +491,7 @@ EOT
475
491
  event = update_event
476
492
  event['table_name'] = TEST_TABLE_APPEND_ONLY
477
493
  expect_emitted_records_with_rows(event, :update, TEST_TABLE_APPEND_ONLY, 2528, "mysql-bin.000048",
478
- [{"1"=>"0SL00000001", "2"=>"wow"}, {"1"=>"0SL00000003", "2"=>"fuga"}])
494
+ [{old:{"1"=>"0SL00000001", "2"=>"foo"}, row:{"1"=>"0SL00000001", "2"=>"wow"}}, {old:{"1"=>"0SL00000003", "2"=>"hoge"}, row:{"1"=>"0SL00000003", "2"=>"fuga"}}])
479
495
  end
480
496
 
481
497
  it 'emits a record when it receives a delete event for non-append only table' do
@@ -136,7 +136,7 @@ describe 'MysqlAlterTableParser' do
136
136
  },{
137
137
  action: :add_column,
138
138
  column: "value2",
139
- type: "int4",
139
+ type: "int4(11)",
140
140
  auto_increment: true,
141
141
  query: "add (value1 varchar(26) not null default 'flydata', value2 int auto_increment)"
142
142
  }]
@@ -160,7 +160,7 @@ describe 'MysqlAlterTableParser' do
160
160
  },{
161
161
  action: :add_column,
162
162
  column: "value2",
163
- type: "int4",
163
+ type: "int4(11)",
164
164
  auto_increment: true,
165
165
  query: "add (`value1` varchar(26) not null default 'flydata', `value2` int auto_increment)"
166
166
  }]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flydata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.30
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Fujikawa
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-01-26 00:00:00.000000000 Z
15
+ date: 2015-02-11 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rest-client
@@ -496,6 +496,7 @@ files:
496
496
  - lib/flydata/compatibility_check.rb
497
497
  - lib/flydata/credentials.rb
498
498
  - lib/flydata/cron.rb
499
+ - lib/flydata/errors.rb
499
500
  - lib/flydata/fluent-plugins/idle_event_detector.rb
500
501
  - lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb
501
502
  - lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb
@@ -569,7 +570,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
569
570
  version: '0'
570
571
  requirements: []
571
572
  rubyforge_project:
572
- rubygems_version: 2.2.2
573
+ rubygems_version: 2.4.3
573
574
  signing_key:
574
575
  specification_version: 4
575
576
  summary: FlyData Agent