class MysqlBinlog::Binlog
Read a binary log, parsing and returning events.
Examples¶ ↑
A basic example of using the Binlog
class:
require 'mysql_binlog' include MysqlBinlog # Open a binary log from a file on disk. binlog = Binlog.new(BinlogFileReader.new("mysql-bin.000001")) # Iterate over all events from the log, printing the event type (such # as :query_event, :write_rows_event, etc.) binlog.each_event do |event| puts event[:type] end
Attributes
Public Class Methods
# File lib/mysql_binlog/binlog.rb, line 56 def initialize(reader) @reader = reader @field_parser = BinlogFieldParser.new(self) @event_parser = BinlogEventParser.new(self) @fde = nil @filter_event_types = nil @filter_flags = nil @ignore_rotate = false @max_query_length = 1048576 @checksum = :nil end
Public Instance Methods
# File lib/mysql_binlog/binlog.rb, line 114 def checksum_length case @checksum when :crc32 4 else 0 end end
Iterate through all events.
# File lib/mysql_binlog/binlog.rb, line 218 def each_event unless block_given? return Enumerable::Enumerator.new(self, :each_event) end while event = read_event yield event end end
# File lib/mysql_binlog/binlog.rb, line 123 def payload_length(header) @fde ? (header[:event_length] - @fde[:header_length] - checksum_length) : 0 end
Scan events until finding one that isn't rejected by the filter rules. If there are no filter rules, this will return the next event provided by the reader.
# File lib/mysql_binlog/binlog.rb, line 130 def read_event while true skip_this_event = false return nil if reader.end? filename = reader.filename position = reader.position # Read the common header for an event. Every event has a header. unless header = event_parser.event_header return nil end # Skip the remaining part of the header which might not have been # parsed. if @fde reader.seek(position + @fde[:header_length]) header[:payload_length] = payload_length(header) header[:payload_end] = position + @fde[:header_length] + payload_length(header) else header[:payload_length] = 0 header[:payload_end] = header[:next_position] end if @filter_event_types unless @filter_event_types.include? header[:event_type] skip_this_event = true end end if @filter_flags unless @filter_flags.include? header[:flags] skip_this_event = true end end # Never skip over rotate_event or format_description_event as they # are critical to understanding the format of this event stream. if skip_this_event unless [:rotate_event, :format_description_event].include? header[:event_type] skip_event(header) next end end fields = read_event_fields(header) case header[:event_type] when :rotate_event unless ignore_rotate reader.rotate(fields[:name], fields[:pos]) end when :format_description_event process_fde(fields) end break end { :type => header[:event_type], :filename => filename, :position => position, :header => header, :event => fields, } end
Rewind to the beginning of the log, if supported by the reader. The reader may throw an exception if rewinding is not supported (e.g. for a stream-based reader).
# File lib/mysql_binlog/binlog.rb, line 71 def rewind reader.rewind end
Private Instance Methods
Process a format description event, which describes the version of this file, and the format of events which will appear in this file. This also provides the version of the MySQL server which generated this file.
# File lib/mysql_binlog/binlog.rb, line 202 def process_fde(fde) if (version = fde[:binlog_version]) != 4 raise UnsupportedVersionException.new("Binlog version #{version} is not supported") end # Save the interesting fields from an FDE so that this information is # available at any time later. @fde = { :header_length => fde[:header_length], :binlog_version => fde[:binlog_version], :server_version => fde[:server_version], } end
Read the content of the event, which follows the header.
# File lib/mysql_binlog/binlog.rb, line 83 def read_event_fields(header) # Delegate the parsing of the event content to a method of the same name # in BinlogEventParser. if event_parser.methods.map(&:to_sym).include? header[:event_type] fields = event_parser.send(header[:event_type], header) end unless fields fields = { payload: reader.read(header[:payload_length]), } end # Check if we've read past the end of the event. This is normally because # of an unsupported substructure in the event causing field misalignment # or a bug in the event reader method in BinlogEventParser. This may also # be due to user error in providing an initial start position or later # seeking to a position which is not a valid event start position. if reader.position > header[:next_position] raise OverReadException.new("Read past end of event; corrupted event, bad start position, or bug in mysql_binlog?") end # Anything left unread at this point is skipped based on the event length # provided in the header. In this way, it is possible to skip over events # that are not able to be parsed completely by this library. skip_event(header) fields end
Skip the remainder of this event. This can be used to skip an entire event or merely the parts of the event this library does not understand.
# File lib/mysql_binlog/binlog.rb, line 77 def skip_event(header) reader.skip(header) end