Commit afbb72b3 authored by Monty's avatar Monty

Made IO_CACHE safe for reading big blocks (> 2G)

The reason for adding this was that while testing mysqlbinlog on
a replication event with 3G event output, Linux failed reading
the whole file in memory with one read (only got 2G on first read
even if file had just been written).

- Don't reset info->error on write error in IO_CACHE.
- In case of write_error in IO_CACHE , always return -1
- Fixed wrong result from my_read when using MY_FULL_IO. Also don't give
  an error in case of retry.
parent e6418413
...@@ -115,6 +115,7 @@ init_functions(IO_CACHE* info) ...@@ -115,6 +115,7 @@ init_functions(IO_CACHE* info)
DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
info->read_function = info->share ? _my_b_cache_read_r : _my_b_cache_read; info->read_function = info->share ? _my_b_cache_read_r : _my_b_cache_read;
info->write_function = info->share ? _my_b_cache_write_r : _my_b_cache_write; info->write_function = info->share ? _my_b_cache_write_r : _my_b_cache_write;
info->myflags&= ~MY_FULL_IO;
break; break;
case TYPE_NOT_SET: case TYPE_NOT_SET:
DBUG_ASSERT(0); DBUG_ASSERT(0);
...@@ -455,6 +456,8 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, ...@@ -455,6 +456,8 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
{ {
info->read_end=info->write_pos; info->read_end=info->write_pos;
info->end_of_file=my_b_tell(info); info->end_of_file=my_b_tell(info);
/* Ensure we will read all data */
info->myflags|= MY_FULL_IO;
/* /*
Trigger a new seek only if we have a valid Trigger a new seek only if we have a valid
file handle. file handle.
...@@ -469,6 +472,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, ...@@ -469,6 +472,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
info->seek_not_done=1; info->seek_not_done=1;
} }
info->end_of_file = ~(my_off_t) 0; info->end_of_file = ~(my_off_t) 0;
info->myflags&= ~MY_FULL_IO;
} }
pos=info->request_pos+(seek_offset-info->pos_in_file); pos=info->request_pos+(seek_offset-info->pos_in_file);
if (type == WRITE_CACHE) if (type == WRITE_CACHE)
...@@ -1917,13 +1921,12 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock) ...@@ -1917,13 +1921,12 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
{ {
if (append_cache) if (append_cache)
{ {
if (mysql_file_write(info->file, info->write_buffer, length, if (mysql_file_write(info->file, info->write_buffer, length,
info->myflags | MY_NABP)) info->myflags | MY_NABP))
{
info->error= -1; info->error= -1;
else DBUG_RETURN(-1);
info->error= 0; }
info->end_of_file+= info->write_pos - info->append_read_pos; info->end_of_file+= info->write_pos - info->append_read_pos;
info->append_read_pos= info->write_buffer; info->append_read_pos= info->write_buffer;
DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0))); DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0)));
......
...@@ -35,11 +35,10 @@ ...@@ -35,11 +35,10 @@
size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags) size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
{ {
size_t readbytes, save_count; size_t readbytes, save_count= 0;
DBUG_ENTER("my_read"); DBUG_ENTER("my_read");
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %lu", DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %lu",
Filedes, Buffer, (ulong) Count, MyFlags)); Filedes, Buffer, (ulong) Count, MyFlags));
save_count= Count;
if (!(MyFlags & (MY_WME | MY_FAE | MY_FNABP))) if (!(MyFlags & (MY_WME | MY_FAE | MY_FNABP)))
MyFlags|= my_global_flags; MyFlags|= my_global_flags;
...@@ -61,47 +60,52 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags) ...@@ -61,47 +60,52 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
if (readbytes != Count) if (readbytes != Count)
{ {
my_errno= errno; int got_errno= my_errno= errno;
if (errno == 0 || (readbytes != (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d", DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d",
(int) readbytes, (ulong) Count, Filedes, (int) readbytes, (ulong) Count, Filedes,
my_errno)); got_errno));
if (got_errno == 0 || (readbytes != (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
my_errno= HA_ERR_FILE_TOO_SHORT;
if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) if ((readbytes == 0 || (int) readbytes == -1) && got_errno == EINTR)
{ {
DBUG_PRINT("debug", ("my_read() was interrupted and returned %ld", DBUG_PRINT("debug", ("my_read() was interrupted and returned %ld",
(long) readbytes)); (long) readbytes));
continue; /* Interrupted */ continue; /* Interrupted */
} }
/* Do a read retry if we didn't get enough data on first read */
if (readbytes != (size_t) -1 && readbytes != 0 &&
(MyFlags & MY_FULL_IO))
{
Buffer+= readbytes;
Count-= readbytes;
save_count+= readbytes;
continue;
}
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{ {
if (readbytes == (size_t) -1) if (readbytes == (size_t) -1)
my_error(EE_READ, my_error(EE_READ,
MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))), MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
my_filename(Filedes),my_errno); my_filename(Filedes), got_errno);
else if (MyFlags & (MY_NABP | MY_FNABP)) else if (MyFlags & (MY_NABP | MY_FNABP))
my_error(EE_EOFERR, my_error(EE_EOFERR,
MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))), MYF(ME_BELL | ME_WAITTANG | (MyFlags & (ME_JUST_INFO | ME_NOREFRESH))),
my_filename(Filedes),my_errno); my_filename(Filedes), got_errno);
} }
if (readbytes == (size_t) -1 || if (readbytes == (size_t) -1 ||
((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO))) ((MyFlags & (MY_FNABP | MY_NABP)) && !(MyFlags & MY_FULL_IO)))
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
if (readbytes != (size_t) -1 && (MyFlags & MY_FULL_IO))
{
Buffer+= readbytes;
Count-= readbytes;
continue;
}
} }
if (MyFlags & (MY_NABP | MY_FNABP)) if (MyFlags & (MY_NABP | MY_FNABP))
readbytes= 0; /* Ok on read */ readbytes= 0; /* Ok on read */
else if (MyFlags & MY_FULL_IO) else
readbytes= save_count; readbytes+= save_count;
break; break;
} }
DBUG_RETURN(readbytes); DBUG_RETURN(readbytes);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment