flydata 0.3.10 → 0.3.11

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: 478d29c0767a534808dea15674528d5b5442bbed
4
- data.tar.gz: c6536fb66fedffbdcc52069cb28f32f74fe3465d
3
+ metadata.gz: c81a2a245fd400366aa535123cd4bcfa009aa29f
4
+ data.tar.gz: 6762cefccdabfd09f5e7034bbf32aa9fb6d6262b
5
5
  SHA512:
6
- metadata.gz: 6b97f3acc0e763fcff4f2d4a18dcc4d9625d736db229b00554aee36da0ff8e68a189324a46abb3d985dfd1e2d4964ec6963a9299d475170e759485cb1e07faec
7
- data.tar.gz: fdee03e1c1bf32699f8c5157aa51f48ecf6f1c023d2160a63b996ca7ac0599fa952de02b55045715b4a66283083b204860201a31a157b9cbf92d2413aebc77d5
6
+ metadata.gz: cd9983b914ef12e36f39248dfe4fde7c49e321b17df7ad476155061d84da62dde5a0cd78ed94c17b23c55bebd5b3b591adccafb45c5c4036305702e8cd5bab44
7
+ data.tar.gz: 18e24eb120bc7d0aa61d7e9819c4d59593a07645703ffcb627d8ede58deb6e43953a20318006a5c4fcf562cc4decac586d34ec4b697373cbc7dde0faea63a7f4
data/Gemfile CHANGED
@@ -14,6 +14,7 @@ gem "slop", '~> 3.4', '>= 3.4.6'
14
14
  gem "treetop", '~> 1.5', '>= 1.5.3'
15
15
  gem "sys-filesystem", '~> 1.1', '>= 1.1.3'
16
16
  gem "io-console", '~> 0.4.2', '>= 0.4.2'
17
+ gem "kodama", '~> 0.1.2', '>= 0.1.2'
17
18
 
18
19
  group :development do
19
20
  gem "jeweler", '~> 1.8', '>= 1.8.8'
data/Gemfile.lock CHANGED
@@ -61,7 +61,7 @@ GEM
61
61
  rdoc
62
62
  json (1.8.1)
63
63
  jwt (1.0.0)
64
- kodama (0.1.1)
64
+ kodama (0.1.2)
65
65
  ruby-binlog (>= 0.1.9)
66
66
  method_source (0.8.2)
67
67
  mime-types (2.3)
@@ -133,6 +133,7 @@ DEPENDENCIES
133
133
  io-console (~> 0.4.2, >= 0.4.2)
134
134
  jeweler (~> 1.8, >= 1.8.8)
135
135
  json (~> 1.8, >= 1.8.0)
136
+ kodama (~> 0.1.2, >= 0.1.2)
136
137
  mysql2 (~> 0.3, >= 0.3.11)
137
138
  protected_attributes (~> 1.0, >= 1.0.8)
138
139
  pry
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.10
1
+ 0.3.11
data/flydata.gemspec CHANGED
@@ -2,16 +2,14 @@
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.3.10 ruby lib
6
5
 
7
6
  Gem::Specification.new do |s|
8
7
  s.name = "flydata"
9
- s.version = "0.3.10"
8
+ s.version = "0.3.11"
10
9
 
11
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
- s.require_paths = ["lib"]
13
11
  s.authors = ["Koichi Fujikawa", "Masashi Miyazaki", "Matthew Luu", "Mak Inada", "Sriram NS"]
14
- s.date = "2015-03-31"
12
+ s.date = "2015-04-03"
15
13
  s.description = "FlyData Agent"
16
14
  s.email = "sysadmin@flydata.com"
17
15
  s.executables = ["fdmysqldump", "flydata", "serverinfo"]
@@ -168,7 +166,8 @@ Gem::Specification.new do |s|
168
166
  ]
169
167
  s.homepage = "http://flydata.com/"
170
168
  s.licenses = ["All right reserved."]
171
- s.rubygems_version = "2.4.3"
169
+ s.require_paths = ["lib"]
170
+ s.rubygems_version = "2.0.14"
172
171
  s.summary = "FlyData Agent"
173
172
 
174
173
  if s.respond_to? :specification_version then
@@ -188,6 +187,7 @@ Gem::Specification.new do |s|
188
187
  s.add_runtime_dependency(%q<treetop>, [">= 1.5.3", "~> 1.5"])
189
188
  s.add_runtime_dependency(%q<sys-filesystem>, [">= 1.1.3", "~> 1.1"])
