diff options
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/CMakeLists.txt | 2 | ||||
-rw-r--r-- | mysys/Makefile.am | 2 | ||||
-rw-r--r-- | mysys/base64.c | 65 | ||||
-rw-r--r-- | mysys/charset.c | 15 | ||||
-rwxr-xr-x | mysys/make-ccc | 2 | ||||
-rw-r--r-- | mysys/mf_iocache.c | 686 | ||||
-rw-r--r-- | mysys/mf_iocache2.c | 48 | ||||
-rw-r--r-- | mysys/my_chsize.c | 6 | ||||
-rw-r--r-- | mysys/my_lock.c | 39 | ||||
-rw-r--r-- | mysys/my_lread.c | 53 | ||||
-rw-r--r-- | mysys/my_lwrite.c | 46 | ||||
-rw-r--r-- | mysys/my_pread.c | 12 | ||||
-rw-r--r-- | mysys/my_quick.c | 26 | ||||
-rw-r--r-- | mysys/my_read.c | 9 | ||||
-rw-r--r-- | mysys/my_seek.c | 35 | ||||
-rw-r--r-- | mysys/my_write.c | 20 | ||||
-rw-r--r-- | mysys/thr_alarm.c | 3 | ||||
-rw-r--r-- | mysys/thr_lock.c | 2 |
18 files changed, 823 insertions, 248 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 4aa99a70121..7b362b4c1f9 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -20,7 +20,7 @@ ADD_LIBRARY(mysys array.c charset-def.c charset.c checksum.c default.c default_m my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c my_div.c my_error.c my_file.c my_fopen.c my_fstream.c my_gethostbyname.c my_gethwaddr.c my_getopt.c my_getsystime.c my_getwd.c my_handler.c my_init.c - my_lib.c my_lock.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c + my_lib.c my_lock.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 4d9570febbd..789295220f1 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -45,7 +45,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ tree.c trie.c list.c hash.c array.c string.c typelib.c \ my_copy.c my_append.c my_lib.c \ my_delete.c my_rename.c my_redel.c \ - my_chsize.c my_lread.c my_lwrite.c my_clock.c \ + my_chsize.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ my_sync.c my_getopt.c my_mkdir.c \ default_modify.c default.c \ diff --git a/mysys/base64.c b/mysys/base64.c index fb51bdb3a60..363aa2cc739 100644 --- a/mysys/base64.c +++ b/mysys/base64.c @@ -125,44 +125,69 @@ pos(unsigned char c) /* Decode a base64 string - Note: We require that dst is pre-allocated to correct size. - See base64_needed_decoded_length(). - - RETURN Number of bytes produced in dst or -1 in case of failure + SYNOPSIS + base64_decode() + src Pointer to base64-encoded string + len Length of string at 'src' + dst Pointer to location where decoded data will be stored + end_ptr Pointer to variable that will refer to the character + after the end of the encoded data that were decoded. Can + be NULL. + + DESCRIPTION + + The base64-encoded data in the range ['src','*end_ptr') will be + decoded and stored starting at 'dst'. The decoding will stop + after 'len' characters have been read from 'src', or when padding + occurs in the base64-encoded data. In either case: if 'end_ptr' is + non-null, '*end_ptr' will be set to point to the character after + the last read character, even in the presence of error. + + NOTE + We require that 'dst' is pre-allocated to correct size. + + SEE ALSO + base64_needed_decoded_length(). + + RETURN VALUE + Number of bytes written at 'dst' or -1 in case of failure */ int -base64_decode(const char *src, size_t size, void *dst) +base64_decode(const char *const src_base, size_t const len, + void *dst, const char **end_ptr) { char b[3]; size_t i= 0; char *dst_base= (char *)dst; + char const *src= src_base; char *d= dst_base; size_t j; - while (i < size) + while (i < len) { unsigned c= 0; size_t mark= 0; - SKIP_SPACE(src, i, size); + SKIP_SPACE(src, i, len); c += pos(*src++); c <<= 6; i++; - SKIP_SPACE(src, i, size); + SKIP_SPACE(src, i, len); c += pos(*src++); c <<= 6; i++; - SKIP_SPACE(src, i, size); + SKIP_SPACE(src, i, len); - if (* src != '=') + if (*src != '=') c += pos(*src++); else { - i= size; + src += 2; /* There should be two bytes padding */ + i= len; mark= 2; c <<= 6; goto end; @@ -170,13 +195,14 @@ base64_decode(const char *src, size_t size, void *dst) c <<= 6; i++; - SKIP_SPACE(src, i, size); + SKIP_SPACE(src, i, len); if (*src != '=') c += pos(*src++); else { - i= size; + src += 1; /* There should be one byte padding */ + i= len; mark= 1; goto end; } @@ -191,11 +217,14 @@ base64_decode(const char *src, size_t size, void *dst) *d++= b[j]; } - if (i != size) - { - return -1; - } - return d - dst_base; + if (end_ptr != NULL) + *end_ptr= src; + + /* + The variable 'i' is set to 'len' when padding has been read, so it + does not actually reflect the number of bytes read from 'src'. + */ + return i != len ? -1 : d - dst_base; } diff --git a/mysys/charset.c b/mysys/charset.c index 64b15fab0c2..d10a580ae4e 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -312,7 +312,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) { char *buf; int fd; - uint len; + uint len, tmp_len; MY_STAT stat_info; if (!my_stat(filename, &stat_info, MYF(myflags)) || @@ -321,12 +321,11 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) return TRUE; if ((fd=my_open(filename,O_RDONLY,myflags)) < 0) - { - my_free(buf,myflags); - return TRUE; - } - len=read(fd,buf,len); + goto error; + tmp_len=my_read(fd, buf, len, myflags); my_close(fd,myflags); + if (tmp_len != len) + goto error; if (my_parse_charset_xml(buf,len,add_collation)) { @@ -340,6 +339,10 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) my_free(buf, myflags); return FALSE; + +error: + my_free(buf, myflags); + return TRUE; } diff --git a/mysys/make-ccc b/mysys/make-ccc index 9c54185682a..b34bd80e1d1 100755 --- a/mysys/make-ccc +++ b/mysys/make-ccc @@ -1,4 +1,4 @@ rm -f .deps/* raid.o mf_iocache.o libmysys.a -ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c +ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c make raid.o mf_iocache.o my_lock.o ar -cr libmysys.a array.o raid.o mf_iocache.o my_lock.o diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index cd2a140182e..249eaf48ad2 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -70,7 +70,6 @@ static void my_aiowait(my_aio_result *result); #define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1)) #define IO_ROUND_DN(X) ( (X) & ~(IO_SIZE-1)) - /* Setup internal pointers inside IO_CACHE @@ -333,7 +332,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, { info->read_end=info->write_pos; info->end_of_file=my_b_tell(info); - info->seek_not_done=1; + /* + Trigger a new seek only if we have a valid + file handle. + */ + info->seek_not_done= (info->file != -1); } else if (type == WRITE_CACHE) { @@ -442,11 +445,24 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count) /* pos_in_file always point on where info->buffer was read */ pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer); + + /* + Whenever a function which operates on IO_CACHE flushes/writes + some part of the IO_CACHE to disk it will set the property + "seek_not_done" to indicate this to other functions operating + on the IO_CACHE. + */ if (info->seek_not_done) - { /* File touched, do seek */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); + { + if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + DBUG_RETURN(1); + } 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 */ @@ -502,65 +518,366 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count) DBUG_RETURN(0); } + #ifdef THREAD -/* Prepare IO_CACHE for shared use */ -void init_io_cache_share(IO_CACHE *info, IO_CACHE_SHARE *s, uint num_threads) +/* + Prepare IO_CACHE for shared use. + + SYNOPSIS + init_io_cache_share() + read_cache A read cache. This will be copied for + every thread after setup. + cshare The share. + write_cache If non-NULL a write cache that is to be + synchronized with the read caches. + num_threads Number of threads sharing the cache + including the write thread if any. + + DESCRIPTION + + The shared cache is used so: One IO_CACHE is initialized with + init_io_cache(). This includes the allocation of a buffer. Then a + share is allocated and init_io_cache_share() is called with the io + cache and the share. Then the io cache is copied for each thread. So + every thread has its own copy of IO_CACHE. But the allocated buffer + is shared because cache->buffer is the same for all caches. + + One thread reads data from the file into the buffer. All threads + read from the buffer, but every thread maintains its own set of + pointers into the buffer. When all threads have used up the buffer + contents, one of the threads reads the next block of data into the + buffer. To accomplish this, each thread enters the cache lock before + accessing the buffer. They wait in lock_io_cache() until all threads + joined the lock. The last thread entering the lock is in charge of + reading from file to buffer. It wakes all threads when done. + + Synchronizing a write cache to the read caches works so: Whenever + the write buffer needs a flush, the write thread enters the lock and + waits for all other threads to enter the lock too. They do this when + they have used up the read buffer. When all threads are in the lock, + the write thread copies the write buffer to the read buffer and + wakes all threads. + + share->running_threads is the number of threads not being in the + cache lock. When entering lock_io_cache() the number is decreased. + When the thread that fills the buffer enters unlock_io_cache() the + number is reset to the number of threads. The condition + running_threads == 0 means that all threads are in the lock. Bumping + up the number to the full count is non-intuitive. But increasing the + number by one for each thread that leaves the lock could lead to a + solo run of one thread. The last thread to join a lock reads from + file to buffer, wakes the other threads, processes the data in the + cache and enters the lock again. If no other thread left the lock + meanwhile, it would think it's the last one again and read the next + block... + + The share has copies of 'error', 'buffer', 'read_end', and + 'pos_in_file' from the thread that filled the buffer. We may not be + able to access this information directly from its cache because the + thread may be removed from the share before the variables could be + copied by all other threads. Or, if a write buffer is synchronized, + it would change its 'pos_in_file' after waking the other threads, + possibly before they could copy its value. + + However, the 'buffer' variable in the share is for a synchronized + write cache. It needs to know where to put the data. Otherwise it + would need access to the read cache of one of the threads that is + not yet removed from the share. + + RETURN + void +*/ + +void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, + IO_CACHE *write_cache, uint num_threads) { - DBUG_ASSERT(info->type == READ_CACHE); - pthread_mutex_init(&s->mutex, MY_MUTEX_INIT_FAST); - pthread_cond_init (&s->cond, 0); - s->total=s->count=num_threads-1; - s->active=0; - info->share=s; - info->read_function=_my_b_read_r; - info->current_pos= info->current_end= 0; + DBUG_ENTER("init_io_cache_share"); + DBUG_PRINT("io_cache_share", ("read_cache: 0x%lx share: 0x%lx " + "write_cache: 0x%lx threads: %u", + read_cache, cshare, write_cache, num_threads)); + + DBUG_ASSERT(num_threads > 1); + DBUG_ASSERT(read_cache->type == READ_CACHE); + DBUG_ASSERT(!write_cache || (write_cache->type == WRITE_CACHE)); + + pthread_mutex_init(&cshare->mutex, MY_MUTEX_INIT_FAST); + pthread_cond_init(&cshare->cond, 0); + pthread_cond_init(&cshare->cond_writer, 0); + + cshare->running_threads= num_threads; + cshare->total_threads= num_threads; + cshare->error= 0; /* Initialize. */ + cshare->buffer= read_cache->buffer; + cshare->read_end= NULL; /* See function comment of lock_io_cache(). */ + cshare->pos_in_file= 0; /* See function comment of lock_io_cache(). */ + cshare->source_cache= write_cache; /* Can be NULL. */ + + read_cache->share= cshare; + read_cache->read_function= _my_b_read_r; + read_cache->current_pos= NULL; + read_cache->current_end= NULL; + + if (write_cache) + write_cache->share= cshare; + + DBUG_VOID_RETURN; } + /* - Remove a thread from shared access to IO_CACHE - Every thread should do that on exit for not - to deadlock other threads + Remove a thread from shared access to IO_CACHE. + + SYNOPSIS + remove_io_thread() + cache The IO_CACHE to be removed from the share. + + NOTE + + Every thread must do that on exit for not to deadlock other threads. + + The last thread destroys the pthread resources. + + A writer flushes its cache first. + + RETURN + void */ -void remove_io_thread(IO_CACHE *info) + +void remove_io_thread(IO_CACHE *cache) { - IO_CACHE_SHARE *s=info->share; + IO_CACHE_SHARE *cshare= cache->share; + uint total; + DBUG_ENTER("remove_io_thread"); + + /* If the writer goes, it needs to flush the write cache. */ + if (cache == cshare->source_cache) + flush_io_cache(cache); + + pthread_mutex_lock(&cshare->mutex); + DBUG_PRINT("io_cache_share", ("%s: 0x%lx", + (cache == cshare->source_cache) ? + "writer" : "reader", cache)); + + /* Remove from share. */ + total= --cshare->total_threads; + DBUG_PRINT("io_cache_share", ("remaining threads: %u", total)); + + /* Detach from share. */ + cache->share= NULL; + + /* If the writer goes, let the readers know. */ + if (cache == cshare->source_cache) + { + DBUG_PRINT("io_cache_share", ("writer leaves")); + cshare->source_cache= NULL; + } + + /* If all threads are waiting for me to join the lock, wake them. */ + if (!--cshare->running_threads) + { + DBUG_PRINT("io_cache_share", ("the last running thread leaves, wake all")); + pthread_cond_signal(&cshare->cond_writer); + pthread_cond_broadcast(&cshare->cond); + } + + pthread_mutex_unlock(&cshare->mutex); + + if (!total) + { + DBUG_PRINT("io_cache_share", ("last thread removed, destroy share")); + pthread_cond_destroy (&cshare->cond_writer); + pthread_cond_destroy (&cshare->cond); + pthread_mutex_destroy(&cshare->mutex); + } - pthread_mutex_lock(&s->mutex); - s->total--; - if (! s->count--) - pthread_cond_signal(&s->cond); - pthread_mutex_unlock(&s->mutex); + DBUG_VOID_RETURN; } -static int lock_io_cache(IO_CACHE *info, my_off_t pos) -{ - int total; - IO_CACHE_SHARE *s=info->share; - pthread_mutex_lock(&s->mutex); - if (!s->count) +/* + Lock IO cache and wait for all other threads to join. + + SYNOPSIS + lock_io_cache() + cache The cache of the thread entering the lock. + pos File position of the block to read. + Unused for the write thread. + + DESCRIPTION + + Wait for all threads to finish with the current buffer. We want + all threads to proceed in concert. The last thread to join + lock_io_cache() will read the block from file and all threads start + to use it. Then they will join again for reading the next block. + + The waiting threads detect a fresh buffer by comparing + cshare->pos_in_file with the position they want to process next. + Since the first block may start at position 0, we take + cshare->read_end as an additional condition. This variable is + initialized to NULL and will be set after a block of data is written + to the buffer. + + RETURN + 1 OK, lock in place, go ahead and read. + 0 OK, unlocked, another thread did the read. +*/ + +static int lock_io_cache(IO_CACHE *cache, my_off_t pos) +{ + IO_CACHE_SHARE *cshare= cache->share; + DBUG_ENTER("lock_io_cache"); + + /* Enter the lock. */ + pthread_mutex_lock(&cshare->mutex); + cshare->running_threads--; + DBUG_PRINT("io_cache_share", ("%s: 0x%lx pos: %lu running: %u", + (cache == cshare->source_cache) ? + "writer" : "reader", cache, (ulong) pos, + cshare->running_threads)); + + if (cshare->source_cache) { - s->count=s->total; - return 1; + /* A write cache is synchronized to the read caches. */ + + if (cache == cshare->source_cache) + { + /* The writer waits until all readers are here. */ + while (cshare->running_threads) + { + DBUG_PRINT("io_cache_share", ("writer waits in lock")); + pthread_cond_wait(&cshare->cond_writer, &cshare->mutex); + } + DBUG_PRINT("io_cache_share", ("writer awoke, going to copy")); + + /* Stay locked. Leave the lock later by unlock_io_cache(). */ + DBUG_RETURN(1); + } + + /* The last thread wakes the writer. */ + if (!cshare->running_threads) + { + DBUG_PRINT("io_cache_share", ("waking writer")); + pthread_cond_signal(&cshare->cond_writer); + } + + /* + Readers wait until the data is copied from the writer. Another + reason to stop waiting is the removal of the write thread. If this + happens, we leave the lock with old data in the buffer. + */ + while ((!cshare->read_end || (cshare->pos_in_file < pos)) && + cshare->source_cache) + { + DBUG_PRINT("io_cache_share", ("reader waits in lock")); + pthread_cond_wait(&cshare->cond, &cshare->mutex); + } + + /* + If the writer was removed from the share while this thread was + asleep, we need to simulate an EOF condition. The writer cannot + reset the share variables as they might still be in use by readers + of the last block. When we awake here then because the last + joining thread signalled us. If the writer is not the last, it + will not signal. So it is safe to clear the buffer here. + */ + if (!cshare->read_end || (cshare->pos_in_file < pos)) + { + DBUG_PRINT("io_cache_share", ("reader found writer removed. EOF")); + cshare->read_end= cshare->buffer; /* Empty buffer. */ + cshare->error= 0; /* EOF is not an error. */ + } } + else + { + /* + There are read caches only. The last thread arriving in + lock_io_cache() continues with a locked cache and reads the block. + */ + if (!cshare->running_threads) + { + DBUG_PRINT("io_cache_share", ("last thread joined, going to read")); + /* Stay locked. Leave the lock later by unlock_io_cache(). */ + DBUG_RETURN(1); + } + + /* + All other threads wait until the requested block is read by the + last thread arriving. Another reason to stop waiting is the + removal of a thread. If this leads to all threads being in the + lock, we have to continue also. The first of the awaken threads + will then do the read. + */ + while ((!cshare->read_end || (cshare->pos_in_file < pos)) && + cshare->running_threads) + { + DBUG_PRINT("io_cache_share", ("reader waits in lock")); + pthread_cond_wait(&cshare->cond, &cshare->mutex); + } - total=s->total; - s->count--; - while (!s->active || s->active->pos_in_file < pos) - pthread_cond_wait(&s->cond, &s->mutex); + /* If the block is not yet read, continue with a locked cache and read. */ + if (!cshare->read_end || (cshare->pos_in_file < pos)) + { + DBUG_PRINT("io_cache_share", ("reader awoke, going to read")); + /* Stay locked. Leave the lock later by unlock_io_cache(). */ + DBUG_RETURN(1); + } - if (s->total < total && - (!s->active || s->active->pos_in_file < pos)) - return 1; + /* Another thread did read the block already. */ + } + DBUG_PRINT("io_cache_share", ("reader awoke, going to process %u bytes", + cshare->read_end ? (uint) + (cshare->read_end - cshare->buffer) : 0)); - pthread_mutex_unlock(&s->mutex); - return 0; + /* + Leave the lock. Do not call unlock_io_cache() later. The thread that + filled the buffer did this and marked all threads as running. + */ + pthread_mutex_unlock(&cshare->mutex); + DBUG_RETURN(0); } -static void unlock_io_cache(IO_CACHE *info) + +/* + Unlock IO cache. + + SYNOPSIS + unlock_io_cache() + cache The cache of the thread leaving the lock. + + NOTE + This is called by the thread that filled the buffer. It marks all + threads as running and awakes them. This must not be done by any + other thread. + + Do not signal cond_writer. Either there is no writer or the writer + is the only one who can call this function. + + The reason for resetting running_threads to total_threads before + waking all other threads is that it could be possible that this + thread is so fast with processing the buffer that it enters the lock + before even one other thread has left it. If every awoken thread + would increase running_threads by one, this thread could think that + he is again the last to join and would not wait for the other + threads to process the data. + + RETURN + void +*/ + +static void unlock_io_cache(IO_CACHE *cache) { - pthread_cond_broadcast(&info->share->cond); - pthread_mutex_unlock(&info->share->mutex); + IO_CACHE_SHARE *cshare= cache->share; + DBUG_ENTER("unlock_io_cache"); + DBUG_PRINT("io_cache_share", ("%s: 0x%lx pos: %lu running: %u", + (cache == cshare->source_cache) ? + "writer" : "reader", + cache, (ulong) cshare->pos_in_file, + cshare->total_threads)); + + cshare->running_threads= cshare->total_threads; + pthread_cond_broadcast(&cshare->cond); + pthread_mutex_unlock(&cshare->mutex); + DBUG_VOID_RETURN; } @@ -569,7 +886,7 @@ static void unlock_io_cache(IO_CACHE *info) SYNOPSIS _my_b_read_r() - info IO_CACHE pointer + cache IO_CACHE pointer Buffer Buffer to retrieve count bytes from file Count Number of bytes to read into Buffer @@ -581,7 +898,7 @@ static void unlock_io_cache(IO_CACHE *info) It works as follows: when a thread tries to read from a file (that is, after using all the data from the (shared) buffer), it just - hangs on lock_io_cache(), wating for other threads. When the very + hangs on lock_io_cache(), waiting for other threads. When the very last thread attempts a read, lock_io_cache() returns 1, the thread does actual IO and unlock_io_cache(), which signals all the waiting threads that data is in the buffer. @@ -601,16 +918,17 @@ static void unlock_io_cache(IO_CACHE *info) 1 Error: can't read requested characters */ -int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count) +int _my_b_read_r(register IO_CACHE *cache, byte *Buffer, uint Count) { my_off_t pos_in_file; uint length, diff_length, left_length; + IO_CACHE_SHARE *cshare= cache->share; DBUG_ENTER("_my_b_read_r"); - if ((left_length= (uint) (info->read_end - info->read_pos))) + if ((left_length= (uint) (cache->read_end - cache->read_pos))) { DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */ - memcpy(Buffer, info->read_pos, (size_t) (left_length)); + memcpy(Buffer, cache->read_pos, (size_t) (left_length)); Buffer+= left_length; Count-= left_length; } @@ -618,63 +936,160 @@ int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count) { int cnt, len; - pos_in_file= info->pos_in_file + (info->read_end - info->buffer); + pos_in_file= cache->pos_in_file + (cache->read_end - cache->buffer); diff_length= (uint) (pos_in_file & (IO_SIZE-1)); length=IO_ROUND_UP(Count+diff_length)-diff_length; - length=(length <= info->read_length) ? - length + IO_ROUND_DN(info->read_length - length) : - length - IO_ROUND_UP(length - info->read_length) ; - if (info->type != READ_FIFO && - (length > (info->end_of_file - pos_in_file))) - length= (uint) (info->end_of_file - pos_in_file); + length= ((length <= cache->read_length) ? + length + IO_ROUND_DN(cache->read_length - length) : + length - IO_ROUND_UP(length - cache->read_length)); + if (cache->type != READ_FIFO && + (length > (cache->end_of_file - pos_in_file))) + length= (uint) (cache->end_of_file - pos_in_file); if (length == 0) { - info->error= (int) left_length; + cache->error= (int) left_length; DBUG_RETURN(1); } - if (lock_io_cache(info, pos_in_file)) + if (lock_io_cache(cache, pos_in_file)) { - info->share->active=info; - if (info->seek_not_done) /* File touched, do seek */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); - len=(int)my_read(info->file,info->buffer, length, info->myflags); - info->read_end=info->buffer + (len == -1 ? 0 : len); - info->error=(len == (int)length ? 0 : len); - info->pos_in_file=pos_in_file; - unlock_io_cache(info); + /* With a synchronized write/read cache we won't come here... */ + DBUG_ASSERT(!cshare->source_cache); + /* + ... unless the writer has gone before this thread entered the + lock. Simulate EOF in this case. It can be distinguished by + cache->file. + */ + if (cache->file < 0) + len= 0; + else + { + /* + Whenever a function which operates on IO_CACHE flushes/writes + some part of the IO_CACHE to disk it will set the property + "seek_not_done" to indicate this to other functions operating + on the IO_CACHE. + */ + if (cache->seek_not_done) + { + if (my_seek(cache->file, pos_in_file, MY_SEEK_SET, MYF(0)) + == MY_FILEPOS_ERROR) + { + cache->error= -1; + unlock_io_cache(cache); + DBUG_RETURN(1); + } + } + len= (int) my_read(cache->file, cache->buffer, length, cache->myflags); + } + DBUG_PRINT("io_cache_share", ("read %d bytes", len)); + + cache->read_end= cache->buffer + (len == -1 ? 0 : len); + cache->error= (len == (int)length ? 0 : len); + cache->pos_in_file= pos_in_file; + + /* Copy important values to the share. */ + cshare->error= cache->error; + cshare->read_end= cache->read_end; + cshare->pos_in_file= pos_in_file; + + /* Mark all threads as running and wake them. */ + unlock_io_cache(cache); } else { - info->error= info->share->active->error; - info->read_end= info->share->active->read_end; - info->pos_in_file= info->share->active->pos_in_file; - len= (int) (info->error == -1 ? -1 : info->read_end-info->buffer); + /* + With a synchronized write/read cache readers always come here. + Copy important values from the share. + */ + cache->error= cshare->error; + cache->read_end= cshare->read_end; + cache->pos_in_file= cshare->pos_in_file; + + len= (int) ((cache->error == -1) ? -1 : cache->read_end - cache->buffer); } - info->read_pos=info->buffer; - info->seek_not_done=0; + cache->read_pos= cache->buffer; + cache->seek_not_done= 0; if (len <= 0) { - info->error= (int) left_length; + DBUG_PRINT("io_cache_share", ("reader error. len %d left %u", + len, left_length)); + cache->error= (int) left_length; DBUG_RETURN(1); } cnt= ((uint) len > Count) ? (int) Count : len; - memcpy(Buffer, info->read_pos, (size_t) cnt); + memcpy(Buffer, cache->read_pos, (size_t) cnt); Count -= cnt; Buffer+= cnt; left_length+= cnt; - info->read_pos+= cnt; + cache->read_pos+= cnt; } DBUG_RETURN(0); } -#endif /* - Do sequential read from the SEQ_READ_APPEND cache - we do this in three stages: + Copy data from write cache to read cache. + + SYNOPSIS + copy_to_read_buffer() + write_cache The write cache. + write_buffer The source of data, mostly the cache buffer. + write_length The number of bytes to copy. + + NOTE + The write thread will wait for all read threads to join the cache + lock. Then it copies the data over and wakes the read threads. + + RETURN + void +*/ + +static void copy_to_read_buffer(IO_CACHE *write_cache, + const byte *write_buffer, uint write_length) +{ + IO_CACHE_SHARE *cshare= write_cache->share; + + DBUG_ASSERT(cshare->source_cache == write_cache); + /* + write_length is usually less or equal to buffer_length. + It can be bigger if _my_b_write() is called with a big length. + */ + while (write_length) + { + uint copy_length= min(write_length, write_cache->buffer_length); + int __attribute__((unused)) rc; + + rc= lock_io_cache(write_cache, write_cache->pos_in_file); + /* The writing thread does always have the lock when it awakes. */ + DBUG_ASSERT(rc); + + memcpy(cshare->buffer, write_buffer, copy_length); + + cshare->error= 0; + cshare->read_end= cshare->buffer + copy_length; + cshare->pos_in_file= write_cache->pos_in_file; + + /* Mark all threads as running and wake them. */ + unlock_io_cache(write_cache); + + write_buffer+= copy_length; + write_length-= copy_length; + } +} +#endif /*THREAD*/ + + +/* + Do sequential read from the SEQ_READ_APPEND cache. + + We do this in three stages: - first read from info->buffer - then if there are still data to read, try the file descriptor - afterwards, if there are still data to read, try append buffer + + RETURNS + 0 Success + 1 Failed to read */ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count) @@ -702,7 +1117,13 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count) With read-append cache we must always do a seek before we read, because the write could have moved the file pointer astray */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); + if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + unlock_append_buffer(info); + return (1); + } info->seek_not_done=0; diff_length=(uint) (pos_in_file & (IO_SIZE-1)); @@ -818,6 +1239,21 @@ read_append_buffer: #ifdef HAVE_AIOWAIT +/* + Read from the IO_CACHE into a buffer and feed asynchronously + from disk when needed. + + SYNOPSIS + _my_b_async_read() + info IO_CACHE pointer + Buffer Buffer to retrieve count bytes from file + Count Number of bytes to read into Buffer + + RETURN VALUE + -1 An error has occurred; my_errno is set. + 0 Success + 1 An error has occurred; IO_CACHE to error state. +*/ 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; @@ -908,13 +1344,20 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count) info->error=(int) (read_length+left_length); return 1; } - VOID(my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0))); + + if (my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + return (1); + } + 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->request_pos, read_length, info->myflags)) == (uint) -1) - return info->error= -1; + return info->error= -1; use_length=min(Count,read_length); memcpy(Buffer,info->request_pos,(size_t) use_length); info->read_pos=info->request_pos+Count; @@ -1001,7 +1444,15 @@ int _my_b_get(IO_CACHE *info) return (int) (uchar) buff; } - /* Returns != 0 if error on write */ +/* + Write a byte buffer to IO_CACHE and flush to disk + if IO_CACHE is full. + + RETURN VALUE + 1 On error on write + 0 On success + -1 On error; my_errno contains error code. +*/ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) { @@ -1018,18 +1469,46 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) Buffer+=rest_length; Count-=rest_length; info->write_pos+=rest_length; + if (my_b_flush_io_cache(info,1)) 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))); + { + /* + Whenever a function which operates on IO_CACHE flushes/writes + some part of the IO_CACHE to disk it will set the property + "seek_not_done" to indicate this to other functions operating + on the IO_CACHE. + */ + if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0))) + { + info->error= -1; + return (1); + } info->seek_not_done=0; } if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP)) return info->error= -1; + +#ifdef THREAD + /* + In case of a shared I/O cache with a writer we normally do direct + write cache to read cache copy. Simulate this here by direct + caller buffer to read cache copy. Do it after the write so that + the cache readers actions on the flushed part can go in parallel + with the write of the extra stuff. copy_to_read_buffer() + synchronizes writer and readers so that after this call the + readers can act on the extra stuff while the writer can go ahead + and prepare the next output. copy_to_read_buffer() relies on + info->pos_in_file. + */ + if (info->share) + copy_to_read_buffer(info, Buffer, length); +#endif + Count-=length; Buffer+=length; info->pos_in_file+=length; @@ -1050,6 +1529,14 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count) { uint rest_length,length; +#ifdef THREAD + /* + Assert that we cannot come here with a shared cache. If we do one + day, we might need to add a call to copy_to_read_buffer(). + */ + DBUG_ASSERT(!info->share); +#endif + lock_append_buffer(info); rest_length=(uint) (info->write_end - info->write_pos); if (Count <= rest_length) @@ -1110,6 +1597,14 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count, uint length; int error=0; +#ifdef THREAD + /* + Assert that we cannot come here with a shared cache. If we do one + day, we might need to add a call to copy_to_read_buffer(). + */ + DBUG_ASSERT(!info->share); +#endif + if (pos < info->pos_in_file) { /* Of no overlap, write everything without buffering */ @@ -1186,6 +1681,17 @@ int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock) if ((length=(uint) (info->write_pos - info->write_buffer))) { +#ifdef THREAD + /* + In case of a shared I/O cache with a writer we do direct write + cache to read cache copy. Do it before the write here so that + the readers can work in parallel with the write. + copy_to_read_buffer() relies on info->pos_in_file. + */ + if (info->share) + copy_to_read_buffer(info, info->write_buffer, length); +#endif + pos_in_file=info->pos_in_file; /* If we have append cache, we always open the file with @@ -1265,16 +1771,10 @@ int end_io_cache(IO_CACHE *info) #ifdef THREAD /* - if IO_CACHE is shared between several threads, only one - thread needs to call end_io_cache() - just as init_io_cache() - should be called only once and then memcopy'ed + Every thread must call remove_io_thread(). The last one destroys + the share elements. */ - if (info->share) - { - pthread_cond_destroy(&info->share->cond); - pthread_mutex_destroy(&info->share->mutex); - info->share=0; - } + DBUG_ASSERT(!info->share || !info->share->total_threads); #endif if ((pre_close=info->pre_close)) diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index f1ea21c2a47..895f03dc714 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -24,6 +24,54 @@ #include <stdarg.h> #include <m_ctype.h> +/* + Copy contents of an IO_CACHE to a file. + + SYNOPSIS + my_b_copy_to_file() + cache IO_CACHE to copy from + file File to copy to + + DESCRIPTION + Copy the contents of the cache to the file. The cache will be + re-inited to a read cache and will read from the beginning of the + cache. + + If a failure to write fully occurs, the cache is only copied + partially. + + TODO + Make this function solid by handling partial reads from the cache + in a correct manner: it should be atomic. + + RETURN VALUE + 0 All OK + 1 An error occured +*/ +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"); + + /* Reinit the cache to read from the beginning of the cache */ + 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) + DBUG_RETURN(1); + bytes_in_cache -= read_bytes; + } + DBUG_RETURN(0); +} + my_off_t my_b_append_tell(IO_CACHE* info) { /* diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c index fe0d0ffa607..4b26085c870 100644 --- a/mysys/my_chsize.c +++ b/mysys/my_chsize.c @@ -86,7 +86,11 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags) Fill space between requested length and true length with 'filler' We should never come here on any modern machine */ - VOID(my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE))); + if (my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE)) + == MY_FILEPOS_ERROR) + { + goto err; + } swap_variables(my_off_t, newlength, oldsize); #endif } diff --git a/mysys/my_lock.c b/mysys/my_lock.c index 919727e03d6..e32807004e8 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -30,7 +30,14 @@ #include <nks/fsio.h> #endif - /* Lock a part of a file */ +/* + Lock a part of a file + + RETURN VALUE + 0 Success + -1 An error has occured and 'my_errno' is set + to indicate the actual error code. +*/ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, myf MyFlags) @@ -94,10 +101,22 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, #elif defined(HAVE_LOCKING) /* Windows */ { - my_bool error; + my_bool error= FALSE; pthread_mutex_lock(&my_file_info[fd].mutex); - if (MyFlags & MY_SEEK_NOT_DONE) - VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))); + if (MyFlags & MY_SEEK_NOT_DONE) + { + if( my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)) + == MY_FILEPOS_ERROR ) + { + /* + If my_seek fails my_errno will already contain an error code; + just unlock and return error code. + */ + DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno)); + pthread_mutex_unlock(&my_file_info[fd].mutex); + DBUG_RETURN(-1); + } + } error= locking(fd,locktype,(ulong) length) && errno != EINVAL; pthread_mutex_unlock(&my_file_info[fd].mutex); if (!error) @@ -135,7 +154,17 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, } #else if (MyFlags & MY_SEEK_NOT_DONE) - VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))); + { + if (my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)) + == MY_FILEPOS_ERROR) + { + /* + If an error has occured in my_seek then we will already + have an error code in my_errno; Just return error code. + */ + DBUG_RETURN(-1); + } + } if (lockf(fd,locktype,length) != -1) DBUG_RETURN(0); #endif /* HAVE_FCNTL */ diff --git a/mysys/my_lread.c b/mysys/my_lread.c deleted file mode 100644 index 601d772b844..00000000000 --- a/mysys/my_lread.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "mysys_priv.h" -#include "mysys_err.h" - - /* Read a chunk of bytes from a file */ - -uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags) - /* File descriptor */ - /* Buffer must be at least count bytes */ - /* Max number of bytes returnd */ - /* Flags on what to do on error */ -{ - uint32 readbytes; - DBUG_ENTER("my_lread"); - DBUG_PRINT("my",("Fd: %d Buffer: %ld Count: %ld MyFlags: %d", - Filedes, Buffer, Count, MyFlags)); - - /* Temp hack to get count to int32 while read wants int */ - if ((readbytes = (uint32) read(Filedes, Buffer, (uint) Count)) != Count) - { - my_errno=errno; - if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) - { - if (readbytes == MY_FILE_ERROR) - my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),errno); - else - if (MyFlags & (MY_NABP | MY_FNABP)) - my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),errno); - } - if (readbytes == MY_FILE_ERROR || MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN((uint32) -1); /* Return med felkod */ - } - if (MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN(0); /* Ok vid l{sning */ - DBUG_RETURN(readbytes); -} /* my_lread */ diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c deleted file mode 100644 index 3b9afdbd71f..00000000000 --- a/mysys/my_lwrite.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "mysys_priv.h" -#include "mysys_err.h" - - /* Write a chunk of bytes to a file */ - -uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags) -{ - uint32 writenbytes; - DBUG_ENTER("my_lwrite"); - DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %ld MyFlags: %d", - Filedes, Buffer, Count, MyFlags)); - - /* Temp hack to get count to int32 while write wants int */ - if ((writenbytes = (uint32) write(Filedes, Buffer, (uint) Count)) != Count) - { - my_errno=errno; - if (writenbytes == (uint32) -1 || MyFlags & (MY_NABP | MY_FNABP)) - { - if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) - { - my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),errno); - } - DBUG_RETURN((uint32) -1); /* Return med felkod */ - } - } - if (MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN(0); /* Ok vid l{sning */ - DBUG_RETURN(writenbytes); -} /* my_lwrite */ diff --git a/mysys/my_pread.c b/mysys/my_pread.c index f14b666060f..bc64cdfe226 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -75,8 +75,12 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d", readbytes,Count,Filedes,my_errno)); #ifdef THREAD - if (readbytes == 0 && errno == EINTR) - continue; /* Interrupted */ + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d", + (int) readbytes)); + continue; /* Interrupted */ + } #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { @@ -171,8 +175,8 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } - if ((writenbytes == 0 && my_errno == EINTR) || - (writenbytes > 0 && (uint) writenbytes != (uint) -1)) + if ((writenbytes > 0 && (uint) writenbytes != (uint) -1) || + my_errno == EINTR) continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) diff --git a/mysys/my_quick.c b/mysys/my_quick.c index 44ed3fc0b2c..ffc8160c371 100644 --- a/mysys/my_quick.c +++ b/mysys/my_quick.c @@ -26,6 +26,14 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags) if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count) { +#ifndef DBUG_OFF + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("error", ("my_quick_read() was interrupted and returned %d" + ". This function does not retry the read!", + (int) readbytes)); + } +#endif my_errno=errno; return readbytes; } @@ -35,8 +43,24 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags) uint my_quick_write(File Filedes,const byte *Buffer,uint Count) { - if ((uint) write(Filedes,Buffer,Count) != Count) +#ifndef DBUG_OFF + uint writtenbytes; +#endif + + if (( +#ifndef DBUG_OFF + writtenbytes = +#endif + (uint) write(Filedes,Buffer,Count)) != Count) { +#ifndef DBUG_OFF + if ((writtenbytes == 0 || (int) writtenbytes == -1) && errno == EINTR) + { + DBUG_PRINT("error", ("my_quick_write() was interrupted and returned %d" + ". This function does not retry the write!", + (int) writtenbytes)); + } +#endif my_errno=errno; return (uint) -1; } diff --git a/mysys/my_read.c b/mysys/my_read.c index 2e23f2175f8..8b88e483fef 100644 --- a/mysys/my_read.c +++ b/mysys/my_read.c @@ -51,10 +51,11 @@ uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags) DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d", readbytes, Count, Filedes, my_errno)); #ifdef THREAD - if ((int) readbytes <= 0 && errno == EINTR) - { - DBUG_PRINT("debug", ("my_read() was interrupted and returned %d", (int) readbytes)); - continue; /* Interrupted */ + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("debug", ("my_read() was interrupted and returned %d", + (int) readbytes)); + continue; /* Interrupted */ } #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) diff --git a/mysys/my_seek.c b/mysys/my_seek.c index e5b1905e551..269d1a65b31 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -16,8 +16,30 @@ #include "mysys_priv.h" - /* Seek to position in file */ - /*ARGSUSED*/ +/* + Seek to a position in a file. + + ARGUMENTS + File fd The file descriptor + my_off_t pos The expected position (absolute or relative) + int whence A direction parameter and one of + {SEEK_SET, SEEK_CUR, SEEK_END} + myf MyFlags Not used. + + DESCRIPTION + The my_seek function is a wrapper around the system call lseek and + repositions the offset of the file descriptor fd to the argument + offset according to the directive whence as follows: + SEEK_SET The offset is set to offset bytes. + SEEK_CUR The offset is set to its current location plus offset bytes + SEEK_END The offset is set to the size of the file plus offset bytes + + RETURN VALUE + my_off_t newpos The new position in the file. + MY_FILEPOS_ERROR An error was encountered while performing + the seek. my_errno is set to indicate the + actual error. +*/ my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags __attribute__((unused))) @@ -29,8 +51,13 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, whence, MyFlags)); DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */ - if (-1 != fd) - newpos=lseek(fd, pos, whence); + /* + Make sure we are using a valid file descriptor! + */ + DBUG_ASSERT(fd != -1); + + newpos= lseek(fd, pos, whence); + if (newpos == (os_off_t) -1) { my_errno=errno; diff --git a/mysys/my_write.c b/mysys/my_write.c index 4e8369480b3..ae8cb4ab02b 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -57,18 +57,24 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } - if (!writenbytes) + + if ((writenbytes == 0 || (int) writenbytes == -1)) { - /* We may come here on an interrupt or if the file quote is exeeded */ if (my_errno == EINTR) - continue; - if (!errors++) /* Retry once */ { - errno=EFBIG; /* Assume this is the error */ - continue; + DBUG_PRINT("debug", ("my_write() was interrupted and returned %d", + (int) writenbytes)); + continue; /* Interrupted */ + } + + if (!writenbytes && !errors++) /* Retry once */ + { + /* We may come here if the file quota is exeeded */ + errno=EFBIG; /* Assume this is the error */ + continue; } } - else if ((uint) writenbytes != (uint) -1) + else continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index dcb41837d96..c55cc32b47d 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -15,8 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* To avoid problems with alarms in debug code, we disable DBUG here */ -#undef DBUG_OFF -#define DBUG_OFF +#define FORCE_DBUG_OFF #include <my_global.h> #if defined(THREAD) && !defined(DONT_USE_THR_ALARM) diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 36cb83ae754..a2c42ee326c 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -72,7 +72,7 @@ multiple read locks. */ #if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG) -#define DBUG_OFF +#define FORCE_DBUG_OFF #endif #include "mysys_priv.h" |