diff options
author | unknown <gbichot@dl145h.mysql.com> | 2007-02-23 22:23:54 +0100 |
---|---|---|
committer | unknown <gbichot@dl145h.mysql.com> | 2007-02-23 22:23:54 +0100 |
commit | 6f6951d21867a2d71de414d21becf55feb3792b1 (patch) | |
tree | d70fb171b2521ed63ca7f3dec32e9a62453f00a0 /mysys/mf_iocache2.c | |
parent | 8777e35a144cbf51e0dc3ee6d621bc9711c1ea07 (diff) | |
download | mariadb-git-6f6951d21867a2d71de414d21becf55feb3792b1.tar.gz |
Fix for BUG#25628: "mysqlbinlog crashes while processing binary logs".
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.
Diffstat (limited to 'mysys/mf_iocache2.c')
-rw-r--r-- | mysys/mf_iocache2.c | 17 |
1 files changed, 7 insertions, 10 deletions
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 7b3393da4f5..a85f741bd67 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -50,7 +50,6 @@ int my_b_copy_to_file(IO_CACHE *cache, FILE *file) { - byte buf[IO_SIZE]; uint bytes_in_cache; DBUG_ENTER("my_b_copy_to_file"); @@ -58,19 +57,17 @@ my_b_copy_to_file(IO_CACHE *cache, FILE *file) if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE)) DBUG_RETURN(1); bytes_in_cache= my_b_bytes_in_cache(cache); - while (bytes_in_cache > 0) { - uint const read_bytes= min(bytes_in_cache, sizeof(buf)); - DBUG_PRINT("debug", ("Remaining %u bytes - Reading %u bytes", - bytes_in_cache, read_bytes)); - if (my_b_read(cache, buf, read_bytes)) - DBUG_RETURN(1); - if (my_fwrite(file, buf, read_bytes, MYF(MY_WME | MY_NABP)) == (uint) -1) + do + { + if (my_fwrite(file, cache->read_pos, bytes_in_cache, + MYF(MY_WME | MY_NABP)) == (uint) -1) DBUG_RETURN(1); - bytes_in_cache -= read_bytes; - } + cache->read_pos= cache->read_end; + } while ((bytes_in_cache= my_b_fill(cache))); DBUG_RETURN(0); } + my_off_t my_b_append_tell(IO_CACHE* info) { /* |