190
189
  s.add_runtime_dependency(%q<io-console>, [">= 0.4.2", "~> 0.4.2"])
190
+ s.add_runtime_dependency(%q<kodama>, [">= 0.1.2", "~> 0.1.2"])
191
191
  s.add_development_dependency(%q<jeweler>, [">= 1.8.8", "~> 1.8"])
192
192
  s.add_development_dependency(%q<rspec>, ["~> 3.0"])
193
193
  s.add_development_dependency(%q<timecop>, [">= 0.7.1", "~> 0.7"])
@@ -211,6 +211,7 @@ Gem::Specification.new do |s|
211
211
  s.add_dependency(%q<treetop>, [">= 1.5.3", "~> 1.5"])
212
212
  s.add_dependency(%q<sys-filesystem>, [">= 1.1.3", "~> 1.1"])
213
213
  s.add_dependency(%q<io-console>, [">= 0.4.2", "~> 0.4.2"])
214
+ s.add_dependency(%q<kodama>, [">= 0.1.2", "~> 0.1.2"])
214
215
  s.add_dependency(%q<jeweler>, [">= 1.8.8", "~> 1.8"])
215
216
  s.add_dependency(%q<rspec>, ["~> 3.0"])
216
217
  s.add_dependency(%q<timecop>, [">= 0.7.1", "~> 0.7"])
@@ -235,6 +236,7 @@ Gem::Specification.new do |s|
235
236
  s.add_dependency(%q<treetop>, [">= 1.5.3", "~> 1.5"])
236
237
  s.add_dependency(%q<sys-filesystem>, [">= 1.1.3", "~> 1.1"])
237
238
  s.add_dependency(%q<io-console>, [">= 0.4.2", "~> 0.4.2"])
239
+ s.add_dependency(%q<kodama>, [">= 0.1.2", "~> 0.1.2"])
238
240
  s.add_dependency(%q<jeweler>, [">= 1.8.8", "~> 1.8"])
239
241
  s.add_dependency(%q<rspec>, ["~> 3.0"])
240
242
  s.add_dependency(%q<timecop>, [">= 0.7.1", "~> 0.7"])
@@ -182,6 +182,7 @@ EOS
182
182
  new_tables_after_reset = @new_tables + @input_tables
183
183
  if @input_tables.empty? or @full_tables.empty? or @full_tables.all?{|ft| new_tables_after_reset.include?(ft)}
184
184
  delete_files << sync_fm.binlog_path
185
+ delete_files << sync_fm.sent_binlog_path
185
186
  end
186
187
  delete_files.flatten.each do |path|
187
188
  FileUtils.rm(path) if File.exists?(path)
@@ -228,6 +229,54 @@ EOS
228
229
  do_generate_table_ddl(de)
229
230
  end
230
231
 
232
+ # Command: flydata sync:fix_binlogpos
233
+ # - Arguments
234
+ def self.slop_fix_binlogpos
235
+ Slop.new do
236
+ on 'f', 'force', 'update sent binlog position file forcibly'
237
+ end
238
+ end
239
+
240
+ # Command: flydata sync:fix_binlogpos
241
+ # Set binlog path
242
+ # - Entry method
243
+ def fix_binlogpos
244
+ de = data_entry
245
+ sync_fm = create_sync_file_manager(de)
246
+
247
+ if File.exists?(sync_fm.sent_binlog_path) && !opts.force?
248
+ log_info_stdout("Skip creating sent binlogpos because sent position file is exist already. (#{sync_fm.sent_binlog_path})")
249
+ return
250
+ end
251
+
252
+ if Flydata::Command::Sender.new.process_exist?
253
+ log_warn_stderr("flydata is running. flydata process needs to be stopped with 'flydata stop'.")
254
+ return
255
+ end
256
+
257
+ binlog_info = sync_fm.load_binlog
258
+ if binlog_info.nil?
259
+ log_info_stdout("Skip creating sent binlogpos because binlog position file is empty or invalid. (#{sync_fm.sent_binlog_path})")
260
+ return
261
+ end
262
+
263
+ say("Updating binlog position files...")
264
+ log_info("Updating binlog position files... Original binlog_info:#{binlog_info}")
265
+
266
+ # Update binlog.sent.pos file
267
+ # -1 is because the position in binlog.pos is the next event's position.
268
+ # on the other hand the position in sent position indicates already processed.
269
+ binlog_info[:pos] -= 1
270
+ log_info("Updating sent position file. #{binlog_info} -> #{sync_fm.sent_binlog_path}")
271
+ sync_fm.save_sent_binlog(binlog_info)
272
+
273
+ # Update binlog.pos file to start from head of the current binlog file
274
+ new_binlog_info = binlog_info.dup.tap{|h| h[:pos] = 4} # 4 is the first position of binlog file.
275
+ log_info("Updating original position file. #{new_binlog_info} -> #{sync_fm.binlog_path}")
276
+ sync_fm.save_binlog(new_binlog_info)
277
+ log_info_stdout("Done!")
278
+ end
279
+
231
280
  private
