Class: Flydata::SourceMysql::Parser::MysqlDumpGeneratorNoMasterData

Inherits:
MysqlDumpGenerator show all
Defined in:
lib/flydata/source_mysql/parser/dump_parser.rb

Instance Method Summary collapse

Methods inherited from MysqlDumpGenerator

#initialize

Constructor Details

This class inherits a constructor from Flydata::SourceMysql::Parser::MysqlDumpGenerator

Instance Method Details

#dump(file_path = nil, &block) ⇒ Object


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/flydata/source_mysql/parser/dump_parser.rb', line 35

def dump(file_path = nil, &block)
  unless file_path || block
    raise ArgumentError.new("file_path or block must be given.")
  end

  dump_cmd = generate_dump_cmd(@conf, file_path)

  # RDS doesn't allow obtaining binlog position using mysqldump.  Get it separately and insert it into the dump file.
  table_locker = create_table_locker(@conf["database"], @conf["tables"])
  table_locker.resume # Lock tables

  begin
    # create pipe for callback function
    rd_io, wr_io = IO.pipe("utf-8", "utf-8")
    wr_io.sync = true
    wr_io.set_encoding("utf-8", "utf-8")
    rd_io.extend(DumpStreamIO)
    binlog_pos = nil

    # start mysqldump
    Open3.popen3 dump_cmd do |cmd_in, cmd_out, cmd_err, wait_thr|
      cmd_in.close_write
      cmd_out.set_encoding("utf-8", "utf-8") # mysqldump output must be in UTF-8

      # wait until the command starts dumping.  Two different ways to
      # check
      if file_path
        # mysqldump dumps to a file `file_path`.  Check if the file
        # exists and not empty.
        loop do
          if File.size? file_path
            break
          end
          sleep 1
        end
      else
        # mysqldump dumps to an IO `cmd_out`.  Wait until it has
        # readable contents.
        cmd_out.wait_readable # wait until first line comes
      end
      binfile, pos = table_locker.resume
      binlog_pos = {binfile: binfile, pos: pos}

      threads = []

      # filter dump stream and write data to pipe
      threads << Thread.new do
        begin
          filter_dump_stream(cmd_out, wr_io)
        ensure
          wr_io.close rescue nil
        end
      end

      # show err message
      errors = ""
      threads << Thread.new do
        cmd_err.each_line do |line|
          errors << line unless /^Warning:/ === line
        end
      end

      if block
        # call callback function with io if block is given
        block.call(rd_io, binlog_pos)
      end

      threads.each(&:join)
      unless wait_thr.value == 0
        #Raise error if the process exited with status != 0
        #(Even if there was no message on stderr stream)
        errors = "Failed to run mysqldump command." if errors.empty?
      end
      raise errors unless errors.empty?
    end
    binlog_pos
  rescue
    # Cleanup
    FileUtils.rm(file_path) if file_path && File.exists?(file_path)
    raise
  ensure
    # Let table_locker finish its task even if an exception happened
    table_locker.resume if table_locker.alive?
    rd_io.close rescue nil
    wr_io.close rescue nil
  end
end

#generate_dump_cmd(conf, file_path = nil) ⇒ Object


123
124
125
# File 'lib/flydata/source_mysql/parser/dump_parser.rb', line 123

def generate_dump_cmd(conf, file_path = nil)
  FlydataCore::Mysql::CommandGenerator.generate_mysqldump_without_master_data_cmd(conf.merge(result_file: file_path))
end