diff options
Diffstat (limited to 'sql/mf_iocache.cc')
-rw-r--r-- | sql/mf_iocache.cc | 624 |
1 files changed, 1 insertions, 623 deletions
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index 40b98983291..55e953687a3 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -42,295 +42,6 @@ static void my_aiowait(my_aio_result *result); extern "C" { /* - ** if cachesize == 0 then use default cachesize (from s-file) - ** if file == -1 then real_open_cached_file() will be called. - ** returns 0 if ok - */ - -int init_io_cache(IO_CACHE *info, File file, uint cachesize, - enum cache_type type, my_off_t seek_offset, - pbool use_async_io, myf cache_myflags) -{ - uint min_cache; - DBUG_ENTER("init_io_cache"); - DBUG_PRINT("enter",("type: %d pos: %ld",(int) type, (ulong) seek_offset)); - - /* There is no file in net_reading */ - info->file= file; - info->pre_close = info->pre_read = info->post_read = 0; - info->arg = 0; - if (!cachesize) - if (! (cachesize= my_default_record_cache_size)) - DBUG_RETURN(1); /* No cache requested */ - min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2; - if (type == READ_CACHE) - { /* Assume file isn't growing */ - if (cache_myflags & MY_DONT_CHECK_FILESIZE) - { - cache_myflags &= ~MY_DONT_CHECK_FILESIZE; - } - else - { - my_off_t file_pos,end_of_file; - if ((file_pos=my_tell(file,MYF(0)) == MY_FILEPOS_ERROR)) - DBUG_RETURN(1); - end_of_file=my_seek(file,0L,MY_SEEK_END,MYF(0)); - if (end_of_file < seek_offset) - end_of_file=seek_offset; - VOID(my_seek(file,file_pos,MY_SEEK_SET,MYF(0))); - if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1) - { - cachesize=(uint) (end_of_file-seek_offset)+IO_SIZE*2-1; - use_async_io=0; /* No need to use async */ - } - } - } - if ((int) type < (int) READ_NET) - { - for (;;) - { - cachesize=(uint) ((ulong) (cachesize + min_cache-1) & - (ulong) ~(min_cache-1)); - if (cachesize < min_cache) - cachesize = min_cache; - if ((info->buffer= - (byte*) my_malloc(cachesize, - MYF((cache_myflags & ~ MY_WME) | - (cachesize == min_cache ? MY_WME : 0)))) != 0) - break; /* Enough memory found */ - if (cachesize == min_cache) - DBUG_RETURN(2); /* Can't alloc cache */ - cachesize= (uint) ((long) cachesize*3/4); /* Try with less memory */ - } - } - else - info->buffer=0; - DBUG_PRINT("info",("init_io_cache: cachesize = %u",cachesize)); - info->pos_in_file= seek_offset; - info->read_length=info->buffer_length=cachesize; - info->seek_not_done= test(file >= 0 && type != READ_FIFO && - type != READ_NET); - info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP); - info->rc_request_pos=info->rc_pos=info->buffer; - - if (type == READ_CACHE || type == READ_NET || type == READ_FIFO) - { - info->rc_end=info->buffer; /* Nothing in cache */ - } - else /* type == WRITE_CACHE */ - { - info->rc_end=info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1)); - } - /* end_of_file may be changed by user later */ - info->end_of_file= ((type == READ_NET || type == READ_FIFO ) ? 0 - : ~(my_off_t) 0); - info->type=type; - info->error=0; - info->read_function=(type == READ_NET) ? _my_b_net_read : _my_b_read; /* net | file */ -#ifdef HAVE_AIOWAIT - if (use_async_io && ! my_disable_async_io) - { - DBUG_PRINT("info",("Using async io")); - info->read_length/=2; - info->read_function=_my_b_async_read; - } - info->inited=info->aio_result.pending=0; -#endif - DBUG_RETURN(0); -} /* init_io_cache */ - - - /* Wait until current request is ready */ - -#ifdef HAVE_AIOWAIT -static void my_aiowait(my_aio_result *result) -{ - if (result->pending) - { - struct aio_result_t *tmp; - for (;;) - { - if ((int) (tmp=aiowait((struct timeval *) 0)) == -1) - { - if (errno == EINTR) - continue; - DBUG_PRINT("error",("No aio request, error: %d",errno)); - result->pending=0; /* Assume everythings is ok */ - break; - } - ((my_aio_result*) tmp)->pending=0; - if ((my_aio_result*) tmp == result) - break; - } - } - return; -} -#endif - - /* Use this to reset cache to start or other type */ - /* Some simple optimizing is done when reinit in current buffer */ - -my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, - my_off_t seek_offset, - pbool use_async_io __attribute__((unused)), - pbool clear_cache) -{ - DBUG_ENTER("reinit_io_cache"); - - info->seek_not_done= test(info->file >= 0); /* Seek not done */ - - /* If the whole file is in memory, avoid flushing to disk */ - if (! clear_cache && - seek_offset >= info->pos_in_file && - seek_offset <= info->pos_in_file + - (uint) (info->rc_end - info->rc_request_pos)) - { /* use current buffer */ - if (info->type == WRITE_CACHE && type == READ_CACHE) - { - info->rc_end=info->rc_pos; - info->end_of_file=my_b_tell(info); - } - else if (type == WRITE_CACHE) - { - if (info->type == READ_CACHE) - info->rc_end=info->buffer+info->buffer_length; - info->end_of_file = ~(my_off_t) 0; - } - info->rc_pos=info->rc_request_pos+(seek_offset-info->pos_in_file); -#ifdef HAVE_AIOWAIT - my_aiowait(&info->aio_result); /* Wait for outstanding req */ -#endif - } - else - { - /* - If we change from WRITE_CACHE to READ_CACHE, assume that everything - after the current positions should be ignored - */ - if (info->type == WRITE_CACHE && type == READ_CACHE) - info->end_of_file=my_b_tell(info); - /* No need to flush cache if we want to reuse it */ - if ((type != WRITE_CACHE || !clear_cache) && flush_io_cache(info)) - DBUG_RETURN(1); - if (info->pos_in_file != seek_offset) - { - info->pos_in_file=seek_offset; - info->seek_not_done=1; - } - info->rc_request_pos=info->rc_pos=info->buffer; - if (type == READ_CACHE || type == READ_NET || type == READ_FIFO) - { - info->rc_end=info->buffer; /* Nothing in cache */ - } - else - { - info->rc_end=info->buffer+info->buffer_length- - (seek_offset & (IO_SIZE-1)); - info->end_of_file= ((type == READ_NET || type == READ_FIFO) ? 0 : - ~(my_off_t) 0); - } - } - info->type=type; - info->error=0; - info->read_function=(type == READ_NET) ? _my_b_net_read : _my_b_read; -#ifdef HAVE_AIOWAIT - if (type != READ_NET) - { - if (use_async_io && ! my_disable_async_io && - ((ulong) info->buffer_length < - (ulong) (info->end_of_file - seek_offset))) - { - info->read_length=info->buffer_length/2; - info->read_function=_my_b_async_read; - } - } - info->inited=0; -#endif - DBUG_RETURN(0); -} /* init_io_cache */ - - - - /* - Read buffered. Returns 1 if can't read requested characters - This function is only called from the my_b_read() macro - when there isn't enough characters in the buffer to - satisfy the request. - Returns 0 we succeeded in reading all data - */ - -int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count) -{ - uint length,diff_length,left_length; - my_off_t max_length, pos_in_file; - - if ((left_length=(uint) (info->rc_end-info->rc_pos))) - { - dbug_assert(Count >= left_length); /* User is not using my_b_read() */ - memcpy(Buffer,info->rc_pos, (size_t) (left_length)); - Buffer+=left_length; - Count-=left_length; - } - /* pos_in_file always point on where info->buffer was read */ - pos_in_file=info->pos_in_file+(uint) (info->rc_end - info->buffer); - if (info->seek_not_done) - { /* File touched, do seek */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); - info->seek_not_done=0; - } - diff_length=(uint) (pos_in_file & (IO_SIZE-1)); - if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length))) - { /* Fill first intern buffer */ - uint read_length; - if (info->end_of_file == pos_in_file) - { /* End of file */ - info->error=(int) left_length; - return 1; - } - length=(Count & (uint) ~(IO_SIZE-1))-diff_length; - if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags)) - != (uint) length) - { - info->error= read_length == (uint) -1 ? -1 : - (int) (read_length+left_length); - return 1; - } - Count-=length; - Buffer+=length; - pos_in_file+=length; - left_length+=length; - diff_length=0; - } - max_length=info->read_length-diff_length; - if (info->type != READ_FIFO && - (info->end_of_file - pos_in_file) < max_length) - max_length = info->end_of_file - pos_in_file; - if (!max_length) - { - if (Count) - { - info->error= left_length; /* We only got this many char */ - return 1; - } - length=0; /* Didn't read any chars */ - } - else if ((length=my_read(info->file,info->buffer,(uint) max_length, - info->myflags)) < Count || - length == (uint) -1) - { - if (length != (uint) -1) - memcpy(Buffer,info->buffer,(size_t) length); - info->error= length == (uint) -1 ? -1 : (int) (length+left_length); - return 1; - } - info->rc_pos=info->buffer+Count; - info->rc_end=info->buffer+length; - info->pos_in_file=pos_in_file; - memcpy(Buffer,info->buffer,(size_t) Count); - return 0; -} - - /* ** Read buffered from the net. ** Returns 1 if can't read requested characters ** Returns 0 if record read @@ -359,341 +70,8 @@ int _my_b_net_read(register IO_CACHE *info, byte *Buffer, info->rc_end = (info->rc_pos = (byte*) net->read_pos) + read_length; Buffer[0] = info->rc_pos[0]; /* length is always 1 */ info->rc_pos++; + info->buffer = info->rc_pos; return 0; } -#ifdef HAVE_AIOWAIT - -int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count) -{ - uint length,read_length,diff_length,left_length,use_length,org_Count; - my_off_t max_length; - my_off_t next_pos_in_file; - byte *read_buffer; - - memcpy(Buffer,info->rc_pos, - (size_t) (left_length=(uint) (info->rc_end-info->rc_pos))); - Buffer+=left_length; - org_Count=Count; - Count-=left_length; - - if (info->inited) - { /* wait for read block */ - info->inited=0; /* No more block to read */ - my_aiowait(&info->aio_result); /* Wait for outstanding req */ - if (info->aio_result.result.aio_errno) - { - if (info->myflags & MY_WME) - my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), - my_filename(info->file), - info->aio_result.result.aio_errno); - my_errno=info->aio_result.result.aio_errno; - info->error= -1; - return(1); - } - if (! (read_length = (uint) info->aio_result.result.aio_return) || - read_length == (uint) -1) - { - my_errno=0; /* For testing */ - info->error= (read_length == (uint) -1 ? -1 : - (int) (read_length+left_length)); - return(1); - } - info->pos_in_file+=(uint) (info->rc_end - info->rc_request_pos); - - if (info->rc_request_pos != info->buffer) - info->rc_request_pos=info->buffer; - else - info->rc_request_pos=info->buffer+info->read_length; - info->rc_pos=info->rc_request_pos; - next_pos_in_file=info->aio_read_pos+read_length; - - /* Check if pos_in_file is changed - (_ni_read_cache may have skipped some bytes) */ - - if (info->aio_read_pos < info->pos_in_file) - { /* Fix if skipped bytes */ - if (info->aio_read_pos + read_length < info->pos_in_file) - { - read_length=0; /* Skipp block */ - next_pos_in_file=info->pos_in_file; - } - else - { - my_off_t offset= (info->pos_in_file - info->aio_read_pos); - info->pos_in_file=info->aio_read_pos; /* Whe are here */ - info->rc_pos=info->rc_request_pos+offset; - read_length-=offset; /* Bytes left from rc_pos */ - } - } -#ifndef DBUG_OFF - if (info->aio_read_pos > info->pos_in_file) - { - my_errno=EINVAL; - return(info->read_length= -1); - } -#endif - /* Copy found bytes to buffer */ - length=min(Count,read_length); - memcpy(Buffer,info->rc_pos,(size_t) length); - Buffer+=length; - Count-=length; - left_length+=length; - info->rc_end=info->rc_pos+read_length; - info->rc_pos+=length; - } - else - next_pos_in_file=(info->pos_in_file+ (uint) - (info->rc_end - info->rc_request_pos)); - - /* If reading large blocks, or first read or read with skipp */ - if (Count) - { - if (next_pos_in_file == info->end_of_file) - { - info->error=(int) (read_length+left_length); - return 1; - } - VOID(my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0))); - read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1)); - if (Count < read_length) - { /* Small block, read to cache */ - if ((read_length=my_read(info->file,info->rc_request_pos, - read_length, info->myflags)) == (uint) -1) - return info->error= -1; - use_length=min(Count,read_length); - memcpy(Buffer,info->rc_request_pos,(size_t) use_length); - info->rc_pos=info->rc_request_pos+Count; - info->rc_end=info->rc_request_pos+read_length; - info->pos_in_file=next_pos_in_file; /* Start of block in cache */ - next_pos_in_file+=read_length; - - if (Count != use_length) - { /* Didn't find hole block */ - if (info->myflags & (MY_WME | MY_FAE | MY_FNABP) && Count != org_Count) - my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), - my_filename(info->file),my_errno); - info->error=(int) (read_length+left_length); - return 1; - } - } - else - { /* Big block, don't cache it */ - if ((read_length=my_read(info->file,Buffer,(uint) Count,info->myflags)) - != Count) - { - info->error= read_length == (uint) -1 ? -1 : read_length+left_length; - return 1; - } - info->rc_pos=info->rc_end=info->rc_request_pos; - info->pos_in_file=(next_pos_in_file+=Count); - } - } - - /* Read next block with asyncronic io */ - max_length=info->end_of_file - next_pos_in_file; - diff_length=(next_pos_in_file & (IO_SIZE-1)); - - if (max_length > (my_off_t) info->read_length - diff_length) - max_length= (my_off_t) info->read_length - diff_length; - if (info->rc_request_pos != info->buffer) - read_buffer=info->buffer; - else - read_buffer=info->buffer+info->read_length; - info->aio_read_pos=next_pos_in_file; - if (max_length) - { - info->aio_result.result.aio_errno=AIO_INPROGRESS; /* Marker for test */ - DBUG_PRINT("aioread",("filepos: %ld length: %ld", - (ulong) next_pos_in_file,(ulong) max_length)); - if (aioread(info->file,read_buffer,(int) max_length, - (my_off_t) next_pos_in_file,MY_SEEK_SET, - &info->aio_result.result)) - { /* Skipp async io */ - my_errno=errno; - DBUG_PRINT("error",("got error: %d, aio_result: %d from aioread, async skipped", - errno, info->aio_result.result.aio_errno)); - if (info->rc_request_pos != info->buffer) - { - bmove(info->buffer,info->rc_request_pos, - (uint) (info->rc_end - info->rc_pos)); - info->rc_request_pos=info->buffer; - info->rc_pos-=info->read_length; - info->rc_end-=info->read_length; - } - info->read_length=info->buffer_length; /* Use hole buffer */ - info->read_function=_my_b_read; /* Use normal IO_READ next */ - } - else - info->inited=info->aio_result.pending=1; - } - return 0; /* Block read, async in use */ -} /* _my_b_async_read */ -#endif - - -/* Read one byte when buffer is empty */ - -int _my_b_get(IO_CACHE *info) -{ - byte buff; - IO_CACHE_CALLBACK pre_read,post_read; - if ((pre_read = info->pre_read)) - (*pre_read)(info); - if ((*(info)->read_function)(info,&buff,1)) - return my_b_EOF; - if ((post_read = info->post_read)) - (*post_read)(info); - return (int) (uchar) buff; -} - - /* Returns != 0 if error on write */ - -int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) -{ - uint rest_length,length; - - rest_length=(uint) (info->rc_end - info->rc_pos); - memcpy(info->rc_pos,Buffer,(size_t) rest_length); - Buffer+=rest_length; - Count-=rest_length; - info->rc_pos+=rest_length; - if (info->pos_in_file+info->buffer_length > info->end_of_file) - { - my_errno=errno=EFBIG; - return info->error = -1; - } - if (flush_io_cache(info)) - return 1; - if (Count >= IO_SIZE) - { /* Fill first intern buffer */ - length=Count & (uint) ~(IO_SIZE-1); - if (info->seek_not_done) - { /* File touched, do seek */ - VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0))); - info->seek_not_done=0; - } - if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP)) - return info->error= -1; - Count-=length; - Buffer+=length; - info->pos_in_file+=length; - } - memcpy(info->rc_pos,Buffer,(size_t) Count); - info->rc_pos+=Count; - return 0; -} - - -/* - Write a block to disk where part of the data may be inside the record - buffer. As all write calls to the data goes through the cache, - we will never get a seek over the end of the buffer -*/ - -int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count, - my_off_t pos) -{ - uint length; - int error=0; - - if (pos < info->pos_in_file) - { - /* Of no overlap, write everything without buffering */ - if (pos + Count <= info->pos_in_file) - return my_pwrite(info->file, Buffer, Count, pos, - info->myflags | MY_NABP); - /* Write the part of the block that is before buffer */ - length= (uint) (info->pos_in_file - pos); - if (my_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP)) - info->error=error=-1; - Buffer+=length; - pos+= length; - Count-= length; - } - - /* Check if we want to write inside the used part of the buffer.*/ - length= (uint) (info->rc_end - info->buffer); - if (pos < info->pos_in_file + length) - { - uint offset= (uint) (pos - info->pos_in_file); - length-=offset; - if (length > Count) - length=Count; - memcpy(info->buffer+offset, Buffer, length); - Buffer+=length; - Count-= length; - /* Fix length of buffer if the new data was larger */ - if (info->buffer+length > info->rc_pos) - info->rc_pos=info->buffer+length; - if (!Count) - return (error); - } - /* Write at the end of the current buffer; This is the normal case */ - if (_my_b_write(info, Buffer, Count)) - error= -1; - return error; -} - - /* Flush write cache */ - -int flush_io_cache(IO_CACHE *info) -{ - uint length; - DBUG_ENTER("flush_io_cache"); - - if (info->type == WRITE_CACHE) - { - if (info->file == -1) - { - if (real_open_cached_file(info)) - DBUG_RETURN((info->error= -1)); - } - if (info->rc_pos != info->buffer) - { - length=(uint) (info->rc_pos - info->buffer); - if (info->seek_not_done) - { /* File touched, do seek */ - if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)) == - MY_FILEPOS_ERROR) - DBUG_RETURN((info->error= -1)); - info->seek_not_done=0; - } - info->rc_pos=info->buffer; - info->pos_in_file+=length; - info->rc_end=(info->buffer+info->buffer_length- - (info->pos_in_file & (IO_SIZE-1))); - if (my_write(info->file,info->buffer,length,info->myflags | MY_NABP)) - DBUG_RETURN((info->error= -1)); - DBUG_RETURN(0); - } - } -#ifdef HAVE_AIOWAIT - else if (info->type != READ_NET) - { - my_aiowait(&info->aio_result); /* Wait for outstanding req */ - info->inited=0; - } -#endif - DBUG_RETURN(0); -} - - -int end_io_cache(IO_CACHE *info) -{ - int error=0; - IO_CACHE_CALLBACK pre_close; - DBUG_ENTER("end_io_cache"); - if((pre_close=info->pre_close)) - (*pre_close)(info); - if (info->buffer) - { - if (info->file != -1) /* File doesn't exist */ - error=flush_io_cache(info); - my_free((gptr) info->buffer,MYF(MY_WME)); - info->buffer=info->rc_pos=(byte*) 0; - } - DBUG_RETURN(error); -} /* end_io_cache */ - } /* extern "C" */ |