232
281
 
233
282
  # Initial sync
@@ -60,6 +60,10 @@ class MysqlBinlogFlydataInput < MysqlBinlogInput
60
60
  unless @binlog_position_file.exists?
61
61
  raise "No position file(#{@position_file}). Initial synchronization is required before starting."
62
62
  end
63
+
64
+ @sync_fm = Flydata::SyncFileManager.new(nil) # Passing nil for data_entry as this class does not use methods which require data_entry
65
+ @sent_position_file_path = @sync_fm.sent_binlog_path(@position_file)
66
+
63
67
  load_custom_conf
64
68
  $log.info "mysql host:\"#{@host}\" port:\"#{@port}\" username:\"#{@username}\" database:\"#{@database}\" tables:\"#{@tables}\" tables_append_only:\"#{tables_append_only}\""
65
69
  $log.info "mysql client version: #{`mysql -V`}"
@@ -72,7 +76,6 @@ class MysqlBinlogFlydataInput < MysqlBinlogInput
72
76
  @tables << table unless @tables.include?(table)
73
77
  @omit_events[table] = [:delete]
74
78
  end
75
- @sync_fm = Flydata::SyncFileManager.new(nil) # Passing nil for data_entry as this class does not use methods which require data_entry
76
79
 
77
80
  #Remove tables that do not have pos files
78
81
  new_tables = @sync_fm.get_new_table_list(@tables, "pos")
@@ -131,6 +134,10 @@ EOS
131
134
  @context.table_meta.update
132
135
  start_kodama(mysql_url) do |c|
133
136
  c.binlog_position_file = @position_file
137
+ if c.respond_to?(:sent_binlog_position_file=)
138
+ $log.info "Sent position feature is enabled. sent_position_file:#{@sent_position_file_path}"
139
+ c.sent_binlog_position_file = @sent_position_file_path
140
+ end
134
141
  c.connection_retry_limit = @retry_limit
135
142
  c.connection_retry_wait = @retry_wait
136
143
  c.log_level = @log_level.to_sym
@@ -13,13 +13,13 @@ module Mysql
13
13
  PATTERN
14
14
  end
15
15
 
16
- def process(record, normalized_query)
16
+ def process(record)
17
17
  emit_record(:alter_table, record) do |opt|
18
18
  ret = nil
19
19
  begin
20
- result = ParserProvider.parser(:mysql, :mysql_alter_table).new.parse(normalized_query)
20
+ result = ParserProvider.parser(:mysql, :mysql_alter_table).new.parse(record["normalized_query"])
21
21
  if result.nil?
22
- $log.error("Received unsupported alter table query. normalized query:'#{normalized_query}', raw query: '#{record['query']}'")
22
+ $log.error("Received unsupported alter table query. normalized query:'#{record['normalized_query']}', raw query: '#{record['query']}'")
23
23
  else
24
24
  ret = result.tree
25
25
  breaking_query = ret[:actions].any?{|action| !action.has_key?(:support_level) || action[:support_level] != :nonbreaking}
@@ -27,7 +27,7 @@ module Mysql
27
27
  end
28
28
  rescue => e
29
29
  msg = <<EOS
30
- Received unsupported alter table query. normalized query:'#{normalized_query}', raw query: '#{record['query']}' Caused by error '#{e.to_s}'
30
+ Received unsupported alter table query. normalized query:'#{record['normalized_query']}', raw query: '#{record['query']}' Caused by error '#{e.to_s}'
31
31
  Stacktrace :
32
32
  #{e.backtrace.join("\n")}
33
33
  EOS
@@ -10,7 +10,7 @@ module Mysql
10
10
  normalize_query(record["query"]) do |query|
11
11
  @handlers.each do |handler|
12
12
  if (handler.pattern.match(query))
13
- handler.process(record, query)
13
+ handler.process(record.merge({"normalized_query" => query}))
14
14
  break
15
15
  end
16
16
  end
@@ -7,7 +7,7 @@ class DdlQueryHandler < BinlogQueryHandler
7
7
 
