Skip to content

Commit

Permalink
Port fix for mysqlbinlog reading big records from stdin
Browse files Browse the repository at this point in the history
Summary:
Fixed mysqlbinlog error when reading big records from stdin.

When mysqlbinlog tries to read a big record (over 128KB) from stdin, the
glibc read in my_read will return 128KB instead of the full size. This
causes _my_b_read to fail.

Ported the folowing change
In mysqlbinlog.cc, enable MY_FULL_IO, and in my_read.c, fix the
MY_FULL_IO logic.

Test Plan:
ported the test case which generates an event of size greater
than greater than 128kb and runs mysqlbinlog.

Reviewers: steaphan

Reviewed By: steaphan
  • Loading branch information
santoshbanda authored and jtolmer committed Jan 5, 2016
1 parent f1c37d1 commit db9f9dd
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 5 deletions.
2 changes: 1 addition & 1 deletion client/mysqlbinlog.cc
Expand Up @@ -2811,7 +2811,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
}
#endif
if (init_io_cache(file, my_fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE | MY_FULL_IO)))
{
error("Failed to init IO cache.");
return ERROR_STOP;
Expand Down
41 changes: 41 additions & 0 deletions mysql-test/r/mysqlbinlog_big_event.result

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions mysql-test/t/mysqlbinlog_big_event-master.opt
@@ -0,0 +1 @@
--force-restart
39 changes: 39 additions & 0 deletions mysql-test/t/mysqlbinlog_big_event.test
@@ -0,0 +1,39 @@
# ==== Purpose ====
# Test mysqlbinlog with a binlog event larger than 128kb.
# using have_binlog_format_statement to create a statement
# based binlog event greater than 128kb. The idea is to insert
# a big string in a table having a BLOB column.
#
# === Implementaion ===

-- source include/have_binlog_format_statement.inc

# Reset master to cleanup binlog
reset master;

# we need this for getting fixed timestamps inside of this test
set timestamp=1000000000;

--disable_warnings
drop table if exists t2;
--enable_warnings

let $MYSQLD_DATADIR=`select @@datadir`;
create table t2 (word LONGBLOB);
let $i = 33000;
--disable_query_log
set @string = 'testing ';
while($i > 0)
{
set @string = concat(@string, 'testing ');
dec $i;
}

insert into t2 values(@string);
--enable_query_log
let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
flush logs;
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/
--exec cat $MYSQLD_DATADIR/$binlog_file | $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ -
drop table t2;
10 changes: 6 additions & 4 deletions mysys/my_read.c
Expand Up @@ -35,11 +35,11 @@

size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
{
size_t readbytes, save_count;
size_t readbytes, savedbytes;
DBUG_ENTER("my_read");
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d",
Filedes, Buffer, (ulong) Count, MyFlags));
save_count= Count;
savedbytes= 0;

for (;;)
{
Expand Down Expand Up @@ -87,18 +87,20 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
if (readbytes == (size_t) -1 ||
((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO)))
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
if (readbytes != (size_t) -1 && (MyFlags & MY_FULL_IO))
/* readbytes == 0 when EOF. No need to continue in case of EOF */
if (readbytes != 0 && (MyFlags & MY_FULL_IO))
{
Buffer+= readbytes;
Count-= readbytes;
savedbytes+= readbytes;
continue;
}
}

if (MyFlags & (MY_NABP | MY_FNABP))
readbytes= 0; /* Ok on read */
else if (MyFlags & MY_FULL_IO)
readbytes= save_count;
readbytes+= savedbytes;
break;
}
DBUG_RETURN(readbytes);
Expand Down

0 comments on commit db9f9dd

Please sign in to comment.