• unknown's avatar
    Fix for BUG#25628: "mysqlbinlog crashes while processing binary logs". · 6f6951d2
    unknown authored
    mysqlbinlog prints all row-based events of a single statement as a
    single "BINLOG" statement containing the concatenation of those events.
    Big (i.e. >64k) concatenations of row-based events
    (e.g. Write_rows_log_event) caused mysqlbinlog's IO_CACHE to overflow
    to a temporary file but the IO_CACHE had not been inited with
    open_cached_file(), so it tried to create a temporary file in
    an uninitialized directory (thus failing to create, then to write;
    some OS errors were printed, and it finally segfaulted).
    After fixing this, it appeared that mysqlbinlog was printing only
    a piece of big concatenations of row-based events (it printed
    at most the size of the IO_CACHE's buffer i.e. 64k); that caused data
    loss at restore. We fix and test that.
    Last, mysqlbinlog's printouts looked a bit strange with the informative
    header (#-prefixed) of groupped Rows_log_event all on one line,
    so we insert \n. After that, a small bug in the --hexdump code appeared
    (only if the string to hex-print had its length a multiple of 16),
    we fix it.
    
    
    
    client/mysqlbinlog.cc:
      if we write to IO_CACHE more than can fit into its memory buffer,
      it will try to overflow into a file; for that to work, IO_CACHE
      must be inited via open_cached_file().
    mysql-test/r/mysqlbinlog_base64.result:
      result update
    mysql-test/t/mysqlbinlog_base64.test:
      test for BUG#25628: test that mysqlbinlog does not have OS errors
      with big concatenations of row-based events
      (e.g. Write_rows_log_event), and prints those concatenations entirely
      (testing by piping the output back into the server and comparing data).
    mysys/mf_iocache2.c:
      my_b_copy_to_file() had a problem: it assumed that bytes_in_cache
      are all the bytes to copy to the file, while it only tells how many
      bytes are in the buffer; so the code forgot to copy what had already
      overflown into a temporary file. Thus any big event was printed only
      partially by mysqlbinlog (loss of data at restore). The fix is
      inspired by MYSQL_BIN_LOG::write_cache().
    sql/log_event.cc:
      Several Table_map/Write_rows events generated by one single statement
      get groupped together in mysqlbinlog's output; it printed things like
      #718 7:30:51 server id 12 end_log_pos 988      Write_rows: table id 17#718 7:30:51 server id 12 #718 7:30:51 server id 12  end_log_pos 988      Write_rows: table id 17#718 7:30:51 server id 12 end_log_pos 1413 <cut>
      It didn't look nice to have printouts glued like this without line
      breaks. Adding a line break.
      Doing this, when using --hexdump the result was:
      #718 7:30:51 server id 12 end_log_pos 988
      # <hexdump output>
      # Write_rows: table id 17
      which is correct; unfortunately if the hex dump had only full lines
      (i.e the string to print in hex had its length a multiple of 16),
      then the # in front of Write_rows was not printed. Fixed.
    sql/log_event.h:
      removing strcpy() (one less function call).
      If we write to IO_CACHE more than can fit into its memory buffer,
      it will try to overflow into a file; for that to work, IO_CACHE
      must be inited via open_cached_file().
      open_cached_file(), like init_io_cache(), can fail; we make sure to
      catch this constructor's problem via the init_ok() method.
    6f6951d2
mysqlbinlog.cc 49.1 KB