8
8
  def acceptable_db?(record)
9
9
  db_name = record["db_name"]
10
- if DDL_TABLE_QUERY =~ record["query"]
10
+ if DDL_TABLE_QUERY =~ record["normalized_query"]
11
11
  table_name_in_query = $1 ? $1 : $2
12
12
 
13
13
  if (idx = table_name_in_query.index("."))
@@ -1,3 +1,5 @@
1
+ require 'mysql2'
2
+
1
3
  module Flydata
2
4
  class SyncFileManager
3
5
  DUMP_DIR = ENV['FLYDATA_DUMP'] || File.join(FLYDATA_HOME, 'dump')
@@ -70,7 +72,7 @@ module Flydata
70
72
  end
71
73
  end
72
74
 
73
- # binlog.pos file
75
+ # master binlog.pos file
74
76
  def save_binlog(binlog_pos)
75
77
  path = binlog_path
76
78
  File.open(path, 'w') do |f|
@@ -78,10 +80,32 @@ module Flydata
78
80
  end
79
81
  end
80
82
 
83
+ def load_binlog(file_path = binlog_path)
84
+ return nil unless File.exists?(file_path)
85
+ f, pos = IO.read(file_path).strip.split("\t")
86
+ return nil if f.nil? || f.empty? || pos.nil?
87
+ { binfile: f, pos: pos.to_i }
88
+ end
89
+
81
90
  def binlog_path
82
91
  File.join(FLYDATA_HOME, @data_entry['name'] + ".binlog.pos")
83
92
  end
84
93
 
94
+ # sent binlog.pos file
95
+ def save_sent_binlog(binlog_pos)
96
+ File.open(sent_binlog_path, 'w') do |f|
97
+ f.write(binlog_content(binlog_pos))
98
+ end
99
+ end
100
+
101
+ def sent_binlog_path(master_binlog_path = binlog_path)
102
+ unless master_binlog_path && master_binlog_path.end_with?('binlog.pos')
103
+ raise ArgumentError.new("Invalid binlog path. binlog path needs to end with 'binlog.pos'")
104
+ end
105
+ "#{master_binlog_path[0..-5]}.sent.pos"
106
+ end
107
+
108
+ # table files
85
109
  def reset_table_position_files(tables)
86
110
  tables.each do |table_name|
87
111
  file = File.join(table_positions_dir_path, table_name + ".pos")
@@ -15,7 +15,7 @@ module Fluent
15
15
  TEST_SEQUENCE_NUM = 1
16
16
  TEST_TABLE_BINLOG_POS = File.join(FLYDATA_HOME, "positions/#{TEST_TABLE}.binlog.pos")
17
17
  TEST_TABLES = "#{TEST_TABLE},test_table_1,test_table_2,test_table_3"
18
- TEST_POSITION_FILE = "test_position.log"
18
+ TEST_POSITION_FILE = "test_position.binlog.pos"
19
19
  TEST_REVISION_FILE = File.join(FLYDATA_HOME, "positions/#{TEST_TABLE}.rev")
20
20
  TEST_TIMESTAMP = 1389214083
21
21
  TEST_TABLE_APPEND_ONLY = "test_table_4"
@@ -22,14 +22,15 @@ module Mysql
22
22
  subject { described_class.new(context) }
23
23
  describe '#process' do
24
24
  let(:query) { "a_query" }
25
+ let(:normalized_query) { double('normalized_query') }
25
26
  let(:record) do
26
27
  r = double('record')
27
28
  allow(r).to receive(:[]).with("db_name").and_return(database)
28
29
  allow(r).to receive(:[]).with("query").and_return(query)
29
30
  allow(r).to receive(:[]).with("table_name").and_return(table)
31
+ allow(r).to receive(:[]).with("normalized_query").and_return(normalized_query)
30
32
  r
31
33
  end
32
- let(:normalized_query) { double('normalized_query') }
33
34
  let(:parse_result) do
34
35
  r = double('parse_result')
35
36
  r
@@ -51,7 +52,7 @@ module Mysql
51
52
  it "returns nil with an error log" do
52
53
  expect($log).to receive(:error).with(/Received unsupported alter table query.*Caused by error '#{an_error}'/m)
53
54
 
54
- expect(subject.process(record, normalized_query)).to eq(nil)
55
+ expect(subject.process(record)).to eq(nil)
55
56
  end
56
57
  end
57
58
 
@@ -74,7 +75,7 @@ module Mysql
74
75
  it "returns nil with a warn log" do
75
76
  expect($log).to receive(:error).with(/Received unsupported alter table query\./)
76
77
 
77
- expect(subject.process(record, normalized_query)).to eq(nil)
78
+ expect(subject.process(record)).to eq(nil)
78
79
  end
79
80
  end
80
81
  end
@@ -46,12 +46,13 @@ EOT
46
46
  let(:record) do
47
47
  r = double('record')
48
48
  allow(r).to receive(:[]).with("query").and_return(query)
49
+ expect(r).to receive(:merge).with({"normalized_query" => normalized_query}).and_return(r)
49
50
  r
50
51
  end
51
52
  let(:query_handler) do
52
53
  r = double('query_handler')
53
54
  allow(r).to receive(:pattern).and_return(/^ALTER TABLE/i)
54
- expect(r).to receive(:process).with(record, normalized_query)
55
+ expect(r).to receive(:process).with(record)
55
56
  r
56
57
  end
57
58
  let(:context) { double('context') }
@@ -153,10 +153,47 @@ module Flydata
153
153
  end
154
154
  end
155
155
 
156
+ describe '#load_binlog' do
157
+ let(:binfile) { 'mysqlbinlog.000001' }
158
+ let(:pos) { 107 }
159
+ let(:binlog_pos) { {binfile: binfile, pos: pos} }
160
+
161
+ subject { default_sfm.load_binlog }
162
+
163
+ context 'when binlog pos does not exist' do
164
+ before do
165
+ File.delete(default_sfm.binlog_path) if File.exist?(default_sfm.binlog_path)
166
+ end
167
+ it { is_expected.to be_nil }
168
+ end
169
+
170
+ context 'when binlog pos exists' do
171
+ before do
172
+ default_sfm.save_binlog(binlog_pos)
173
+ end
174
+ it { is_expected.to eq(binlog_pos) }
175
+ end
176
+ end
177
+
156
178
  describe '#binlog_path' do
157
179
  it { expect(default_sfm.binlog_path).to eq("#{FLYDATA_HOME}/flydata_sync_mysql.binlog.pos") }
158
180
  end
159
181
 
182
+ describe '#sent_binlog_path' do
183
+ context 'with no args' do
184
+ subject { default_sfm.sent_binlog_path }
185
+ it { is_expected.to eq("#{FLYDATA_HOME}/flydata_sync_mysql.binlog.sent.pos") }
186
+ end
187
+ context 'with invalid args' do
188
+ subject { default_sfm.sent_binlog_path('/home/ec2-user/.flydata/flydata_sync.pos') }
189
+ it { expect{subject}.to raise_error(ArgumentError) }
190
+ end
191
+ context 'with valid args' do
192
+ subject { default_sfm.sent_binlog_path('/home/ec2-user/.flydata/flydata_sync.binlog.pos') }
193
+ it { is_expected.to eq('/home/ec2-user/.flydata/flydata_sync.binlog.sent.pos') }
194
+ end
195
+ end
196
+
160
197
  describe '#increment_and_save_table_position' do
161
198
  let(:test_table) { 'test_table' }
162
199
  before do
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.3.10
4
+ version: 0.3.11
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-03-31 00:00:00.000000000 Z
15
+ date: 2015-04-03 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rest-client
@@ -262,6 +262,26 @@ dependencies:
262
262
  - - ~>
263
263
  - !ruby/object:Gem::Version
264
264
  version: 0.4.2
265
+ - !ruby/object:Gem::Dependency
266
+ name: kodama
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - '>='
270
+ - !ruby/object:Gem::Version
271
+ version: 0.1.2
272
+ - - ~>
273
+ - !ruby/object:Gem::Version
274
+ version: 0.1.2
275
+ type: :runtime
276
+ prerelease: false
277
+ version_requirements: !ruby/object:Gem::Requirement
278
+ requirements:
279
+ - - '>='
280
+ - !ruby/object:Gem::Version
281
+ version: 0.1.2
282
+ - - ~>
283
+ - !ruby/object:Gem::Version
284
+ version: 0.1.2
265
285
  - !ruby/object:Gem::Dependency
266
286
  name: jeweler
267
287
  requirement: !ruby/object:Gem::Requirement
@@ -608,7 +628,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
608
628
  version: '0'
609
629
  requirements: []
610
630
  rubyforge_project:
611
- rubygems_version: 2.4.3
631
+ rubygems_version: 2.0.14
612
632
  signing_key:
613
633
  specification_version: 4
614
634
  summary: FlyData Agent