diff options
Diffstat (limited to 'mysys')
57 files changed, 1643 insertions, 764 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 917421aa07a..eb7f75ed6a8 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -33,13 +33,15 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c my_basename.c my_write.c ptr_cmp.c queues.c stacktrace.c string.c thr_alarm.c thr_lock.c thr_mutex.c - thr_rwlock.c tree.c typelib.c base64.c my_memmem.c my_getpagesize.c + thr_rwlock.c thr_timer.c + tree.c typelib.c base64.c my_memmem.c + my_getpagesize.c lf_alloc-pin.c lf_dynarray.c lf_hash.c safemalloc.c my_new.cc my_atomic.c my_getncpus.c my_safehash.c my_chmod.c my_rnd.c my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c my_rdtsc.c my_context.c psi_noop.c - file_logger.c) + file_logger.c my_dlerror.c) IF (WIN32) SET (MYSYS_SOURCES ${MYSYS_SOURCES} my_winthread.c my_wincond.c my_winerr.c my_winfile.c my_windac.c my_conio.c) @@ -68,8 +70,8 @@ IF(HAVE_MLOCK) ENDIF() ADD_CONVENIENCE_LIBRARY(mysys ${MYSYS_SOURCES}) -TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY} - ${LIBNSL} ${LIBM} ${LIBRT} ${LIBSOCKET} ${LIBEXECINFO} ${LIBDL}) +TARGET_LINK_LIBRARIES(mysys dbug strings mysys_ssl ${ZLIB_LIBRARY} + ${LIBNSL} ${LIBM} ${LIBRT} ${LIBDL} ${LIBSOCKET} ${LIBEXECINFO}) DTRACE_INSTRUMENT(mysys) IF(HAVE_BFD_H) @@ -89,6 +91,10 @@ ADD_EXECUTABLE(thr_lock thr_lock.c) TARGET_LINK_LIBRARIES(thr_lock mysys) SET_TARGET_PROPERTIES(thr_lock PROPERTIES COMPILE_FLAGS "-DMAIN") +ADD_EXECUTABLE(thr_timer thr_timer.c) +TARGET_LINK_LIBRARIES(thr_timer mysys) +SET_TARGET_PROPERTIES(thr_timer PROPERTIES COMPILE_FLAGS "-DMAIN") + IF(MSVC) INSTALL_DEBUG_TARGET(mysys DESTINATION ${INSTALL_LIBDIR}/debug) ENDIF() diff --git a/mysys/array.c b/mysys/array.c index a8c5d181638..5548ca1b694 100644 --- a/mysys/array.c +++ b/mysys/array.c @@ -35,7 +35,6 @@ init_alloc eilements. Array is usable even if space allocation failed, hence, the function never returns TRUE. - Static buffers must begin immediately after the array structure. RETURN VALUE FALSE Ok @@ -57,8 +56,12 @@ my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size, array->alloc_increment=alloc_increment; array->size_of_element=element_size; array->malloc_flags= my_flags; + DBUG_ASSERT((my_flags & MY_INIT_BUFFER_USED) == 0); if ((array->buffer= init_buffer)) + { + array->malloc_flags|= MY_INIT_BUFFER_USED; DBUG_RETURN(FALSE); + } /* Since the dynamic array is usable even if allocation fails here malloc should not throw an error @@ -87,7 +90,7 @@ my_bool insert_dynamic(DYNAMIC_ARRAY *array, const void * element) { void *buffer; if (array->elements == array->max_element) - { /* Call only when nessesary */ + { /* Call only when necessary */ if (!(buffer=alloc_dynamic(array))) return TRUE; } @@ -124,10 +127,10 @@ void *alloc_dynamic(DYNAMIC_ARRAY *array) if (array->elements == array->max_element) { char *new_ptr; - if (array->buffer == (uchar *)(array + 1)) + if (array->malloc_flags & MY_INIT_BUFFER_USED) { /* - In this senerio, the buffer is statically preallocated, + In this scenario, the buffer is statically preallocated, so we have to create an all-new malloc since we overflowed */ if (!(new_ptr= (char *) my_malloc((array->max_element+ @@ -137,6 +140,7 @@ void *alloc_dynamic(DYNAMIC_ARRAY *array) DBUG_RETURN(0); memcpy(new_ptr, array->buffer, array->elements * array->size_of_element); + array->malloc_flags&= ~MY_INIT_BUFFER_USED; } else if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+ @@ -231,7 +235,7 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements) uchar *new_ptr; size= (max_elements + array->alloc_increment)/array->alloc_increment; size*= array->alloc_increment; - if (array->buffer == (uchar *)(array + 1)) + if (array->malloc_flags & MY_INIT_BUFFER_USED) { /* In this senerio, the buffer is statically preallocated, @@ -243,7 +247,8 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements) DBUG_RETURN(0); memcpy(new_ptr, array->buffer, array->elements * array->size_of_element); - } + array->malloc_flags&= ~MY_INIT_BUFFER_USED; + } else if (!(new_ptr= (uchar*) my_realloc(array->buffer,size* array->size_of_element, MYF(MY_WME | MY_ALLOW_ZERO_PTR | @@ -293,15 +298,11 @@ void delete_dynamic(DYNAMIC_ARRAY *array) /* Just mark as empty if we are using a static buffer */ - if (array->buffer == (uchar *)(array + 1)) - array->elements= 0; - else - if (array->buffer) - { + if (!(array->malloc_flags & MY_INIT_BUFFER_USED) && array->buffer) my_free(array->buffer); - array->buffer=0; - array->elements=array->max_element=0; - } + + array->buffer= 0; + array->elements= array->max_element= 0; } /* @@ -350,24 +351,25 @@ void delete_dynamic_with_callback(DYNAMIC_ARRAY *array, FREE_FUNC f) { void freeze_size(DYNAMIC_ARRAY *array) { - uint elements=MY_MAX(array->elements,1); + uint elements; /* Do nothing if we are using a static buffer */ - if (array->buffer == (uchar *)(array + 1)) + if (array->malloc_flags & MY_INIT_BUFFER_USED) return; - if (array->buffer && array->max_element != elements) + elements= MY_MAX(array->elements, 1); + if (array->buffer && array->max_element > elements) { array->buffer=(uchar*) my_realloc(array->buffer, - elements*array->size_of_element, + elements*array->size_of_element, MYF(MY_WME | array->malloc_flags)); - array->max_element=elements; + array->max_element= elements; } } - +#ifdef NOT_USED /* Get the index of a dynamic element @@ -391,3 +393,4 @@ int get_index_dynamic(DYNAMIC_ARRAY *array, void* element) return ret; } +#endif diff --git a/mysys/base64.c b/mysys/base64.c index 265b2f22aad..04411418857 100644 --- a/mysys/base64.c +++ b/mysys/base64.c @@ -17,7 +17,6 @@ #include <my_global.h> #include <m_string.h> /* strchr() */ #include <m_ctype.h> /* my_isspace() */ -#include <base64.h> #ifndef MAIN diff --git a/mysys/charset-def.c b/mysys/charset-def.c index af1e9bae2ac..defb5c0062d 100644 --- a/mysys/charset-def.c +++ b/mysys/charset-def.c @@ -49,6 +49,7 @@ extern struct charset_info_st my_charset_ucs2_unicode_520_ci; extern struct charset_info_st my_charset_ucs2_vietnamese_ci; extern struct charset_info_st my_charset_ucs2_croatian_uca_ci; extern struct charset_info_st my_charset_ucs2_myanmar_uca_ci; +extern struct charset_info_st my_charset_ucs2_thai_520_w2; #endif @@ -78,6 +79,7 @@ extern struct charset_info_st my_charset_utf32_unicode_520_ci; extern struct charset_info_st my_charset_utf32_vietnamese_ci; extern struct charset_info_st my_charset_utf32_croatian_uca_ci; extern struct charset_info_st my_charset_utf32_myanmar_uca_ci; +extern struct charset_info_st my_charset_utf32_thai_520_w2; #endif /* HAVE_CHARSET_utf32 */ @@ -107,6 +109,7 @@ extern struct charset_info_st my_charset_utf16_unicode_520_ci; extern struct charset_info_st my_charset_utf16_vietnamese_ci; extern struct charset_info_st my_charset_utf16_croatian_uca_ci; extern struct charset_info_st my_charset_utf16_myanmar_uca_ci; +extern struct charset_info_st my_charset_utf16_thai_520_w2; #endif /* HAVE_CHARSET_utf16 */ @@ -136,6 +139,7 @@ extern struct charset_info_st my_charset_utf8_unicode_520_ci; extern struct charset_info_st my_charset_utf8_vietnamese_ci; extern struct charset_info_st my_charset_utf8_croatian_uca_ci; extern struct charset_info_st my_charset_utf8_myanmar_uca_ci; +extern struct charset_info_st my_charset_utf8_thai_520_w2; #ifdef HAVE_UTF8_GENERAL_CS extern struct charset_info_st my_charset_utf8_general_cs; #endif @@ -167,6 +171,7 @@ extern struct charset_info_st my_charset_utf8mb4_unicode_520_ci; extern struct charset_info_st my_charset_utf8mb4_vietnamese_ci; extern struct charset_info_st my_charset_utf8mb4_croatian_uca_ci; extern struct charset_info_st my_charset_utf8mb4_myanmar_uca_ci; +extern struct charset_info_st my_charset_utf8mb4_thai_520_w2; #endif /* HAVE_CHARSET_utf8mb4 */ #endif /* HAVE_UCA_COLLATIONS */ @@ -261,6 +266,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_ucs2_vietnamese_ci); add_compiled_collation(&my_charset_ucs2_croatian_uca_ci); add_compiled_collation(&my_charset_ucs2_myanmar_uca_ci); + add_compiled_collation(&my_charset_ucs2_thai_520_w2); #endif #endif @@ -303,6 +309,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8_vietnamese_ci); add_compiled_collation(&my_charset_utf8_croatian_uca_ci); add_compiled_collation(&my_charset_utf8_myanmar_uca_ci); + add_compiled_collation(&my_charset_utf8_thai_520_w2); #endif #endif /* HAVE_CHARSET_utf8 */ @@ -337,6 +344,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf8mb4_vietnamese_ci); add_compiled_collation(&my_charset_utf8mb4_croatian_uca_ci); add_compiled_collation(&my_charset_utf8mb4_myanmar_uca_ci); + add_compiled_collation(&my_charset_utf8mb4_thai_520_w2); #endif /* HAVE_UCA_COLLATIONS */ #endif /* HAVE_CHARSET_utf8mb4 */ @@ -373,6 +381,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf16_vietnamese_ci); add_compiled_collation(&my_charset_utf16_croatian_uca_ci); add_compiled_collation(&my_charset_utf16_myanmar_uca_ci); + add_compiled_collation(&my_charset_utf16_thai_520_w2); #endif /* HAVE_UCA_COLLATIONS */ #endif /* HAVE_CHARSET_utf16 */ @@ -407,6 +416,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused))) add_compiled_collation(&my_charset_utf32_vietnamese_ci); add_compiled_collation(&my_charset_utf32_croatian_uca_ci); add_compiled_collation(&my_charset_utf32_myanmar_uca_ci); + add_compiled_collation(&my_charset_utf32_thai_520_w2); #endif /* HAVE_UCA_COLLATIONS */ #endif /* HAVE_CHARSET_utf32 */ diff --git a/mysys/checksum.c b/mysys/checksum.c index 7bc52c6a178..a948785d935 100644 --- a/mysys/checksum.c +++ b/mysys/checksum.c @@ -18,8 +18,6 @@ #include <my_sys.h> #include <zlib.h> -ulong my_crc_dbug_check= ~0; /* Cannot happen */ - /* Calculate a long checksum for a memoryblock. @@ -34,7 +32,5 @@ ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length) { crc= (ha_checksum) crc32((uint)crc, pos, (uint) length); DBUG_PRINT("info", ("crc: %lu", (ulong) crc)); - if ((ulong)crc == my_crc_dbug_check) - my_debug_put_break_here(); return crc; } diff --git a/mysys/file_logger.c b/mysys/file_logger.c index b94cb705d3f..078286cd7d0 100644 --- a/mysys/file_logger.c +++ b/mysys/file_logger.c @@ -11,7 +11,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #ifndef FLOGGER_SKIP_INCLUDES diff --git a/mysys/hash.c b/mysys/hash.c index c2f3555396e..3c17dcb991c 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -61,7 +61,7 @@ my_hash_value_type my_hash_sort(CHARSET_INFO *cs, const uchar *key, @param[in,out] hash The hash that is initialized @param[in[ growth_size size incrememnt for the underlying dynarray - @param[in] charset The charater set information + @param[in] charset The character set information @param[in] size The hash size @param[in] key_offest The key offset for the hash @param[in] key_length The length of the key used in @@ -94,10 +94,9 @@ my_hash_init2(HASH *hash, uint growth_size, CHARSET_INFO *charset, hash->free=free_element; hash->flags=flags; hash->charset=charset; - res= my_init_dynamic_array2(&hash->array, - sizeof(HASH_LINK), NULL, size, growth_size, - MYF((flags & HASH_THREAD_SPECIFIC ? - MY_THREAD_SPECIFIC : 0))); + res= init_dynamic_array2(&hash->array, sizeof(HASH_LINK), NULL, size, + growth_size, MYF((flags & HASH_THREAD_SPECIFIC ? + MY_THREAD_SPECIFIC : 0))); DBUG_RETURN(res); } @@ -619,7 +618,7 @@ exit: /** Update keys when record has changed. - This is much more efficent than using a delete & insert. + This is much more efficient than using a delete & insert. */ my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key, diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index a60a2ae657c..b9260b115bd 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -111,7 +111,7 @@ #define LF_PINBOX_MAX_PINS 65536 -static void _lf_pinbox_real_free(LF_PINS *pins); +static void lf_pinbox_real_free(LF_PINS *pins); /* Initialize a pinbox. Normally called from lf_alloc_init. @@ -139,7 +139,7 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox) Get pins from a pinbox. Usually called via lf_alloc_get_pins() or lf_hash_get_pins(). - SYNOPSYS + SYNOPSIS pinbox - DESCRIPTION @@ -150,7 +150,7 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox) It is assumed that pins belong to a thread and are not transferable between threads. */ -LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox) +LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox) { struct st_my_thread_var *var; uint32 pins, next, top_ver; @@ -177,12 +177,12 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox) note that the first allocated element has index 1 (pins==1). index 0 is reserved to mean "NULL pointer" */ - el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins); + el= (LF_PINS *)lf_dynarray_lvalue(&pinbox->pinarray, pins); if (unlikely(!el)) return 0; break; } - el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins); + el= (LF_PINS *)lf_dynarray_value(&pinbox->pinarray, pins); next= el->link; } while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver, (int32*) &top_ver, @@ -212,7 +212,7 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox) empty the purgatory (XXX deadlock warning below!), push LF_PINS structure to a stack */ -void _lf_pinbox_put_pins(LF_PINS *pins) +void lf_pinbox_put_pins(LF_PINS *pins) { LF_PINBOX *pinbox= pins->pinbox; uint32 top_ver, nr; @@ -229,19 +229,15 @@ void _lf_pinbox_put_pins(LF_PINS *pins) /* XXX this will deadlock if other threads will wait for - the caller to do something after _lf_pinbox_put_pins(), + the caller to do something after lf_pinbox_put_pins(), and they would have pinned addresses that the caller wants to free. Thus: only free pins when all work is done and nobody can wait for you!!! */ while (pins->purgatory_count) { - _lf_pinbox_real_free(pins); + lf_pinbox_real_free(pins); if (pins->purgatory_count) - { - my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock); pthread_yield(); - my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock); - } } top_ver= pinbox->pinstack_top_ver; do @@ -271,14 +267,14 @@ static int ptr_cmp(void **a, void **b) Free an object allocated via pinbox allocator DESCRIPTION - add an object to purgatory. if necessary, call _lf_pinbox_real_free() + add an object to purgatory. if necessary, calllf_pinbox_real_free() to actually free something. */ -void _lf_pinbox_free(LF_PINS *pins, void *addr) +void lf_pinbox_free(LF_PINS *pins, void *addr) { add_to_purgatory(pins, addr); if (pins->purgatory_count % LF_PURGATORY_SIZE == 0) - _lf_pinbox_real_free(pins); + lf_pinbox_real_free(pins); } struct st_harvester { @@ -287,7 +283,7 @@ struct st_harvester { }; /* - callback for _lf_dynarray_iterate: + callback forlf_dynarray_iterate: scan all pins of all threads and accumulate all pins */ static int harvest_pins(LF_PINS *el, struct st_harvester *hv) @@ -314,7 +310,7 @@ static int harvest_pins(LF_PINS *el, struct st_harvester *hv) } /* - callback for _lf_dynarray_iterate: + callback forlf_dynarray_iterate: scan all pins of all threads and see if addr is present there */ static int match_pins(LF_PINS *el, void *addr) @@ -334,7 +330,7 @@ static int match_pins(LF_PINS *el, void *addr) /* Scan the purgatory and free everything that can be freed */ -static void _lf_pinbox_real_free(LF_PINS *pins) +static void lf_pinbox_real_free(LF_PINS *pins) { int npins; void *list; @@ -357,7 +353,7 @@ static void _lf_pinbox_real_free(LF_PINS *pins) hv.granary= addr; hv.npins= npins; /* scan the dynarray and accumulate all pinned addresses */ - _lf_dynarray_iterate(&pinbox->pinarray, + lf_dynarray_iterate(&pinbox->pinarray, (lf_dynarray_func)harvest_pins, &hv); npins= hv.granary-addr; @@ -392,7 +388,7 @@ static void _lf_pinbox_real_free(LF_PINS *pins) } else /* no alloca - no cookie. linear search here */ { - if (_lf_dynarray_iterate(&pinbox->pinarray, + if (lf_dynarray_iterate(&pinbox->pinarray, (lf_dynarray_func)match_pins, cur)) goto found; } @@ -414,7 +410,7 @@ found: /* lock-free memory allocator for fixed-size objects */ /* - callback for _lf_pinbox_real_free to free a list of unpinned objects - + callback forlf_pinbox_real_free to free a list of unpinned objects - add it back to the allocator stack DESCRIPTION @@ -441,7 +437,7 @@ static void alloc_free(uchar *first, /* initialize lock-free allocator - SYNOPSYS + SYNOPSIS allocator - size a size of an object to allocate free_ptr_offset an offset inside the object to a sizeof(void *) @@ -496,7 +492,7 @@ void lf_alloc_destroy(LF_ALLOCATOR *allocator) Pop an unused object from the stack or malloc it is the stack is empty. pin[0] is used, it's removed on return. */ -void *_lf_alloc_new(LF_PINS *pins) +void *lf_alloc_new(LF_PINS *pins) { LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg); uchar *node; @@ -505,7 +501,7 @@ void *_lf_alloc_new(LF_PINS *pins) do { node= allocator->top; - _lf_pin(pins, 0, node); + lf_pin(pins, 0, node); } while (node != allocator->top && LF_BACKOFF); if (!node) { @@ -522,7 +518,7 @@ void *_lf_alloc_new(LF_PINS *pins) (void *)&node, anext_node(node))) break; } - _lf_unpin(pins, 0); + lf_unpin(pins, 0); return node; } diff --git a/mysys/lf_dynarray.c b/mysys/lf_dynarray.c index 16a77c0fa1a..bb6cbcefc49 100644 --- a/mysys/lf_dynarray.c +++ b/mysys/lf_dynarray.c @@ -44,7 +44,6 @@ void lf_dynarray_init(LF_DYNARRAY *array, uint element_size) { bzero(array, sizeof(*array)); array->size_of_element= element_size; - my_atomic_rwlock_init(&array->lock); } static void recursive_free(void **alloc, int level) @@ -68,7 +67,6 @@ void lf_dynarray_destroy(LF_DYNARRAY *array) int i; for (i= 0; i < LF_DYNARRAY_LEVELS; i++) recursive_free(array->level[i], i); - my_atomic_rwlock_destroy(&array->lock); } static const ulong dynarray_idxes_in_prev_levels[LF_DYNARRAY_LEVELS]= @@ -95,7 +93,7 @@ static const ulong dynarray_idxes_in_prev_level[LF_DYNARRAY_LEVELS]= Returns a valid lvalue pointer to the element number 'idx'. Allocates memory if necessary. */ -void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx) +void *lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx) { void * ptr, * volatile * ptr_ptr= 0; int i; @@ -148,7 +146,7 @@ void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx) Returns a pointer to the element number 'idx' or NULL if an element does not exists */ -void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx) +void *lf_dynarray_value(LF_DYNARRAY *array, uint idx) { void * ptr, * volatile * ptr_ptr= 0; int i; @@ -189,14 +187,14 @@ static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level, DESCRIPTION lf_dynarray consists of a set of arrays, LF_DYNARRAY_LEVEL_LENGTH elements - each. _lf_dynarray_iterate() calls user-supplied function on every array + each. lf_dynarray_iterate() calls user-supplied function on every array from the set. It is the fastest way to scan the array, faster than - for (i=0; i < N; i++) { func(_lf_dynarray_value(dynarray, i)); } + for (i=0; i < N; i++) { func(lf_dynarray_value(dynarray, i)); } NOTE if func() returns non-zero, the scan is aborted */ -int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg) +int lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg) { int i, res; for (i= 0; i < LF_DYNARRAY_LEVELS; i++) diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c index 7edf5e3a03d..7354b1699b1 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -25,12 +25,13 @@ #include <my_global.h> #include <m_string.h> #include <my_sys.h> +#include <mysys_err.h> #include <my_bit.h> #include <lf.h> /* An element of the list */ typedef struct { - intptr volatile link; /* a pointer to the next element in a listand a flag */ + intptr volatile link; /* a pointer to the next element in a list and a flag */ uint32 hashnr; /* reversed hash number, for sorting */ const uchar *key; size_t keylen; @@ -58,63 +59,84 @@ typedef struct { #define PTR(V) (LF_SLIST *)((V) & (~(intptr)1)) #define DELETED(V) ((V) & 1) -/* - DESCRIPTION +/** walk the list, searching for an element or invoking a callback + Search for hashnr/key/keylen in the list starting from 'head' and position the cursor. The list is ORDER BY hashnr, key - RETURN - 0 - not found - 1 - found + @param head start walking the list from this node + @param cs charset for comparing keys, NULL if callback is used + @param hashnr hash number to search for + @param key key to search for OR data for the callback + @param keylen length of the key to compare, 0 if callback is used + @param cursor for returning the found element + @param pins see lf_alloc-pin.c + @param callback callback action, invoked for every element - NOTE + @note cursor is positioned in either case pins[0..2] are used, they are NOT removed on return + callback might see some elements twice (because of retries) + + @return + if find: 0 - not found + 1 - found + if callback: + 0 - ok + 1 - error (callbck returned 1) */ static int l_find(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, - const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins) + const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins, + my_hash_walk_action callback) { uint32 cur_hashnr; const uchar *cur_key; uint cur_keylen; intptr link; + DBUG_ASSERT(!cs || !callback); /* should not be set both */ + DBUG_ASSERT(!keylen || !callback); /* should not be set both */ + retry: cursor->prev= (intptr *)head; do { /* PTR() isn't necessary below, head is a dummy node */ cursor->curr= (LF_SLIST *)(*cursor->prev); - _lf_pin(pins, 1, cursor->curr); + lf_pin(pins, 1, cursor->curr); } while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF); + for (;;) { if (unlikely(!cursor->curr)) return 0; /* end of the list */ + + cur_hashnr= cursor->curr->hashnr; + cur_keylen= cursor->curr->keylen; + cur_key= cursor->curr->key; + do { - /* QQ: XXX or goto retry ? */ link= cursor->curr->link; cursor->next= PTR(link); - _lf_pin(pins, 0, cursor->next); + lf_pin(pins, 0, cursor->next); } while (link != cursor->curr->link && LF_BACKOFF); - cur_hashnr= cursor->curr->hashnr; - cur_key= cursor->curr->key; - cur_keylen= cursor->curr->keylen; - if (*cursor->prev != (intptr)cursor->curr) - { - (void)LF_BACKOFF; - goto retry; - } + if (!DELETED(link)) { - if (cur_hashnr >= hashnr) + if (unlikely(callback)) + { + if (cur_hashnr & 1 && callback(cursor->curr + 1, (void*)key)) + return 1; + } + else if (cur_hashnr >= hashnr) { int r= 1; if (cur_hashnr > hashnr || - (r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key, - keylen)) >= 0) + (r= my_strnncoll(cs, cur_key, cur_keylen, key, keylen)) >= 0) return !r; } cursor->prev= &(cursor->curr->link); - _lf_pin(pins, 2, cursor->curr); + if (!(cur_hashnr & 1)) /* dummy node */ + head= (LF_SLIST **)cursor->prev; + lf_pin(pins, 2, cursor->curr); } else { @@ -123,16 +145,13 @@ retry: and remove this deleted node */ if (my_atomic_casptr((void **) cursor->prev, - (void **)(char*) &cursor->curr, cursor->next)) - _lf_alloc_free(pins, cursor->curr); + (void **) &cursor->curr, cursor->next) && LF_BACKOFF) + lf_alloc_free(pins, cursor->curr); else - { - (void)LF_BACKOFF; goto retry; - } } cursor->curr= cursor->next; - _lf_pin(pins, 1, cursor->curr); + lf_pin(pins, 1, cursor->curr); } } @@ -158,7 +177,7 @@ static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs, for (;;) { if (l_find(head, cs, node->hashnr, node->key, node->keylen, - &cursor, pins) && + &cursor, pins, 0) && (flags & LF_HASH_UNIQUE)) { res= 0; /* duplicate found */ @@ -177,12 +196,12 @@ static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs, } } } - _lf_unpin(pins, 0); - _lf_unpin(pins, 1); - _lf_unpin(pins, 2); + lf_unpin(pins, 0); + lf_unpin(pins, 1); + lf_unpin(pins, 2); /* Note that cursor.curr is not pinned here and the pointer is unreliable, - the object may dissapear anytime. But if it points to a dummy node, the + the object may disappear anytime. But if it points to a dummy node, the pointer is safe, because dummy nodes are never freed - initialize_bucket() uses this fact. */ @@ -209,7 +228,7 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, for (;;) { - if (!l_find(head, cs, hashnr, key, keylen, &cursor, pins)) + if (!l_find(head, cs, hashnr, key, keylen, &cursor, pins, 0)) { res= 1; /* not found */ break; @@ -224,7 +243,7 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, /* and remove it from the list */ if (my_atomic_casptr((void **)cursor.prev, (void **)(char*)&cursor.curr, cursor.next)) - _lf_alloc_free(pins, cursor.curr); + lf_alloc_free(pins, cursor.curr); else { /* @@ -233,16 +252,16 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, (to ensure the number of "set DELETED flag" actions is equal to the number of "remove from the list" actions) */ - l_find(head, cs, hashnr, key, keylen, &cursor, pins); + l_find(head, cs, hashnr, key, keylen, &cursor, pins, 0); } res= 0; break; } } } - _lf_unpin(pins, 0); - _lf_unpin(pins, 1); - _lf_unpin(pins, 2); + lf_unpin(pins, 0); + lf_unpin(pins, 1); + lf_unpin(pins, 2); return res; } @@ -264,13 +283,13 @@ static LF_SLIST *l_search(LF_SLIST * volatile *head, CHARSET_INFO *cs, LF_PINS *pins) { CURSOR cursor; - int res= l_find(head, cs, hashnr, key, keylen, &cursor, pins); + int res= l_find(head, cs, hashnr, key, keylen, &cursor, pins, 0); if (res) - _lf_pin(pins, 2, cursor.curr); + lf_pin(pins, 2, cursor.curr); else - _lf_unpin(pins, 2); - _lf_unpin(pins, 1); - _lf_unpin(pins, 0); + lf_unpin(pins, 2); + lf_unpin(pins, 1); + lf_unpin(pins, 0); return res ? cursor.curr : 0; } @@ -289,18 +308,24 @@ static inline const uchar* hash_key(const LF_HASH *hash, @note, that the hash value is limited to 2^31, because we need one bit to distinguish between normal and dummy nodes. */ -static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen) +static inline my_hash_value_type calc_hash(const CHARSET_INFO *cs, + const uchar *key, + size_t keylen) { ulong nr1= 1, nr2= 4; - hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen, - &nr1, &nr2); - return nr1 & INT_MAX32; + cs->coll->hash_sort(cs, (uchar*) key, keylen, &nr1, &nr2); + return nr1; } #define MAX_LOAD 1.0 /* average number of elements in a bucket */ static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *); +static void default_initializer(LF_HASH *hash, void *dst, const void *src) +{ + memcpy(dst, src, hash->element_size); +} + /* Initializes lf_hash, the arguments are compatible with hash_init @@ -308,11 +333,13 @@ static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *); lf_alloc and a size of memcpy'ed block size in lf_hash_insert. Typically they are the same, indeed. But LF_HASH::element_size can be decreased after lf_hash_init, and then lf_alloc will allocate larger block that - lf_hash_insert will copy over. It is desireable if part of the element + lf_hash_insert will copy over. It is desirable if part of the element is expensive to initialize - for example if there is a mutex or DYNAMIC_ARRAY. In this case they should be initialize in the LF_ALLOCATOR::constructor, and lf_hash_insert should not overwrite them. - See wt_init() for example. + + The above works well with PODS. For more complex cases (e.g. C++ classes + with private members) use initializer function. */ void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, uint key_offset, uint key_length, my_hash_get_key get_key, @@ -329,12 +356,14 @@ void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, hash->key_offset= key_offset; hash->key_length= key_length; hash->get_key= get_key; + hash->initializer= default_initializer; + hash->hash_function= calc_hash; DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length); } void lf_hash_destroy(LF_HASH *hash) { - LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0); + LF_SLIST *el, **head= (LF_SLIST **)lf_dynarray_value(&hash->array, 0); if (head) { @@ -371,15 +400,14 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) int csize, bucket, hashnr; LF_SLIST *node, * volatile *el; - lf_rwlock_by_pins(pins); - node= (LF_SLIST *)_lf_alloc_new(pins); + node= (LF_SLIST *)lf_alloc_new(pins); if (unlikely(!node)) return -1; - memcpy(node+1, data, hash->element_size); + hash->initializer(hash, node + 1, data); node->key= hash_key(hash, (uchar *)(node+1), &node->keylen); - hashnr= calc_hash(hash, node->key, node->keylen); + hashnr= hash->hash_function(hash->charset, node->key, node->keylen) & INT_MAX32; bucket= hashnr % hash->size; - el= _lf_dynarray_lvalue(&hash->array, bucket); + el= lf_dynarray_lvalue(&hash->array, bucket); if (unlikely(!el)) return -1; if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) @@ -387,14 +415,12 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */ if (l_insert(el, hash->charset, node, pins, hash->flags)) { - _lf_alloc_free(pins, node); - lf_rwunlock_by_pins(pins); + lf_alloc_free(pins, node); return 1; } csize= hash->size; if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD) my_atomic_cas32(&hash->size, &csize, csize*2); - lf_rwunlock_by_pins(pins); return 0; } @@ -406,36 +432,31 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) RETURN 0 - deleted 1 - didn't (not found) - -1 - out of memory NOTE see l_delete() for pin usage notes */ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) { LF_SLIST * volatile *el; - uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen); + uint bucket, hashnr; - bucket= hashnr % hash->size; - lf_rwlock_by_pins(pins); - el= _lf_dynarray_lvalue(&hash->array, bucket); - if (unlikely(!el)) - return -1; - /* - note that we still need to initialize_bucket here, - we cannot return "node not found", because an old bucket of that - node may've been split and the node was assigned to a new bucket - that was never accessed before and thus is not initialized. - */ - if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) - return -1; + hashnr= hash->hash_function(hash->charset, (uchar *)key, keylen) & INT_MAX32; + + /* hide OOM errors - if we cannot initialize a bucket, try the previous one */ + for (bucket= hashnr % hash->size; ;bucket= my_clear_highest_bit(bucket)) + { + el= lf_dynarray_lvalue(&hash->array, bucket); + if (el && (*el || initialize_bucket(hash, el, bucket, pins) == 0)) + break; + if (unlikely(bucket == 0)) + return 1; /* if there's no bucket==0, the hash is empty */ + } if (l_delete(el, hash->charset, my_reverse_bits(hashnr) | 1, (uchar *)key, keylen, pins)) { - lf_rwunlock_by_pins(pins); return 1; } my_atomic_add32(&hash->count, -1); - lf_rwunlock_by_pins(pins); return 0; } @@ -444,29 +465,73 @@ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) a pointer to an element with the given key (if a hash is not unique and there're many elements with this key - the "first" matching element) NULL if nothing is found - MY_ERRPTR if OOM NOTE see l_search() for pin usage notes */ -void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) +void *lf_hash_search_using_hash_value(LF_HASH *hash, LF_PINS *pins, + my_hash_value_type hashnr, + const void *key, uint keylen) { LF_SLIST * volatile *el, *found; - uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen); + uint bucket; - bucket= hashnr % hash->size; - lf_rwlock_by_pins(pins); - el= _lf_dynarray_lvalue(&hash->array, bucket); - if (unlikely(!el)) - return MY_ERRPTR; - if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) - return MY_ERRPTR; + /* hide OOM errors - if we cannot initialize a bucket, try the previous one */ + for (bucket= hashnr % hash->size; ;bucket= my_clear_highest_bit(bucket)) + { + el= lf_dynarray_lvalue(&hash->array, bucket); + if (el && (*el || initialize_bucket(hash, el, bucket, pins) == 0)) + break; + if (unlikely(bucket == 0)) + return 0; /* if there's no bucket==0, the hash is empty */ + } found= l_search(el, hash->charset, my_reverse_bits(hashnr) | 1, (uchar *)key, keylen, pins); - lf_rwunlock_by_pins(pins); return found ? found+1 : 0; } + +/** + Iterate over all elements in hash and call function with the element + + @note + If one of 'action' invocations returns 1 the iteration aborts. + 'action' might see some elements twice! + + @retval 0 ok + @retval 1 error (action returned 1) +*/ +int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins, + my_hash_walk_action action, void *argument) +{ + CURSOR cursor; + uint bucket= 0; + int res; + LF_SLIST * volatile *el; + + el= lf_dynarray_lvalue(&hash->array, bucket); + if (unlikely(!el)) + return 0; /* if there's no bucket==0, the hash is empty */ + if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins))) + return 0; /* if there's no bucket==0, the hash is empty */ + + res= l_find(el, 0, 0, (uchar*)argument, 0, &cursor, pins, action); + + lf_unpin(pins, 2); + lf_unpin(pins, 1); + lf_unpin(pins, 0); + return res; +} + +void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen) +{ + return lf_hash_search_using_hash_value(hash, pins, + hash->hash_function(hash->charset, + (uchar*) key, + keylen) & INT_MAX32, + key, keylen); +} + static const uchar *dummy_key= (uchar*)""; /* @@ -480,7 +545,7 @@ static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node, uint parent= my_clear_highest_bit(bucket); LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME)); LF_SLIST **tmp= 0, *cur; - LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent); + LF_SLIST * volatile *el= lf_dynarray_lvalue(&hash->array, parent); if (unlikely(!el || !dummy)) return -1; if (*el == NULL && bucket && diff --git a/mysys/ma_dyncol.c b/mysys/ma_dyncol.c index 909f9dcac41..53edfc5d87b 100644 --- a/mysys/ma_dyncol.c +++ b/mysys/ma_dyncol.c @@ -2066,7 +2066,7 @@ static uchar *find_entry_named(DYN_HEADER *hdr, LEX_STRING *key) /** Write number in the buffer (backward direction - starts from the buffer end) - @return pointer on the number begining + @return pointer on the number beginning */ static char *backwritenum(char *chr, uint numkey) @@ -2136,7 +2136,7 @@ find_column(DYN_HEADER *hdr, uint numkey, LEX_STRING *strkey) hdr->length= hdr_interval_length(hdr, hdr->entry + hdr->entry_size); hdr->data= hdr->dtpool + hdr->offset; /* - Check that the found data is withing the ranges. This can happen if + Check that the found data is within the ranges. This can happen if we get data with wrong offsets. */ if (hdr->length == DYNCOL_OFFSET_ERROR || @@ -2578,7 +2578,6 @@ find_place(DYN_HEADER *hdr, void *key, my_bool string_keys) mid= 1; while (start != end) { - uint val; mid= (start + end) / 2; hdr->entry= hdr->header + mid * hdr->entry_size; if (!string_keys) @@ -3481,7 +3480,7 @@ dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str, if (plan[i].val->type == DYN_COL_NULL) { - plan[i].act= PLAN_NOP; /* Mark entry to be skiped */ + plan[i].act= PLAN_NOP; /* Mark entry to be skipped */ } else { @@ -3950,11 +3949,11 @@ mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val, } case DYN_COL_DECIMAL: { - int len= sizeof(buff); - decimal2string(&val->x.decimal.value, buff, &len, + int tmp_len= sizeof(buff); + decimal2string(&val->x.decimal.value, buff, &tmp_len, 0, val->x.decimal.value.frac, '0'); - if (dynstr_append_mem(str, buff, len)) + if (dynstr_append_mem(str, buff, tmp_len)) return ER_DYNCOL_RESOURCE; break; } @@ -4187,7 +4186,7 @@ mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json, hdr_interval_length(&header, header.entry + header.entry_size); header.data= header.dtpool + header.offset; /* - Check that the found data is withing the ranges. This can happen if + Check that the found data is within the ranges. This can happen if we get data with wrong offsets. */ if (header.length == DYNCOL_OFFSET_ERROR || @@ -4327,7 +4326,7 @@ mariadb_dyncol_unpack(DYNAMIC_COLUMN *str, hdr_interval_length(&header, header.entry + header.entry_size); header.data= header.dtpool + header.offset; /* - Check that the found data is withing the ranges. This can happen if + Check that the found data is within the ranges. This can happen if we get data with wrong offsets. */ if (header.length == DYNCOL_OFFSET_ERROR || diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c index 545084ea97f..a3426889a82 100644 --- a/mysys/mf_cache.c +++ b/mysys/mf_cache.c @@ -20,11 +20,12 @@ #include "my_static.h" #include "mysys_err.h" - /* - Remove an open tempfile so that it doesn't survive - if we crash; If the operating system doesn't support - this, just remember the file name for later removal - */ +/** + Remove an open tempfile so that it doesn't survive if we crash + + If the operating system doesn't support this, just remember + the file name for later removal +*/ static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)), const char *name) @@ -49,41 +50,46 @@ static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)), return 0; } - /* - ** Open tempfile cached by IO_CACHE - ** Should be used when no seeks are done (only reinit_io_buff) - ** Return 0 if cache is inited ok - ** The actual file is created when the IO_CACHE buffer gets filled - ** If dir is not given, use TMPDIR. - */ +/** + Open tempfile cached by IO_CACHE + Should be used when no seeks are done (only reinit_io_buff) + Return 0 if cache is inited ok + The actual file is created when the IO_CACHE buffer gets filled + If dir is not given, use TMPDIR. +*/ my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix, size_t cache_size, myf cache_myflags) { DBUG_ENTER("open_cached_file"); - cache->dir= dir ? my_strdup(dir,MYF(cache_myflags & MY_WME)) : (char*) 0; - cache->prefix= (prefix ? my_strdup(prefix,MYF(cache_myflags & MY_WME)) : - (char*) 0); + cache->dir= dir; + if (prefix) + { + DBUG_ASSERT(strlen(prefix) == 2); + memcpy(cache->prefix, prefix, 3); + } + else + cache->prefix[0]= 0; cache->file_name=0; cache->buffer=0; /* Mark that not open */ - if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0, + if (!init_io_cache(cache, -1, cache_size, WRITE_CACHE, 0L, 0, MYF(cache_myflags | MY_NABP))) { DBUG_RETURN(0); } - my_free(cache->dir); - my_free(cache->prefix); DBUG_RETURN(1); } - /* Create the temporary file */ - +/** + Create the temporary file +*/ my_bool real_open_cached_file(IO_CACHE *cache) { char name_buff[FN_REFLEN]; int error=1; DBUG_ENTER("real_open_cached_file"); - if ((cache->file=create_temp_file(name_buff, cache->dir, cache->prefix, + if ((cache->file=create_temp_file(name_buff, cache->dir, + cache->prefix[0] ? cache->prefix : 0, (O_RDWR | O_BINARY | O_TRUNC | O_TEMPORARY | O_SHORT_LIVED), MYF(MY_WME))) >= 0) @@ -114,8 +120,6 @@ void close_cached_file(IO_CACHE *cache) } #endif } - my_free(cache->dir); - my_free(cache->prefix); } DBUG_VOID_RETURN; } diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c index b78d73074da..debed8afed3 100644 --- a/mysys/mf_fn_ext.c +++ b/mysys/mf_fn_ext.c @@ -86,7 +86,7 @@ char *fn_ext2(const char *name) if (!(gpos= strrchr(name, FN_LIBCHAR))) gpos= name; #endif - // locate the last occurence of FN_EXTCHAR + // locate the last occurrence of FN_EXTCHAR pos= strrchr(gpos, FN_EXTCHAR); DBUG_RETURN((char*) (pos ? pos : strend(gpos))); } /* fn_ext2 */ diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index f356aa91929..a0ddc3e40a5 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates + Copyright (c) 2010, 2015, MariaDB 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 @@ -22,7 +23,6 @@ Possibly use of asyncronic io. macros for read and writes for faster io. Used instead of FILE when reading or writing whole files. - This code makes mf_rec_cache obsolete (currently only used by ISAM) One can change info->pos_in_file to a higher value to skip bytes in file if also info->read_pos is set to info->read_end. If called through open_cached_file(), then the temporary file will @@ -64,6 +64,16 @@ 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)) +static int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count); +static int _my_b_cache_read_r(IO_CACHE *info, uchar *Buffer, size_t Count); +static int _my_b_seq_read(IO_CACHE *info, uchar *Buffer, size_t Count); +static int _my_b_cache_write(IO_CACHE *info, const uchar *Buffer, size_t Count); +static int _my_b_cache_write_r(IO_CACHE *info, const uchar *Buffer, size_t Count); + +int (*_my_b_encr_read)(IO_CACHE *info,uchar *Buffer,size_t Count)= 0; +int (*_my_b_encr_write)(IO_CACHE *info,const uchar *Buffer,size_t Count)= 0; + + /* Setup internal pointers inside IO_CACHE @@ -72,7 +82,7 @@ static void my_aiowait(my_aio_result *result); info IO_CACHE handler NOTES - This is called on automaticly on init or reinit of IO_CACHE + This is called on automatically on init or reinit of IO_CACHE It must be called externally if one moves or copies an IO_CACHE object. */ @@ -97,6 +107,8 @@ static void init_functions(IO_CACHE* info) { enum cache_type type= info->type; + info->read_function = 0; /* Force a core if used */ + info->write_function = 0; /* Force a core if used */ switch (type) { case READ_NET: /* @@ -106,14 +118,35 @@ init_functions(IO_CACHE* info) programs that link against mysys but know nothing about THD, such as myisamchk */ + DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); break; case SEQ_READ_APPEND: info->read_function = _my_b_seq_read; - info->write_function = 0; /* Force a core if used */ + DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); + break; + case READ_CACHE: + if (info->myflags & MY_ENCRYPT) + { + DBUG_ASSERT(info->share == 0); + info->read_function = _my_b_encr_read; + break; + } + /* fall through */ + case WRITE_CACHE: + if (info->myflags & MY_ENCRYPT) + { + info->write_function = _my_b_encr_write; + break; + } + /* fall through */ + case READ_FIFO: + DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); + 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; + break; + case TYPE_NOT_SET: + DBUG_ASSERT(0); break; - default: - info->read_function = info->share ? _my_b_read_r : _my_b_read; - info->write_function = _my_b_write; } setup_io_cache(info); @@ -133,8 +166,8 @@ init_functions(IO_CACHE* info) If == 0 then use my_default_record_cache_size type Type of cache seek_offset Where cache should start reading/writing - use_async_io Set to 1 of we should use async_io (if avaiable) - cache_myflags Bitmap of differnt flags + use_async_io Set to 1 of we should use async_io (if available) + cache_myflags Bitmap of different flags MY_WME | MY_FAE | MY_NABP | MY_FNABP | MY_DONT_CHECK_FILESIZE @@ -145,7 +178,7 @@ init_functions(IO_CACHE* info) int init_io_cache(IO_CACHE *info, File file, size_t cachesize, enum cache_type type, my_off_t seek_offset, - pbool use_async_io, myf cache_myflags) + my_bool use_async_io, myf cache_myflags) { size_t min_cache; my_off_t pos; @@ -157,14 +190,13 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, info->file= file; info->type= TYPE_NOT_SET; /* Don't set it until mutex are created */ info->pos_in_file= seek_offset; - info->pre_close = info->pre_read = info->post_read = 0; - info->arg = 0; info->alloced_buffer = 0; info->buffer=0; info->seek_not_done= 0; if (file >= 0) { + DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT)); pos= mysql_file_tell(file, MYF(0)); if ((pos == (my_off_t) -1) && (my_errno == ESPIPE)) { @@ -181,6 +213,12 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, else info->seek_not_done= MY_TEST(seek_offset != pos); } + else + if (type == WRITE_CACHE && _my_b_encr_read) + { + cache_myflags|= MY_ENCRYPT; + DBUG_ASSERT(seek_offset == 0); + } info->disk_writes= 0; info->share=0; @@ -190,6 +228,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2; if (type == READ_CACHE || type == SEQ_READ_APPEND) { /* Assume file isn't growing */ + DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT)); if (!(cache_myflags & MY_DONT_CHECK_FILESIZE)) { /* Calculate end of file to avoid allocating oversized buffers */ @@ -207,7 +246,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, } } cache_myflags &= ~MY_DONT_CHECK_FILESIZE; - if (type != READ_NET && type != WRITE_NET) + if (type != READ_NET) { /* Retry allocating memory in smaller blocks until we get one */ cachesize= ((cachesize + min_cache-1) & ~(min_cache-1)); @@ -225,15 +264,18 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, buffer_block= cachesize; if (type == SEQ_READ_APPEND) buffer_block *= 2; + else if (cache_myflags & MY_ENCRYPT) + buffer_block= 2*(buffer_block + MY_AES_BLOCK_SIZE) + sizeof(IO_CACHE_CRYPT); if (cachesize == min_cache) flags|= (myf) MY_WME; if ((info->buffer= (uchar*) my_malloc(buffer_block, flags)) != 0) { - info->write_buffer=info->buffer; if (type == SEQ_READ_APPEND) - info->write_buffer = info->buffer + cachesize; - info->alloced_buffer=1; + info->write_buffer= info->buffer + cachesize; + else + info->write_buffer= info->buffer; + info->alloced_buffer= 1; break; /* Enough memory found */ } if (cachesize == min_cache) @@ -277,6 +319,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, if (use_async_io && ! my_disable_async_io) { DBUG_PRINT("info",("Using async io")); + DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT)); info->read_length/=2; info->read_function=_my_b_async_read; } @@ -300,7 +343,7 @@ static void my_aiowait(my_aio_result *result) if (errno == EINTR) continue; DBUG_PRINT("error",("No aio request, error: %d",errno)); - result->pending=0; /* Assume everythings is ok */ + result->pending=0; /* Assume everything is ok */ break; } ((my_aio_result*) tmp)->pending=0; @@ -322,18 +365,16 @@ static void my_aiowait(my_aio_result *result) 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) + my_bool use_async_io __attribute__((unused)), + my_bool clear_cache) { DBUG_ENTER("reinit_io_cache"); DBUG_PRINT("enter",("cache: 0x%lx type: %d seek_offset: %lu clear_cache: %d", (ulong) info, type, (ulong) seek_offset, (int) clear_cache)); - /* One can't do reinit with the following types */ - DBUG_ASSERT(type != READ_NET && info->type != READ_NET && - type != WRITE_NET && info->type != WRITE_NET && - type != SEQ_READ_APPEND && info->type != SEQ_READ_APPEND); + DBUG_ASSERT(type == READ_CACHE || type == WRITE_CACHE); + DBUG_ASSERT(info->type == READ_CACHE || info->type == WRITE_CACHE); /* If the whole file is in memory, avoid flushing to disk */ if (! clear_cache && @@ -391,8 +432,22 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, } else { - info->write_end=(info->buffer + info->buffer_length - - (seek_offset & (IO_SIZE-1))); + if (info->myflags & MY_ENCRYPT) + { + info->write_end = info->write_buffer + info->buffer_length; + if (seek_offset && info->file != -1) + { + info->read_end= info->buffer; + _my_b_encr_read(info, 0, 0); /* prefill the buffer */ + info->write_pos= info->read_pos; + info->pos_in_file+= info->buffer_length; + } + } + else + { + info->write_end=(info->buffer + info->buffer_length - + (seek_offset & (IO_SIZE-1))); + } info->end_of_file= ~(my_off_t) 0; } } @@ -405,6 +460,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, ((ulong) info->buffer_length < (ulong) (info->end_of_file - seek_offset))) { + DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT)); info->read_length=info->buffer_length/2; info->read_function=_my_b_async_read; } @@ -414,12 +470,72 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, } /* reinit_io_cache */ +int _my_b_read(IO_CACHE *info, uchar *Buffer, size_t Count) +{ + size_t left_length; + int res; + + /* If the buffer is not empty yet, copy what is available. */ + if ((left_length= (size_t) (info->read_end - info->read_pos))) + { + DBUG_ASSERT(Count > left_length); + memcpy(Buffer, info->read_pos, left_length); + Buffer+=left_length; + Count-=left_length; + } + res= info->read_function(info, Buffer, Count); + if (res && info->error >= 0) + info->error+= left_length; /* update number or read bytes */ + return res; +} + +int _my_b_write(IO_CACHE *info, const uchar *Buffer, size_t Count) +{ + size_t rest_length; + int res; + + /* Always use my_b_flush_io_cache() to flush write_buffer! */ + DBUG_ASSERT(Buffer != info->write_buffer); + + if (info->pos_in_file + info->buffer_length > info->end_of_file) + { + my_errno=errno=EFBIG; + return info->error = -1; + } + + rest_length= (size_t) (info->write_end - info->write_pos); + DBUG_ASSERT(Count >= rest_length); + memcpy(info->write_pos, Buffer, (size_t) rest_length); + Buffer+=rest_length; + Count-=rest_length; + info->write_pos+=rest_length; + + if (my_b_flush_io_cache(info, 1)) + return 1; + + if (Count) + { + my_off_t old_pos_in_file= info->pos_in_file; + res= info->write_function(info, Buffer, Count); + Count-= info->pos_in_file - old_pos_in_file; + Buffer+= info->pos_in_file - old_pos_in_file; + } + else + res= 0; + + if (!res && Count) + { + memcpy(info->write_pos, Buffer, Count); + info->write_pos+= Count; + } + return res; +} /* Read buffered. SYNOPSIS - _my_b_read() + _my_b_cache_read() info IO_CACHE pointer Buffer Buffer to retrieve count bytes from file Count Number of bytes to read into Buffer @@ -435,7 +551,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, types than my_off_t unless you can be sure that their value fits. Same applies to differences of file offsets. - When changing this function, check _my_b_read_r(). It might need the + When changing this function, check _my_b_cache_read_r(). It might need the same change. RETURN @@ -445,20 +561,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, Otherwise info->error contains the number of bytes in Buffer. */ -int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) +int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count) { - size_t length,diff_length,left_length, max_length; + size_t length, diff_length, left_length= 0, max_length; my_off_t pos_in_file; - DBUG_ENTER("_my_b_read"); - - /* If the buffer is not empty yet, copy what is available. */ - if ((left_length= (size_t) (info->read_end-info->read_pos))) - { - DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */ - memcpy(Buffer,info->read_pos, left_length); - Buffer+=left_length; - Count-=left_length; - } + DBUG_ENTER("_my_b_cache_read"); /* pos_in_file always point on where info->buffer was read */ pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer); @@ -515,7 +622,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) what we did already read from a block. That way, the read will end aligned with a block. */ - length=(Count & (size_t) ~(IO_SIZE-1))-diff_length; + length= IO_ROUND_DN(Count) - diff_length; if ((read_length= mysql_file_read(info->file,Buffer, length, info->myflags)) != length) { @@ -558,7 +665,11 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) info->error= (int) left_length; DBUG_RETURN(1); } - length=0; /* Didn't read any chars */ + else + { + info->error= 0; + DBUG_RETURN(0); /* EOF */ + } } else if ((length= mysql_file_read(info->file,info->buffer, max_length, info->myflags)) < Count || @@ -685,12 +796,15 @@ void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare, cshare->source_cache= write_cache; /* Can be NULL. */ read_cache->share= cshare; - read_cache->read_function= _my_b_read_r; + read_cache->read_function= _my_b_cache_read_r; read_cache->current_pos= NULL; read_cache->current_end= NULL; if (write_cache) + { write_cache->share= cshare; + write_cache->write_function= _my_b_cache_write_r; + } DBUG_VOID_RETURN; } @@ -958,7 +1072,7 @@ static void unlock_io_cache(IO_CACHE *cache) Read from IO_CACHE when it is shared between several threads. SYNOPSIS - _my_b_read_r() + _my_b_cache_read_r() cache IO_CACHE pointer Buffer Buffer to retrieve count bytes from file Count Number of bytes to read into Buffer @@ -983,7 +1097,7 @@ static void unlock_io_cache(IO_CACHE *cache) types than my_off_t unless you can be sure that their value fits. Same applies to differences of file offsets. (Bug #11527) - When changing this function, check _my_b_read(). It might need the + When changing this function, check _my_b_cache_read(). It might need the same change. RETURN @@ -991,20 +1105,14 @@ static void unlock_io_cache(IO_CACHE *cache) 1 Error: can't read requested characters */ -int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count) +static int _my_b_cache_read_r(IO_CACHE *cache, uchar *Buffer, size_t Count) { my_off_t pos_in_file; - size_t length, diff_length, left_length; + size_t length, diff_length, left_length= 0; IO_CACHE_SHARE *cshare= cache->share; - DBUG_ENTER("_my_b_read_r"); + DBUG_ENTER("_my_b_cache_read_r"); + DBUG_ASSERT(!(cache->myflags & MY_ENCRYPT)); - if ((left_length= (size_t) (cache->read_end - cache->read_pos))) - { - DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */ - memcpy(Buffer, cache->read_pos, left_length); - Buffer+= left_length; - Count-= left_length; - } while (Count) { size_t cnt, len; @@ -1119,21 +1227,22 @@ int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count) */ static void copy_to_read_buffer(IO_CACHE *write_cache, - const uchar *write_buffer, size_t write_length) + const uchar *write_buffer, my_off_t pos_in_file) { + size_t write_length= write_cache->pos_in_file - pos_in_file; 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. + It can be bigger if _my_b_cache_write_r() is called with a big length. */ while (write_length) { size_t copy_length= MY_MIN(write_length, write_cache->buffer_length); int __attribute__((unused)) rc; - rc= lock_io_cache(write_cache, write_cache->pos_in_file); + rc= lock_io_cache(write_cache, pos_in_file); /* The writing thread does always have the lock when it awakes. */ DBUG_ASSERT(rc); @@ -1141,7 +1250,7 @@ static void copy_to_read_buffer(IO_CACHE *write_cache, cshare->error= 0; cshare->read_end= cshare->buffer + copy_length; - cshare->pos_in_file= write_cache->pos_in_file; + cshare->pos_in_file= pos_in_file; /* Mark all threads as running and wake them. */ unlock_io_cache(write_cache); @@ -1165,20 +1274,12 @@ static void copy_to_read_buffer(IO_CACHE *write_cache, 1 Failed to read */ -int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count) +static int _my_b_seq_read(IO_CACHE *info, uchar *Buffer, size_t Count) { - size_t length, diff_length, left_length, save_count, max_length; + size_t length, diff_length, left_length= 0, save_count, max_length; my_off_t pos_in_file; save_count=Count; - /* first, read the regular buffer */ - if ((left_length=(size_t) (info->read_end-info->read_pos))) - { - DBUG_ASSERT(Count > left_length); /* User is not using my_b_read() */ - memcpy(Buffer,info->read_pos, left_length); - Buffer+=left_length; - Count-=left_length; - } lock_append_buffer(info); /* pos_in_file always point on where info->buffer was read */ @@ -1206,7 +1307,7 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count) /* Fill first intern buffer */ size_t read_length; - length=(Count & (size_t) ~(IO_SIZE-1))-diff_length; + length= IO_ROUND_DN(Count) - diff_length; if ((read_length= mysql_file_read(info->file,Buffer, length, info->myflags)) == (size_t) -1) { @@ -1323,18 +1424,14 @@ read_append_buffer: 1 An error has occurred; IO_CACHE to error state. */ -int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count) +int _my_b_async_read(IO_CACHE *info, uchar *Buffer, size_t Count) { - size_t length,read_length,diff_length,left_length,use_length,org_Count; + size_t length, read_length, diff_length, left_length=0, use_length, org_Count; size_t max_length; my_off_t next_pos_in_file; uchar *read_buffer; - memcpy(Buffer,info->read_pos, - (left_length= (size_t) (info->read_end-info->read_pos))); - Buffer+=left_length; org_Count=Count; - Count-=left_length; if (info->inited) { /* wait for read block */ @@ -1488,7 +1585,7 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count) info->read_end-=info->read_length; } info->read_length=info->buffer_length; /* Use hole buffer */ - info->read_function=_my_b_read; /* Use normal IO_READ next */ + info->read_function=_my_b_cache_read; /* Use normal IO_READ next */ } else info->inited=info->aio_result.pending=1; @@ -1503,13 +1600,8 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count) int _my_b_get(IO_CACHE *info) { uchar 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; } @@ -1523,70 +1615,61 @@ int _my_b_get(IO_CACHE *info) -1 On error; my_errno contains error code. */ -int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count) +int _my_b_cache_write(IO_CACHE *info, const uchar *Buffer, size_t Count) { - size_t rest_length,length; - my_off_t pos_in_file= info->pos_in_file; - - DBUG_EXECUTE_IF("simulate_huge_load_data_file", - { - pos_in_file=(my_off_t)(5000000000ULL); - }); - if (pos_in_file+info->buffer_length > info->end_of_file) + if (Buffer != info->write_buffer) { - my_errno=errno=EFBIG; - return info->error = -1; + Count= IO_ROUND_DN(Count); + if (!Count) + return 0; } - rest_length= (size_t) (info->write_end - info->write_pos); - memcpy(info->write_pos,Buffer,(size_t) rest_length); - 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 & (size_t) ~(IO_SIZE-1); - if (info->seek_not_done) + if (info->seek_not_done) + { + /* + 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 (mysql_file_seek(info->file, info->pos_in_file, MY_SEEK_SET, + MYF(info->myflags & MY_WME)) == MY_FILEPOS_ERROR) { - /* - 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 (mysql_file_seek(info->file, info->pos_in_file, MY_SEEK_SET, MYF(0))) - { - info->error= -1; - return (1); - } - info->seek_not_done=0; + info->error= -1; + return 1; } - if (mysql_file_write(info->file, Buffer, length, info->myflags | MY_NABP)) - return info->error= -1; + info->seek_not_done=0; + } + if (mysql_file_write(info->file, Buffer, Count, info->myflags | MY_NABP)) + return info->error= -1; - /* - 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); + info->pos_in_file+= Count; + return 0; +} + + +/* + 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. +*/ +static int _my_b_cache_write_r(IO_CACHE *info, const uchar *Buffer, size_t Count) +{ + my_off_t old_pos_in_file= info->pos_in_file; + int res= _my_b_cache_write(info, Buffer, Count); + if (res) + return res; + + DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); + DBUG_ASSERT(info->share); + copy_to_read_buffer(info, Buffer, old_pos_in_file); - Count-=length; - Buffer+=length; - info->pos_in_file+=length; - } - memcpy(info->write_pos,Buffer,(size_t) Count); - info->write_pos+=Count; return 0; } @@ -1597,7 +1680,7 @@ int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count) the write buffer before we are ready with it. */ -int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count) +int my_b_append(IO_CACHE *info, const uchar *Buffer, size_t Count) { size_t rest_length,length; @@ -1606,6 +1689,7 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count) day, we might need to add a call to copy_to_read_buffer(). */ DBUG_ASSERT(!info->share); + DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); lock_append_buffer(info); rest_length= (size_t) (info->write_end - info->write_pos); @@ -1622,7 +1706,7 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count) } if (Count >= IO_SIZE) { /* Fill first intern buffer */ - length=Count & (size_t) ~(IO_SIZE-1); + length= IO_ROUND_DN(Count); if (mysql_file_write(info->file,Buffer, length, info->myflags | MY_NABP)) { unlock_append_buffer(info); @@ -1661,7 +1745,7 @@ int my_b_safe_write(IO_CACHE *info, const uchar *Buffer, size_t Count) we will never get a seek over the end of the buffer */ -int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count, +int my_block_write(IO_CACHE *info, const uchar *Buffer, size_t Count, my_off_t pos) { size_t length; @@ -1672,6 +1756,7 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count, day, we might need to add a call to copy_to_read_buffer(). */ DBUG_ASSERT(!info->share); + DBUG_ASSERT(!(info->myflags & MY_ENCRYPT)); if (pos < info->pos_in_file) { @@ -1719,11 +1804,9 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count, #define UNLOCK_APPEND_BUFFER if (need_append_buffer_lock) \ unlock_append_buffer(info); -int my_b_flush_io_cache(IO_CACHE *info, - int need_append_buffer_lock __attribute__((unused))) +int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock) { size_t length; - my_off_t pos_in_file; my_bool append_cache= (info->type == SEQ_READ_APPEND); DBUG_ENTER("my_b_flush_io_cache"); DBUG_PRINT("enter", ("cache: 0x%lx", (long) info)); @@ -1742,52 +1825,30 @@ int my_b_flush_io_cache(IO_CACHE *info, if ((length=(size_t) (info->write_pos - info->write_buffer))) { - /* - 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); - - pos_in_file=info->pos_in_file; - /* - If we have append cache, we always open the file with - O_APPEND which moves the pos to EOF automatically on every write - */ - if (!append_cache && info->seek_not_done) - { /* File touched, do seek */ - if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(info->myflags & MY_WME)) == - MY_FILEPOS_ERROR) - { - UNLOCK_APPEND_BUFFER; - DBUG_RETURN((info->error= -1)); - } - if (!append_cache) - info->seek_not_done=0; - } - if (!append_cache) - info->pos_in_file+=length; - info->write_end= (info->write_buffer+info->buffer_length- - ((pos_in_file+length) & (IO_SIZE-1))); - - if (mysql_file_write(info->file,info->write_buffer,length, - info->myflags | MY_NABP)) - info->error= -1; - else - info->error= 0; - if (!append_cache) + if (append_cache) { - set_if_bigger(info->end_of_file,(pos_in_file+length)); + + if (mysql_file_write(info->file, info->write_buffer, length, + info->myflags | MY_NABP)) + info->error= -1; + else + info->error= 0; + + info->end_of_file+= info->write_pos - info->append_read_pos; + info->append_read_pos= info->write_buffer; + DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0))); } else { - info->end_of_file+=(info->write_pos-info->append_read_pos); - DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0))); - } + int res= info->write_function(info, info->write_buffer, length); + if (res) + DBUG_RETURN(res); - info->append_read_pos=info->write_pos=info->write_buffer; + set_if_bigger(info->end_of_file, info->pos_in_file); + } + info->write_end= (info->write_buffer + info->buffer_length - + ((info->pos_in_file + length) & (IO_SIZE - 1))); + info->write_pos= info->write_buffer; ++info->disk_writes; UNLOCK_APPEND_BUFFER; DBUG_RETURN(info->error); @@ -1825,7 +1886,6 @@ int my_b_flush_io_cache(IO_CACHE *info, int end_io_cache(IO_CACHE *info) { int error=0; - IO_CACHE_CALLBACK pre_close; DBUG_ENTER("end_io_cache"); DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info)); @@ -1835,11 +1895,6 @@ int end_io_cache(IO_CACHE *info) */ DBUG_ASSERT(!info->share || !info->share->total_threads); - if ((pre_close=info->pre_close)) - { - (*pre_close)(info); - info->pre_close= 0; - } if (info->alloced_buffer) { info->alloced_buffer=0; @@ -1944,7 +1999,7 @@ int main(int argc, char** argv) /* check correctness of tests */ if (total_bytes != status.st_size) { - fprintf(stderr,"Not the same number of bytes acutally in file as bytes \ + fprintf(stderr,"Not the same number of bytes actually in file as bytes \ supposedly written\n"); error=1; } diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 9e693209445..2499094037d 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -61,7 +61,6 @@ my_b_copy_to_file(IO_CACHE *cache, FILE *file) if (my_fwrite(file, cache->read_pos, bytes_in_cache, MYF(MY_WME | MY_NABP)) == (size_t) -1) DBUG_RETURN(1); - cache->read_pos= cache->read_end; } while ((bytes_in_cache= my_b_fill(cache))); if(cache->error == -1) DBUG_RETURN(1); @@ -181,60 +180,19 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) DBUG_VOID_RETURN; } - -/* - Fill buffer of the cache. - - NOTES - This assumes that you have already used all characters in the CACHE, - independent of the read_pos value! - - RETURN - 0 On error or EOF (info->error = -1 on error) - # Number of characters -*/ - - -size_t my_b_fill(IO_CACHE *info) +int my_b_pread(IO_CACHE *info, uchar *Buffer, size_t Count, my_off_t pos) { - my_off_t pos_in_file=(info->pos_in_file+ - (size_t) (info->read_end - info->buffer)); - size_t diff_length, length, max_length; - - if (info->seek_not_done) - { /* File touched, do seek */ - if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) == - MY_FILEPOS_ERROR) - { - info->error= 0; - return 0; - } - info->seek_not_done=0; - } - diff_length=(size_t) (pos_in_file & (IO_SIZE-1)); - max_length=(info->read_length-diff_length); - if (max_length >= (info->end_of_file - pos_in_file)) - max_length= (size_t) (info->end_of_file - pos_in_file); - - if (!max_length) - { - info->error= 0; - return 0; /* EOF */ - } - DBUG_EXECUTE_IF ("simulate_my_b_fill_error", - {DBUG_SET("+d,simulate_file_read_error");}); - if ((length= mysql_file_read(info->file, info->buffer, max_length, - info->myflags)) == (size_t) -1) + if (info->myflags & MY_ENCRYPT) { - info->error= -1; - return 0; + my_b_seek(info, pos); + return my_b_read(info, Buffer, Count); } - info->read_pos=info->buffer; - info->read_end=info->buffer+length; - info->pos_in_file=pos_in_file; - return length; -} + /* backward compatibility behavior. XXX remove it? */ + if (mysql_file_pread(info->file, Buffer, Count, pos, info->myflags | MY_NABP)) + return info->error= -1; + return 0; +} /* Read a string ended by '\n' into a buffer of 'max_length' size. diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 0e7c43cc4c4..9356f9154f0 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -58,11 +58,11 @@ When a new block is required it is first tried to pop one from the stack. If the stack is empty, it is tried to get a never-used block from the pool. If this is empty too, then a block is taken from the LRU ring, flushing it - to disk, if neccessary. This is handled in find_key_block(). + to disk, if necessary. This is handled in find_key_block(). With the new free list, the blocks can have three temperatures: hot, warm and cold (which is free). This is remembered in the block header by the enum BLOCK_TEMPERATURE temperature variable. Remembering the - temperature is neccessary to correctly count the number of warm blocks, + temperature is necessary to correctly count the number of warm blocks, which is required to decide when blocks are allowed to become hot. Whenever a block is inserted to another (sub-)chain, we take the old and new temperature into account to decide if we got one more or less warm block. @@ -450,7 +450,7 @@ static inline uint next_power(uint value) structure of the type SIMPLE_KEY_CACHE_CB that is used for this key cache. The parameter keycache is supposed to point to this structure. The parameter key_cache_block_size specifies the size of the blocks in - the key cache to be built. The parameters division_limit and age_threshhold + the key cache to be built. The parameters division_limit and age_threshold determine the initial values of those characteristics of the key cache that are used for midpoint insertion strategy. The parameter use_mem specifies the total amount of memory to be allocated for key cache blocks @@ -4166,10 +4166,10 @@ restart: if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE)) { - BLOCK_LINK *last_for_update= NULL; BLOCK_LINK *last_in_switch= NULL; uint total_found= 0; uint found; + last_for_update= NULL; /* Finally free all clean blocks for this file. diff --git a/mysys/my_access.c b/mysys/my_access.c index 68cd01d33e6..75774240406 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -173,6 +173,11 @@ static my_bool does_drive_exists(char drive_letter) file names with a colon (:) are not allowed because such file names store data in Alternate Data Streams which can be used to hide the data. + Apart from colon, other characters that are not allowed in filenames + on Windows are greater/less sign, double quotes, forward slash, backslash, + pipe and star characters. + + See MSDN documentation on filename restrictions. @param name contains the file name with or without path @param length contains the length of file name @@ -181,6 +186,8 @@ static my_bool does_drive_exists(char drive_letter) @return TRUE if the file name is allowed, FALSE otherwise. */ +#define ILLEGAL_FILENAME_CHARS "<>:\"/\\|?*" + my_bool is_filename_allowed(const char *name __attribute__((unused)), size_t length __attribute__((unused)), my_bool allow_current_dir __attribute__((unused))) @@ -205,6 +212,8 @@ my_bool is_filename_allowed(const char *name __attribute__((unused)), return (allow_current_dir && (ch - name == 1) && does_drive_exists(*name)); } + else if (strchr(ILLEGAL_FILENAME_CHARS, *ch)) + return FALSE; } return TRUE; } /* is_filename_allowed */ @@ -214,7 +223,7 @@ my_bool is_filename_allowed(const char *name __attribute__((unused)), /* - Check if a path will access a reserverd file name that may cause problems + Check if a path will access a reserved file name that may cause problems SYNOPSIS check_if_legal_filename diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index f831ad5121f..82043dc03fe 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -126,8 +126,8 @@ err: */ #elif defined(MY_ADDR_RESOLVE_FORK) /* - yet another - just execute addr2line or eu-addr2line, whatever available, - pipe the addresses to it, and parse the output + yet another - just execute addr2line pipe the addresses to it, and parse the + output */ #include <m_string.h> @@ -181,9 +181,19 @@ int start_addr2line_fork(const char *binary_path) int my_addr_resolve(void *ptr, my_addr_loc *loc) { - char input[32], *s; + char input[32]; size_t len; + ssize_t total_bytes_read = 0; + ssize_t extra_bytes_read = 0; + ssize_t parsed = 0; + + fd_set set; + struct timeval timeout; + + int filename_start = -1; + int line_number_start = -1; + Dl_info info; void *offset; @@ -207,24 +217,58 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) len= my_snprintf(input, sizeof(input), "%p\n", ptr - offset); if (write(in[1], input, len) <= 0) return 1; - if (read(out[0], output, sizeof(output)) <= 0) - return 1; - loc->func= s= output; - while (*s != '\n') - s++; - *s++= 0; - loc->file= s; - while (*s != ':') - s++; - *s++= 0; + FD_ZERO(&set); + FD_SET(out[0], &set); + + /* 100 ms should be plenty of time for addr2line to issue a response. */ + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + /* Read in a loop till all the output from addr2line is complete. */ + while (parsed == total_bytes_read && + select(out[0] + 1, &set, NULL, NULL, &timeout) > 0) + { + extra_bytes_read= read(out[0], output + total_bytes_read, + sizeof(output) - total_bytes_read); + if (extra_bytes_read < 0) + return 1; + /* Timeout or max bytes read. */ + if (extra_bytes_read == 0) + break; + + total_bytes_read += extra_bytes_read; + + /* Go through the addr2line response and get the required data. + The response is structured in 2 lines. The first line contains the function + name, while the second one contains <filename>:<line number> */ + for (; parsed < total_bytes_read; parsed++) + { + if (output[parsed] == '\n') + { + filename_start = parsed + 1; + output[parsed] = '\0'; + } + if (filename_start != -1 && output[parsed] == ':') + { + line_number_start = parsed + 1; + output[parsed] = '\0'; + break; + } + } + } + + /* Response is malformed. */ + if (filename_start == -1 || line_number_start == -1) + return 1; + + loc->func= output; + loc->file= output + filename_start; + loc->line= atoi(output + line_number_start); + + /* Addr2line was unable to extract any meaningful information. */ if (strcmp(loc->file, "??") == 0) return 1; - loc->line= 0; - while (isdigit(*s)) - loc->line = loc->line * 10 + (*s++ - '0'); - *s = 0; loc->file= strip_path(loc->file); return 0; diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 05b6cac6733..1b0ef857afa 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -45,7 +45,7 @@ DESCRIPTION This function prepares memory root for further use, sets initial size of chunk for memory allocation and pre-allocates first block if specified. - Altough error can happen during execution of this function if + Although error can happen during execution of this function if pre_alloc_size is non-0 it won't be reported. Instead it will be reported as error in first alloc_root() on this memory root. @@ -58,7 +58,8 @@ void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, myf my_flags) { DBUG_ENTER("init_alloc_root"); - DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root)); + DBUG_PRINT("enter",("root: %p prealloc: %zu", mem_root, + pre_alloc_size)); mem_root->free= mem_root->used= mem_root->pre_alloc= 0; mem_root->min_malloc= 32; @@ -107,6 +108,7 @@ void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size __attribute__((unused))) { + DBUG_ENTER("reset_root_defaults"); DBUG_ASSERT(alloc_root_inited(mem_root)); mem_root->block_size= (((block_size - ALLOC_ROOT_MIN_BLOCK_SIZE) & ~1) | @@ -129,7 +131,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, { /* We found a suitable block, no need to do anything else */ mem_root->pre_alloc= mem; - return; + DBUG_VOID_RETURN; } if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size) { @@ -160,6 +162,8 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size, else #endif mem_root->pre_alloc= 0; + + DBUG_VOID_RETURN; } @@ -168,7 +172,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) #if defined(HAVE_valgrind) && defined(EXTRA_DEBUG) reg1 USED_MEM *next; DBUG_ENTER("alloc_root"); - DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root)); + DBUG_PRINT("enter",("root: %p", mem_root)); DBUG_ASSERT(alloc_root_inited(mem_root)); @@ -192,8 +196,8 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) next->next= mem_root->used; next->size= length; mem_root->used= next; - DBUG_PRINT("exit",("ptr: 0x%lx", (long) (((char*) next)+ - ALIGN_SIZE(sizeof(USED_MEM))))); + DBUG_PRINT("exit",("ptr: %p", (((char*) next)+ + ALIGN_SIZE(sizeof(USED_MEM))))); DBUG_RETURN((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)))); #else size_t get_size, block_size; @@ -201,7 +205,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) reg1 USED_MEM *next= 0; reg2 USED_MEM **prev; DBUG_ENTER("alloc_root"); - DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root)); + DBUG_PRINT("enter",("root: %p", mem_root)); DBUG_ASSERT(alloc_root_inited(mem_root)); DBUG_EXECUTE_IF("simulate_out_of_memory", @@ -261,7 +265,7 @@ void *alloc_root(MEM_ROOT *mem_root, size_t length) mem_root->first_block_usage= 0; } TRASH_ALLOC(point, length); - DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point)); + DBUG_PRINT("exit",("ptr: %p", point)); DBUG_RETURN((void*) point); #endif } @@ -371,7 +375,7 @@ void free_root(MEM_ROOT *root, myf MyFlags) { reg1 USED_MEM *next,*old; DBUG_ENTER("free_root"); - DBUG_PRINT("enter",("root: 0x%lx flags: %u", (long) root, (uint) MyFlags)); + DBUG_PRINT("enter",("root: %p flags: %u", root, (uint) MyFlags)); if (MyFlags & MY_MARK_BLOCKS_FREE) { diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 67c478659b5..0eaf1a88aa1 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -306,6 +306,12 @@ uint bitmap_set_next(MY_BITMAP *map) } +/** + Set the specified number of bits in the bitmap buffer. + + @param map [IN] Bitmap + @param prefix_size [IN] Number of bits to be set +*/ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size) { uint prefix_bytes, prefix_bits, d; @@ -319,11 +325,12 @@ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size) m+= prefix_bytes; if ((prefix_bits= prefix_size & 7)) { - *m++= (1 << prefix_bits)-1; - prefix_bytes++; + *(m++)= (1 << prefix_bits)-1; + // As the prefix bits are set, lets count this byte too as a prefix byte. + prefix_bytes ++; } if ((d= no_bytes_in_map(map)-prefix_bytes)) - bzero(m, d); + memset(m, 0, d); } @@ -373,6 +380,7 @@ my_bool bitmap_is_clear_all(const MY_BITMAP *map) my_bitmap_map *data_ptr= map->bitmap; my_bitmap_map *end= map->last_word_ptr; + DBUG_ASSERT(map->n_bits > 0); for (; data_ptr < end; data_ptr++) if (*data_ptr) return FALSE; diff --git a/mysys/my_chmod.c b/mysys/my_chmod.c index 91fd51b47d2..095ac858834 100644 --- a/mysys/my_chmod.c +++ b/mysys/my_chmod.c @@ -11,7 +11,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "mysys_priv.h" #include "mysys_err.h" diff --git a/mysys/my_compare.c b/mysys/my_compare.c index 6de7ff774c0..7fb2ef97916 100644 --- a/mysys/my_compare.c +++ b/mysys/my_compare.c @@ -99,12 +99,12 @@ static int compare_bin(const uchar *a, uint a_length, Example1: if the function is called for tuples ('aaa','bbb') and ('eee','fff'), then diff_pos[0] = 1 (as 'aaa' != 'eee') - diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart). + diff_pos[1] = 0 (offset from beginning of tuple b to 'eee' keypart). Example2: if the index function is called for tuples ('aaa','bbb') and ('aaa','fff'), diff_pos[0] = 2 (as 'aaa' != 'eee') - diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart, + diff_pos[1] = 3 (offset from beginning of tuple b to 'fff' keypart, here we assume that first key part is CHAR(3) NOT NULL) NOTES diff --git a/mysys/my_compress.c b/mysys/my_compress.c index 4cd43596031..0e4db5c3b17 100644 --- a/mysys/my_compress.c +++ b/mysys/my_compress.c @@ -162,7 +162,7 @@ uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen) SYNOPSIS my_uncompress() - packet Compressed data. This is is replaced with the orignal data. + packet Compressed data. This is is replaced with the original data. len Length of compressed data complen Length of the packet buffer (must be enough for the original data) @@ -203,129 +203,4 @@ my_bool my_uncompress(uchar *packet, size_t len, size_t *complen) DBUG_RETURN(0); } -/* - Internal representation of the frm blob is: - - ver 4 bytes - orglen 4 bytes - complen 4 bytes -*/ - -#define BLOB_HEADER 12 - - -/* - packfrm is a method used to compress the frm file for storage in a - handler. This method was developed for the NDB handler and has been moved - here to serve also other uses. - - SYNOPSIS - packfrm() - data Data reference to frm file data. - len Length of frm file data - out:pack_data Reference to the pointer to the packed frm data - out:pack_len Length of packed frm file data - - NOTES - data is replaced with compressed content - - RETURN VALUES - 0 Success - >0 Failure -*/ - -int packfrm(const uchar *data, size_t len, - uchar **pack_data, size_t *pack_len) -{ - int error; - size_t org_len, comp_len, blob_len; - uchar *blob; - DBUG_ENTER("packfrm"); - DBUG_PRINT("enter", ("data: 0x%lx len: %lu", (long) data, (ulong) len)); - - error= 1; - org_len= len; - if (my_compress((uchar*)data, &org_len, &comp_len)) - goto err; - - DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", (ulong) org_len, - (ulong) comp_len)); - DBUG_DUMP("compressed", data, org_len); - - error= 2; - blob_len= BLOB_HEADER + org_len; - if (!(blob= (uchar*) my_malloc(blob_len,MYF(MY_WME)))) - goto err; - - /* Store compressed blob in machine independent format */ - int4store(blob, 1); - int4store(blob+4, (uint32) len); - int4store(blob+8, (uint32) org_len); /* compressed length */ - - /* Copy frm data into blob, already in machine independent format */ - memcpy(blob+BLOB_HEADER, data, org_len); - - *pack_data= blob; - *pack_len= blob_len; - error= 0; - - DBUG_PRINT("exit", ("pack_data: 0x%lx pack_len: %lu", - (long) *pack_data, (ulong) *pack_len)); -err: - DBUG_RETURN(error); - -} - -/* - unpackfrm is a method used to decompress the frm file received from a - handler. This method was developed for the NDB handler and has been moved - here to serve also other uses for other clustered storage engines. - - SYNOPSIS - unpackfrm() - pack_data Data reference to packed frm file data - out:unpack_data Reference to the pointer to the unpacked frm data - out:unpack_len Length of unpacked frm file data - - RETURN VALUES¨ - 0 Success - >0 Failure -*/ - -int unpackfrm(uchar **unpack_data, size_t *unpack_len, - const uchar *pack_data) -{ - uchar *data; - size_t complen, orglen; - ulong ver; - DBUG_ENTER("unpackfrm"); - DBUG_PRINT("enter", ("pack_data: 0x%lx", (long) pack_data)); - - ver= uint4korr(pack_data); - orglen= uint4korr(pack_data+4); - complen= uint4korr(pack_data+8); - - DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu", - ver, (ulong) complen, (ulong) orglen)); - DBUG_DUMP("blob->data", pack_data + BLOB_HEADER, complen); - - if (ver != 1) - DBUG_RETURN(1); - if (!(data= my_malloc(MY_MAX(orglen, complen), MYF(MY_WME)))) - DBUG_RETURN(2); - memcpy(data, pack_data + BLOB_HEADER, complen); - - if (my_uncompress(data, complen, &orglen)) - { - my_free(data); - DBUG_RETURN(3); - } - - *unpack_data= data; - *unpack_len= orglen; - - DBUG_PRINT("exit", ("frmdata: 0x%lx len: %lu", (long) *unpack_data, - (ulong) *unpack_len)); - DBUG_RETURN(0); -} #endif /* HAVE_COMPRESS */ diff --git a/mysys/my_create.c b/mysys/my_create.c index 32ad3d44a7a..014b65c4e14 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -43,7 +43,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags, #if defined(_WIN32) fd= my_win_open(FileName, access_flags | O_CREAT); #else - fd= open((char *) FileName, access_flags | O_CREAT, + fd= open((char *) FileName, access_flags | O_CREAT | O_CLOEXEC, CreateFlags ? CreateFlags : my_umask); #endif diff --git a/mysys/my_default.c b/mysys/my_default.c index 5d9e4ffac88..2358aed8f3b 100644 --- a/mysys/my_default.c +++ b/mysys/my_default.c @@ -25,7 +25,7 @@ pre- and end 'blank space' are removed from options and values. The following escape sequences are recognized in values: \b \t \n \r \\ - The following arguments are handled automaticly; If used, they must be + The following arguments are handled automatically; If used, they must be first argument on the command line! --no-defaults ; no options are read. --defaults-file=full-path-to-default-file ; Only this file will be read. @@ -63,7 +63,7 @@ check the pointer, use "----args-separator----" here to ease debug if someone misused it. - The args seprator will only be added when + The args separator will only be added when my_getopt_use_args_seprator is set to TRUE before calling load_defaults(); @@ -103,8 +103,7 @@ static const char *f_extensions[]= { ".cnf", 0 }; #define NEWLINE "\n" #endif -static int handle_default_option(void *in_ctx, const char *group_name, - const char *option); +static int handle_default_option(void *, const char *, const char *); /* This structure defines the context that we pass to callback @@ -411,14 +410,13 @@ int get_defaults_options(int argc, char **argv, char **extra_defaults, char **group_suffix) { - int org_argc= argc, prev_argc= 0; + int org_argc= argc; *defaults= *extra_defaults= *group_suffix= 0; - while (argc >= 2 && argc != prev_argc) + while (argc >= 2) { /* Skip program name or previously handled argument */ argv++; - prev_argc= argc; /* To check if we found */ if (!*defaults && is_prefix(*argv,"--defaults-file=")) { *defaults= *argv + sizeof("--defaults-file=")-1; @@ -437,6 +435,7 @@ int get_defaults_options(int argc, char **argv, argc--; continue; } + break; } return org_argc - argc; } @@ -489,8 +488,7 @@ int load_defaults(const char *conf_file, const char **groups, easily command line options override options in configuration files NOTES - In case of fatal error, the function will print a warning and do - exit(1) + In case of fatal error, the function will print a warning and returns 2 To free used memory one should call free_defaults() with the argument that was put in *argv @@ -599,7 +597,7 @@ int my_load_defaults(const char *conf_file, const char **groups, (*argv)+= args_used; /* - Check if we wan't to see the new argument list + Check if we want to see the new argument list This options must always be the last of the default options */ if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults")) @@ -643,8 +641,7 @@ int my_load_defaults(const char *conf_file, const char **groups, err: fprintf(stderr,"Fatal error in defaults handling. Program aborted\n"); - exit(1); - return 0; /* Keep compiler happy */ + return 2; } @@ -919,7 +916,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler, end= remove_end_comment(ptr); if ((value= strchr(ptr, '='))) - end= value; /* Option without argument */ + end= value; for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ; if (!value) { diff --git a/mysys/my_dlerror.c b/mysys/my_dlerror.c new file mode 100644 index 00000000000..db21b7fc274 --- /dev/null +++ b/mysys/my_dlerror.c @@ -0,0 +1,31 @@ +/* + Copyright (c) 2017, MariaDB + + 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; version 2 of the License. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include <my_global.h> +#include <string.h> + +const char *my_dlerror(const char *dlpath) +{ + const char *errmsg=dlerror(); + size_t dlpathlen= strlen(dlpath); + if (!strncmp(dlpath, errmsg, dlpathlen)) + { /* if errmsg starts from dlpath, trim this prefix */ + errmsg+=dlpathlen; + if (*errmsg == ':') errmsg++; + if (*errmsg == ' ') errmsg++; + } + return errmsg; +} diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index f3d64845526..c720e2c9168 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -42,7 +42,7 @@ static void make_ftype(char * to,int flag); FILE *my_fopen(const char *filename, int flags, myf MyFlags) { FILE *fd; - char type[5]; + char type[10]; DBUG_ENTER("my_fopen"); DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %lu", filename, flags, MyFlags)); @@ -81,8 +81,7 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags) my_errno=errno; DBUG_PRINT("error",("Got error %d on open",my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) - my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND : - EE_CANTCREATEFILE, + my_error((flags & O_RDONLY) ? EE_FILENOTFOUND : EE_CANTCREATEFILE, MYF(ME_BELL+ME_WAITTANG), filename, my_errno); DBUG_RETURN((FILE*) 0); } /* my_fopen */ @@ -345,9 +344,11 @@ static void make_ftype(register char * to, register int flag) else *to++= 'r'; -#if FILE_BINARY /* If we have binary-files */ if (flag & FILE_BINARY) *to++='b'; -#endif + + if (O_CLOEXEC) + *to++= 'e'; + *to='\0'; } /* make_ftype */ diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index e68a08ee735..57b28d1fd8a 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -47,16 +47,17 @@ static char *check_struct_option(char *cur_arg, char *key_name); order of their arguments must correspond to each other. */ static const char *special_opt_prefix[]= -{"skip", "disable", "enable", "maximum", "loose", 0}; +{"skip", "disable", "enable", "maximum", "loose", "autoset", 0}; static const uint special_opt_prefix_lengths[]= -{ 4, 7, 6, 7, 5, 0}; +{ 4, 7, 6, 7, 5, 7, 0}; enum enum_special_opt -{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE}; +{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE, OPT_AUTOSET}; char *disabled_my_option= (char*) "0"; char *enabled_my_option= (char*) "1"; +char *autoset_my_option= (char*) "auto"; -/* +/* This is a flag that can be set in client programs. 0 means that my_getopt will not print error messages, but the client should do it by itself @@ -64,13 +65,21 @@ char *enabled_my_option= (char*) "1"; my_bool my_getopt_print_errors= 1; -/* +/* This is a flag that can be set in client programs. 1 means that my_getopt will skip over options it does not know how to handle. */ my_bool my_getopt_skip_unknown= 0; + +/* + This is a flag that can be set in client programs. 1 means that + my_getopt will reconize command line options by their unambiguous + prefixes. 0 means an option must be always specified in full. +*/ +my_bool my_getopt_prefix_matching= 1; + static void default_reporter(enum loglevel level, const char *format, ...) { @@ -190,7 +199,7 @@ int handle_options(int *argc, char ***argv, { uint UNINIT_VAR(opt_found), argvpos= 0, length; my_bool end_of_options= 0, must_be_var, set_maximum_value, - option_is_loose; + option_is_loose, option_is_autoset; char **pos, **pos_end, *optend, *opt_str, key_name[FN_REFLEN]; const char *UNINIT_VAR(prev_found); const struct my_option *optp; @@ -241,6 +250,7 @@ int handle_options(int *argc, char ***argv, must_be_var= 0; set_maximum_value= 0; option_is_loose= 0; + option_is_autoset= 0; cur_arg++; /* skip '-' */ if (*cur_arg == '-') /* check for long option, */ @@ -289,6 +299,8 @@ int handle_options(int *argc, char ***argv, length-= special_opt_prefix_lengths[i] + 1; if (i == OPT_LOOSE) option_is_loose= 1; + else if (i == OPT_AUTOSET) + option_is_autoset= 1; if ((opt_found= findopt(opt_str, length, &optp, &prev_found))) { if (opt_found > 1) @@ -450,6 +462,36 @@ int handle_options(int *argc, char ***argv, } argument= optend; } + else if (option_is_autoset) + { + if (optend) + { + my_getopt_error_reporter(ERROR_LEVEL, + "%s: automatically set " + "option '--%s' cannot take an argument", + my_progname, optp->name); + + DBUG_RETURN(EXIT_NO_ARGUMENT_ALLOWED); + } + /* + We support automatic setup only via get_one_option and only for + marked options. + */ + if (!get_one_option || + !(optp->var_type & GET_AUTO)) + { + my_getopt_error_reporter(option_is_loose ? + WARNING_LEVEL : ERROR_LEVEL, + "%s: automatic setup request is " + "unsupported by option '--%s'", + my_progname, optp->name); + if (!option_is_loose) + DBUG_RETURN(EXIT_ARGUMENT_INVALID); + continue; + } + else + argument= autoset_my_option; + } else if (optp->arg_type == REQUIRED_ARG && !optend) { /* Check if there are more arguments after this one, @@ -577,7 +619,8 @@ int handle_options(int *argc, char ***argv, (*argc)--; /* option handled (short), decrease argument count */ continue; } - if (((error= setval(optp, value, argument, set_maximum_value))) && + if ((!option_is_autoset) && + ((error= setval(optp, value, argument, set_maximum_value))) && !option_is_loose) DBUG_RETURN(error); if (get_one_option && get_one_option(optp->id, optp, argument)) @@ -851,6 +894,9 @@ static int findopt(char *optpat, uint length, if (!opt->name[length]) /* Exact match */ DBUG_RETURN(1); + if (!my_getopt_prefix_matching) + continue; + if (!count) { /* We only need to know one prev */ @@ -867,6 +913,14 @@ static int findopt(char *optpat, uint length, } } } + + if (count == 1) + my_getopt_error_reporter(INFORMATION_LEVEL, + "Using unique option prefix '%.*s' is error-prone " + "and can break in the future. " + "Please use the full name '%s' instead.", + length, optpat, *ffname); + DBUG_RETURN(count); } @@ -1307,7 +1361,8 @@ void my_cleanup_options(const struct my_option *options) SYNOPSIS init_variables() - options Array of options + options Array of options + func_init_one_value Call this function to init the variable NOTES We will initialize the value that is pointed to by options->value. @@ -1316,7 +1371,7 @@ void my_cleanup_options(const struct my_option *options) */ static void init_variables(const struct my_option *options, - init_func_p init_one_value) + init_func_p func_init_one_value) { DBUG_ENTER("init_variables"); for (; options->name; options++) @@ -1329,11 +1384,11 @@ static void init_variables(const struct my_option *options, set the value to default value. */ if (options->u_max_value) - init_one_value(options, options->u_max_value, options->max_value); + func_init_one_value(options, options->u_max_value, options->max_value); value= (options->var_type & GET_ASK_ADDR ? (*getopt_get_addr)("", 0, options, 0) : options->value); if (value) - init_one_value(options, value, options->def_value); + func_init_one_value(options, value, options->def_value); } DBUG_VOID_RETURN; } @@ -1348,6 +1403,48 @@ static uint print_name(const struct my_option *optp) return s - optp->name; } +/** prints option comment with indentation and wrapping. + + The comment column starts at startpos, and has width of width + Current cursor position is curpos, returns new cursor position + + @note can print one character beyond width! +*/ +static uint print_comment(const char *comment, + int curpos, int startpos, int width) +{ + const char *end= strend(comment); + int endpos= startpos + width; + + for (; curpos < startpos; curpos++) + putchar(' '); + + if (*comment == '.' || *comment == ',') + { + putchar(*comment); + comment++; + curpos++; + } + + while (end - comment > endpos - curpos) + { + const char *line_end; + for (line_end= comment + endpos - curpos; + line_end > comment && *line_end != ' '; + line_end--); + for (; comment < line_end; comment++) + putchar(*comment); + while (*comment == ' ') + comment++; /* skip the space, as a newline will take it's place now */ + putchar('\n'); + for (curpos= 0; curpos < startpos; curpos++) + putchar(' '); + } + printf("%s", comment); + return curpos + (end - comment); +} + + /* function: my_print_options @@ -1357,12 +1454,12 @@ static uint print_name(const struct my_option *optp) void my_print_help(const struct my_option *options) { uint col, name_space= 22, comment_space= 57; - const char *line_end; const struct my_option *optp; DBUG_ENTER("my_print_help"); for (optp= options; optp->name; optp++) { + const char *typelib_help= 0; if (!optp->comment) continue; if (optp->id && optp->id < 256) @@ -1401,29 +1498,51 @@ void my_print_help(const struct my_option *options) optp->arg_type == OPT_ARG ? "]" : ""); col+= (optp->arg_type == OPT_ARG) ? 5 : 3; } - if (col > name_space && optp->comment && *optp->comment) - { - putchar('\n'); - col= 0; - } } - for (; col < name_space; col++) - putchar(' '); if (optp->comment && *optp->comment) { - const char *comment= optp->comment, *end= strend(comment); + uint count; - while ((uint) (end - comment) > comment_space) + if (col > name_space) { - for (line_end= comment + comment_space; *line_end != ' '; line_end--); - for (; comment != line_end; comment++) - putchar(*comment); - comment++; /* skip the space, as a newline will take it's place now */ putchar('\n'); - for (col= 0; col < name_space; col++) - putchar(' '); + col= 0; + } + + col= print_comment(optp->comment, col, name_space, comment_space); + if (optp->var_type & GET_AUTO) + { + col= print_comment(" (Automatically configured unless set explicitly)", + col, name_space, comment_space); + } + + switch (optp->var_type & GET_TYPE_MASK) { + case GET_ENUM: + typelib_help= ". One of: "; + count= optp->typelib->count; + break; + case GET_SET: + typelib_help= ". Any combination of: "; + count= optp->typelib->count; + break; + case GET_FLAGSET: + typelib_help= ". Takes a comma-separated list of option=value pairs, " + "where value is on, off, or default, and options are: "; + count= optp->typelib->count - 1; + break; + } + if (typelib_help && + strstr(optp->comment, optp->typelib->type_names[0]) == NULL) + { + uint i; + col= print_comment(typelib_help, col, name_space, comment_space); + col= print_comment(optp->typelib->type_names[0], col, name_space, comment_space); + for (i= 1; i < count; i++) + { + col= print_comment(", ", col, name_space, comment_space); + col= print_comment(optp->typelib->type_names[i], col, name_space, comment_space); + } } - printf("%s", comment); } putchar('\n'); if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL) diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c index fbdcef88bda..bfa28f1d372 100644 --- a/mysys/my_getwd.c +++ b/mysys/my_getwd.c @@ -37,7 +37,7 @@ MyFlags Flags NOTES - Directory is allways ended with FN_LIBCHAR + Directory is always ended with FN_LIBCHAR RESULT 0 ok diff --git a/mysys/my_init.c b/mysys/my_init.c index a0f8e21322e..84489a994e3 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -99,7 +99,7 @@ my_bool my_init(void) if (my_progname) my_progname_short= my_progname + dirname_length(my_progname); - /* Initalize our mutex handling */ + /* Initialize our mutex handling */ my_mutex_init(); if (my_thread_global_init()) @@ -414,7 +414,7 @@ static my_bool win32_init_tcp_ip() WORD wVersionRequested = MAKEWORD( 2, 2 ); WSADATA wsaData; /* Be a good citizen: maybe another lib has already initialised - sockets, so dont clobber them unless necessary */ + sockets, so don't clobber them unless necessary */ if (WSAStartup( wVersionRequested, &wsaData )) { /* Load failed, maybe because of previously loaded @@ -453,7 +453,8 @@ PSI_mutex_key key_LOCK_localtime_r; #endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */ PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock, - key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm, + key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, + key_LOCK_alarm, key_LOCK_timer, key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap, key_THR_LOCK_lock, key_THR_LOCK_malloc, key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net, @@ -473,6 +474,7 @@ static PSI_mutex_info all_mysys_mutexes[]= { &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0}, { &key_KEY_CACHE_cache_lock, "KEY_CACHE::cache_lock", 0}, { &key_LOCK_alarm, "LOCK_alarm", PSI_FLAG_GLOBAL}, + { &key_LOCK_timer, "LOCK_timer", PSI_FLAG_GLOBAL}, { &key_my_thread_var_mutex, "my_thread_var::mutex", 0}, { &key_THR_LOCK_charset, "THR_LOCK_charset", PSI_FLAG_GLOBAL}, { &key_THR_LOCK_heap, "THR_LOCK_heap", PSI_FLAG_GLOBAL}, @@ -488,13 +490,14 @@ static PSI_mutex_info all_mysys_mutexes[]= { &key_LOCK_uuid_generator, "LOCK_uuid_generator", PSI_FLAG_GLOBAL } }; -PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond, +PSI_cond_key key_COND_alarm, key_COND_timer, key_IO_CACHE_SHARE_cond, key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend, key_THR_COND_threads, key_WT_RESOURCE_cond; static PSI_cond_info all_mysys_conds[]= { { &key_COND_alarm, "COND_alarm", PSI_FLAG_GLOBAL}, + { &key_COND_timer, "COND_timer", PSI_FLAG_GLOBAL}, { &key_IO_CACHE_SHARE_cond, "IO_CACHE_SHARE::cond", 0}, { &key_IO_CACHE_SHARE_cond_writer, "IO_CACHE_SHARE::cond_writer", 0}, { &key_my_thread_var_suspend, "my_thread_var::suspend", 0}, @@ -511,12 +514,17 @@ static PSI_rwlock_info all_mysys_rwlocks[]= #ifdef USE_ALARM_THREAD PSI_thread_key key_thread_alarm; +#endif +PSI_thread_key key_thread_timer; static PSI_thread_info all_mysys_threads[]= { - { &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL} +#ifdef USE_ALARM_THREAD + { &key_thread_alarm, "alarm", PSI_FLAG_GLOBAL}, +#endif + { &key_thread_timer, "statement_timer", PSI_FLAG_GLOBAL} }; -#endif /* USE_ALARM_THREAD */ + #ifdef HUGETLB_USE_PROC_MEMINFO PSI_file_key key_file_proc_meminfo; @@ -551,10 +559,8 @@ void my_init_mysys_psi_keys() count= sizeof(all_mysys_rwlocks)/sizeof(all_mysys_rwlocks[0]); mysql_rwlock_register(category, all_mysys_rwlocks, count); -#ifdef USE_ALARM_THREAD count= sizeof(all_mysys_threads)/sizeof(all_mysys_threads[0]); mysql_thread_register(category, all_mysys_threads, count); -#endif /* USE_ALARM_THREAD */ count= sizeof(all_mysys_files)/sizeof(all_mysys_files[0]); mysql_file_register(category, all_mysys_files, count); diff --git a/mysys/my_lib.c b/mysys/my_lib.c index be5bfe6c545..8daed1101ec 100644 --- a/mysys/my_lib.c +++ b/mysys/my_lib.c @@ -14,7 +14,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* TODO: check for overun of memory for names. */ +/* TODO: check for overrun of memory for names. */ #include "mysys_priv.h" #include <m_string.h> diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c index e533230106e..719c13a040e 100644 --- a/mysys/my_malloc.c +++ b/mysys/my_malloc.c @@ -48,7 +48,6 @@ static inline size_t malloc_size_and_flag(void *p, my_bool *is_thread_specific) #define MALLOC_FIX_POINTER_FOR_FREE(p) (((char*) (p)) - MALLOC_PREFIX_SIZE) #endif /* SAFEMALLOC */ -static MALLOC_SIZE_CB malloc_size_cb_func= NULL; /** Inform application that memory usage has changed @@ -59,17 +58,19 @@ static MALLOC_SIZE_CB malloc_size_cb_func= NULL; The type os size is long long, to be able to handle negative numbers to decrement the memory usage + + @return 0 - ok + 1 - failure, abort the allocation */ +static void dummy(long long size __attribute__((unused)), + my_bool is_thread_specific __attribute__((unused))) +{} -static void update_malloc_size(long long size, my_bool is_thread_specific) -{ - if (malloc_size_cb_func) - malloc_size_cb_func(size, is_thread_specific); -} +static MALLOC_SIZE_CB update_malloc_size= dummy; void set_malloc_size_cb(MALLOC_SIZE_CB func) { - malloc_size_cb_func= func; + update_malloc_size= func ? func : dummy; } @@ -108,7 +109,7 @@ void *my_malloc(size_t size, myf my_flags) my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_WAITTANG + ME_NOREFRESH + ME_FATALERROR),size); if (my_flags & MY_FAE) - exit(1); + abort(); } else { diff --git a/mysys/my_open.c b/mysys/my_open.c index b1327a316e9..3999810eb2e 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -52,9 +52,9 @@ File my_open(const char *FileName, int Flags, myf MyFlags) fd= my_win_open(FileName, Flags); #else if (MyFlags & MY_NOSYMLINKS) - fd = open_nosymlinks(FileName, Flags, my_umask); + fd = open_nosymlinks(FileName, Flags | O_CLOEXEC, my_umask); else - fd = open(FileName, Flags, my_umask); + fd = open(FileName, Flags | O_CLOEXEC, my_umask); #endif fd= my_register_filename(fd, FileName, FILE_BY_OPEN, diff --git a/mysys/my_port.c b/mysys/my_port.c index 96dbe10b1bd..75a07b03efe 100644 --- a/mysys/my_port.c +++ b/mysys/my_port.c @@ -12,8 +12,8 @@ You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA */ + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02111-1301, USA */ /* Small functions to make code portable diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 745cde9ec41..d3524279ea9 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -28,7 +28,7 @@ SYNOPSIOS my_pread() - Filedes File decsriptor + Filedes File descriptor Buffer Buffer to read data into Count Number of bytes to read offset Position to read from @@ -108,7 +108,7 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset, SYNOPSIOS my_pwrite() - Filedes File decsriptor + Filedes File descriptor Buffer Buffer to write data from Count Number of bytes to write offset Position to write to diff --git a/mysys/my_rdtsc.c b/mysys/my_rdtsc.c index ad11e8c6a6c..4228973caa8 100644 --- a/mysys/my_rdtsc.c +++ b/mysys/my_rdtsc.c @@ -249,6 +249,13 @@ ulonglong my_timer_cycles(void) clock_gettime(CLOCK_SGI_CYCLE, &tp); return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec; } +#elif defined(__GNUC__) && defined(__s390__) + /* covers both s390 and s390x */ + { + ulonglong result; + __asm__ __volatile__ ("stck %0" : "=Q" (result) : : "cc"); + return result; + } #elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) /* gethrtime may appear as either cycle or nanosecond counter */ return (ulonglong) gethrtime(); @@ -558,6 +565,8 @@ void my_timer_init(MY_TIMER_INFO *mti) mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC32; #elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE) mti->cycles.routine= MY_TIMER_ROUTINE_SGI_CYCLE; +#elif defined(__GNUC__) && defined(__s390__) + mti->cycles.routine= MY_TIMER_ROUTINE_ASM_S390; #elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME; #else @@ -753,7 +762,6 @@ void my_timer_init(MY_TIMER_INFO *mti) mti->cycles.frequency= mti->microseconds.frequency; else { - ulonglong time1, time2; time1= my_timer_init_frequency(mti); /* Repeat once in case there was an interruption. */ time2= my_timer_init_frequency(mti); @@ -775,8 +783,7 @@ void my_timer_init(MY_TIMER_INFO *mti) && mti->microseconds.routine && mti->cycles.routine) { - int i; - ulonglong time1, time2, time3, time4; + ulonglong time3, time4; time1= my_timer_cycles(); time2= my_timer_milliseconds(); time3= time2; /* Avoids a Microsoft/IBM compiler warning */ @@ -801,8 +808,7 @@ void my_timer_init(MY_TIMER_INFO *mti) && mti->microseconds.routine && mti->cycles.routine) { - int i; - ulonglong time1, time2, time3, time4; + ulonglong time3, time4; time1= my_timer_cycles(); time2= my_timer_ticks(); time3= time2; /* Avoids a Microsoft/IBM compiler warning */ diff --git a/mysys/my_redel.c b/mysys/my_redel.c index 976fc5a18c3..9091c74e6b5 100644 --- a/mysys/my_redel.c +++ b/mysys/my_redel.c @@ -32,10 +32,10 @@ struct utimbuf { /* Rename with copy stat form old file - Copy stats from old file to new file, deletes orginal and + Copy stats from old file to new file, deletes original and changes new file name to old file name - if MY_REDEL_MAKE_COPY is given, then the orginal file + if MY_REDEL_MAKE_COPY is given, then the original file is renamed to org_name-'current_time'.BAK */ diff --git a/mysys/my_rnd.c b/mysys/my_rnd.c index ad7bda0b42b..fc38d5586ce 100644 --- a/mysys/my_rnd.c +++ b/mysys/my_rnd.c @@ -11,7 +11,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include "mysys_priv.h" #include <my_rnd.h> diff --git a/mysys/my_safehash.c b/mysys/my_safehash.c index 1417b8ea94e..c34f3c456cd 100644 --- a/mysys/my_safehash.c +++ b/mysys/my_safehash.c @@ -12,7 +12,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /* Handling of multiple key caches diff --git a/mysys/my_safehash.h b/mysys/my_safehash.h index e52fee68b57..3d3aa1e6006 100644 --- a/mysys/my_safehash.h +++ b/mysys/my_safehash.h @@ -12,7 +12,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /* Handling of multiple key caches diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index c851468ce1b..f1ace5dcd77 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -17,7 +17,7 @@ /* Advanced symlink handling. This is used in MyISAM to let users symlinks tables to different disk. - The main idea with these functions is to automaticly create, delete and + The main idea with these functions is to automatically create, delete and rename files and symlinks like they would be one unit. */ diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 04ce0574200..f827fb136d3 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -273,7 +273,7 @@ my_bool my_thread_init(void) my_bool error=0; if (!my_thread_global_init_done) - return 1; /* cannot proceed with unintialized library */ + return 1; /* cannot proceed with uninitialized library */ #ifdef EXTRA_DEBUG_THREADS fprintf(stderr,"my_thread_init(): pthread_self: %p\n", pthread_self()); diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index a8614afef2c..f167ebe1d6e 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -11,7 +11,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /* implements Universal Unique Identifiers (UUIDs), as in diff --git a/mysys/my_windac.c b/mysys/my_windac.c index 51fe22e8f59..9b489759625 100644 --- a/mysys/my_windac.c +++ b/mysys/my_windac.c @@ -33,7 +33,7 @@ static my_bool is_nt() } /* - Auxilary structure to store pointers to the data which we need to keep + Auxiliary structure to store pointers to the data which we need to keep around while SECURITY_ATTRIBUTES is in use. */ diff --git a/mysys/my_winerr.c b/mysys/my_winerr.c index 9577db09eaf..a3f6229b74e 100644 --- a/mysys/my_winerr.c +++ b/mysys/my_winerr.c @@ -119,7 +119,7 @@ static int get_errno_from_oserr(unsigned long oserrno) return EINVAL; } -/* Set errno corresponsing to GetLastError() value */ +/* Set errno corresponding to GetLastError() value */ void my_osmaperr ( unsigned long oserrno) { errno= get_errno_from_oserr(oserrno); diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h index b33e155a718..892e09148ef 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -13,8 +13,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef MYSYS_PRIV_INCLUDED +#define MYSYS_PRIV_INCLUDED + #include <my_global.h> #include <my_sys.h> +#include <my_crypt.h> + +C_MODE_START #ifdef USE_SYSTEM_WRAPPERS #include "system_wrappers.h" @@ -42,16 +48,16 @@ extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock, key_THR_LOCK_lock, key_THR_LOCK_malloc, key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net, key_THR_LOCK_open, key_THR_LOCK_threads, key_LOCK_uuid_generator, - key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap; + key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap, key_LOCK_timer; -extern PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond, +extern PSI_cond_key key_COND_alarm, key_COND_timer, key_IO_CACHE_SHARE_cond, key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend, key_THR_COND_threads; #ifdef USE_ALARM_THREAD extern PSI_thread_key key_thread_alarm; #endif /* USE_ALARM_THREAD */ - +extern PSI_thread_key key_thread_timer; extern PSI_rwlock_key key_SAFEHASH_mutex; #endif /* HAVE_PSI_INTERFACE */ @@ -71,6 +77,16 @@ extern PSI_file_key key_file_proc_meminfo; extern PSI_file_key key_file_charset, key_file_cnf; #endif /* HAVE_PSI_INTERFACE */ +typedef struct { + ulonglong counter; + uint block_length, last_block_length; + uchar key[MY_AES_BLOCK_SIZE]; + ulonglong inbuf_counter; +} IO_CACHE_CRYPT; + +extern int (*_my_b_encr_read)(IO_CACHE *info,uchar *Buffer,size_t Count); +extern int (*_my_b_encr_write)(IO_CACHE *info,const uchar *Buffer,size_t Count); + #ifdef SAFEMALLOC void *sf_malloc(size_t size, myf my_flags); void *sf_realloc(void *ptr, size_t size, myf my_flags); @@ -157,3 +173,7 @@ extern File my_win_dup(File fd); extern File my_win_sopen(const char *path, int oflag, int shflag, int perm); extern File my_open_osfhandle(HANDLE handle, int oflag); #endif + +C_MODE_END + +#endif diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index 6e373e98972..6d853a8db25 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -88,8 +88,8 @@ qsort2_cmp get_ptr_compare (size_t size) static int ptr_compare(size_t *compare_length, uchar **a, uchar **b) { - reg3 int length= *compare_length; - reg1 uchar *first,*last; + size_t length= *compare_length; + uchar *first,*last; DBUG_ASSERT(length > 0); first= *a; last= *b; @@ -104,8 +104,8 @@ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b) static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b) { - reg3 int length= *compare_length; - reg1 uchar *first,*last; + size_t length= *compare_length; + uchar *first,*last; first= *a; last= *b; loop: @@ -125,8 +125,8 @@ static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b) static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b) { - reg3 int length= *compare_length-1; - reg1 uchar *first,*last; + size_t length= *compare_length-1; + uchar *first,*last; first= *a+1; last= *b+1; cmp(-1); @@ -146,8 +146,8 @@ static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b) static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b) { - reg3 int length= *compare_length-2; - reg1 uchar *first,*last; + size_t length= *compare_length-2; + uchar *first,*last; first= *a +2 ; last= *b +2; cmp(-2); @@ -168,8 +168,8 @@ static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b) static int ptr_compare_3(size_t *compare_length,uchar **a, uchar **b) { - reg3 int length= *compare_length-3; - reg1 uchar *first,*last; + size_t length= *compare_length-3; + uchar *first,*last; first= *a +3 ; last= *b +3; cmp(-3); diff --git a/mysys/queues.c b/mysys/queues.c index 418163d7c58..5d09ce2063f 100644 --- a/mysys/queues.c +++ b/mysys/queues.c @@ -27,7 +27,7 @@ This code originates from the Unireg project. Code for generell handling of priority Queues. - Implemention of queues from "Algoritms in C" by Robert Sedgewick. + Implementation of queues from "Algorithms in C" by Robert Sedgewick. The queue can optionally store the position in queue in the element that is in the queue. This allows one to remove any element from the queue diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 2b83c5d5479..0d4d5fce803 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -336,12 +336,11 @@ inline uint32* find_prev_pc(uint32* pc, uchar** fp) void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack) { - uchar** fp; + uchar** UNINIT_VAR(fp); uint frame_count = 0, sigreturn_frame_count; #if defined(__alpha__) && defined(__GNUC__) uint32* pc; #endif - LINT_INIT(fp); #ifdef __i386__ diff --git a/mysys/test_thr_mutex.c b/mysys/test_thr_mutex.c index 0bd14a0d31b..fa5b6f74ba3 100644 --- a/mysys/test_thr_mutex.c +++ b/mysys/test_thr_mutex.c @@ -11,7 +11,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /* Testing of deadlock detector */ diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 9d917d3dd59..61ef3657161 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -273,7 +273,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) /* Come here when some alarm in queue is due. Mark all alarms with are finnished in list. - Shedule alarms to be sent again after 1-10 sec (many alarms at once) + Schedule alarms to be sent again after 1-10 sec (many alarms at once) If alarm_aborted is set then all alarms are given and resent every second. */ @@ -425,7 +425,7 @@ void end_thr_alarm(my_bool free_structures) if (alarm_aborted != 1) /* If memory not freed */ { mysql_mutex_lock(&LOCK_alarm); - DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); + DBUG_PRINT("info",("Rescheduling %d waiting alarms",alarm_queue.elements)); alarm_aborted= -1; /* mark aborted */ if (alarm_queue.elements || (alarm_thread_running && free_structures)) { diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 8dce58dd58a..45376f7c5fc 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -95,6 +95,24 @@ my_bool thr_lock_inited=0; ulong locks_immediate = 0L, locks_waited = 0L; enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE; +#ifdef WITH_WSREP +static wsrep_thd_is_brute_force_fun wsrep_thd_is_brute_force= NULL; +static wsrep_abort_thd_fun wsrep_abort_thd= NULL; +static my_bool wsrep_debug; +static my_bool wsrep_convert_LOCK_to_trx; +static wsrep_on_fun wsrep_on = NULL; + +void wsrep_thr_lock_init( + wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun, + my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun +) { + wsrep_thd_is_brute_force = bf_fun; + wsrep_abort_thd = abort_fun; + wsrep_debug = debug; + wsrep_convert_LOCK_to_trx= convert_LOCK_to_trx; + wsrep_on = on_fun; +} +#endif /* The following constants are only for debug output */ #define MAX_THREADS 1000 #define MAX_LOCKS 1000 @@ -327,15 +345,14 @@ static void check_locks(THR_LOCK *lock, const char *where, "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type); DBUG_PRINT("warning", ("Warning at '%s': Write lock %d waiting while no exclusive read locks",where,(int) lock->write_wait.data->type)); } - } + } } else { /* We have at least one write lock */ if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT) { - THR_LOCK_DATA *data; - uint count= 0; + count= 0; for (data=lock->write.data->next; data && count < MAX_LOCKS; data=data->next) @@ -368,7 +385,6 @@ static void check_locks(THR_LOCK *lock, const char *where, } if (lock->read.data) { - THR_LOCK_DATA *data; for (data=lock->read.data ; data ; data=data->next) { if (!thr_lock_owner_equal(lock->write.data->owner, @@ -512,8 +528,8 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, One can use this to signal when a thread is going to wait for a lock. See debug_sync.cc. - Beware of waiting for a signal here. The lock has aquired its mutex. - While waiting on a signal here, the locking thread could not aquire + Beware of waiting for a signal here. The lock has acquired its mutex. + While waiting on a signal here, the locking thread could not acquire the mutex to release the lock. One could lock up the table completely. @@ -646,6 +662,92 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, DBUG_RETURN(result); } +#ifdef WITH_WSREP +/* + * If brute force applier would need to wait for a thr lock, + * it needs to make sure that it will get the lock without (too much) + * delay. + * We identify here the owners of blocking locks and ask them to + * abort. We then put our lock request in the first place in the + * wait queue. When lock holders abort (one by one) the lock release + * algorithm should grant the lock to us. We rely on this and proceed + * to wait_for_locks(). + * wsrep_break_locks() should be called in all the cases, where lock + * wait would happen. + * + * TODO: current implementation might not cover all possible lock wait + * situations. This needs an review still. + * TODO: lock release, might favor some other lock (instead our bf). + * This needs an condition to check for bf locks first. + * TODO: we still have a debug fprintf, this should be removed + */ +static my_bool +wsrep_break_lock( + THR_LOCK_DATA *data, struct st_lock_list *lock_queue1, + struct st_lock_list *wait_queue) +{ + if (wsrep_on && wsrep_on(data->owner->mysql_thd) && + wsrep_thd_is_brute_force && + wsrep_thd_is_brute_force(data->owner->mysql_thd, TRUE)) + { + THR_LOCK_DATA *holder; + + /* if locking session conversion to transaction has been enabled, + we know that this conflicting lock must be read lock and furthermore, + lock holder is read-only. It is safe to wait for him. + */ +#ifdef TODO_WHEN_LOCK_TABLES_IS_A_TRANSACTION + if (wsrep_convert_LOCK_to_trx && + (THD*)(data->owner->mysql_thd)->in_lock_tables) + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n"); + return FALSE; + } +#endif + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n"); + + /* aborting lock holder(s) here */ + for (holder=(lock_queue1) ? lock_queue1->data : NULL; + holder; + holder=holder->next) + { + if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE)) + { + wsrep_abort_thd(data->owner->mysql_thd, + holder->owner->mysql_thd, FALSE); + } + else + { + if (wsrep_debug) + fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n"); + return FALSE; + } + } + + /* Add our lock to the head of the wait queue */ + if (*(wait_queue->last)==wait_queue->data) + { + wait_queue->last=&data->next; + assert(wait_queue->data==0); + } + else + { + assert(wait_queue->data!=0); + wait_queue->data->prev=&data->next; + } + data->next=wait_queue->data; + data->prev=&wait_queue->data; + wait_queue->data=data; + data->cond=get_cond(); + + statistic_increment(locks_immediate,&THR_LOCK_lock); + return TRUE; + } + return FALSE; +} +#endif static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) @@ -654,6 +756,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; enum thr_lock_type lock_type= data->type; +#ifdef WITH_WSREP + my_bool wsrep_lock_inserted= FALSE; +#endif MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */ DBUG_ENTER("thr_lock"); @@ -694,8 +799,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) \ = READ - + = Request can be satisified. - - = Request cannot be satisified. + + = Request can be satisfied. + - = Request cannot be satisfied. READ_NO_INSERT and WRITE_ALLOW_WRITE should in principle be incompatible. However this will cause starvation of @@ -750,6 +855,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) lock but a high priority write waiting in the write_wait queue. In the latter case we should yield the lock to the writer. */ +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, &lock->read_wait)) + { + wsrep_lock_inserted= TRUE; + } +#endif + wait_queue= &lock->read_wait; } else /* Request for WRITE lock */ @@ -894,9 +1006,20 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout) DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d", lock->read.data->owner->thread_id, data->type)); } +#ifdef WITH_WSREP + if (wsrep_break_lock(data, &lock->write, &lock->write_wait)) + { + wsrep_lock_inserted= TRUE; + } +#endif + wait_queue= &lock->write_wait; } /* Can't get lock yet; Wait for it */ +#ifdef WITH_WSREP + if (wsrep_lock_inserted && wsrep_on(data->owner->mysql_thd)) + DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout)); +#endif result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout); MYSQL_END_TABLE_LOCK_WAIT(locker); DBUG_RETURN(result); @@ -1134,7 +1257,7 @@ end: /* Get all locks in a specific order to avoid dead-locks - Sort acording to lock position and put write_locks before read_locks if + Sort according to lock position and put write_locks before read_locks if lock on same lock. Locks on MERGE tables has lower priority than other locks of the same type. See comment for lock_priority. */ diff --git a/mysys/thr_timer.c b/mysys/thr_timer.c new file mode 100644 index 00000000000..b8726617f44 --- /dev/null +++ b/mysys/thr_timer.c @@ -0,0 +1,570 @@ +/* + Copyright (c) 2012 Monty Program 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; version 2 or later of the License. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* + Implementation if OS independent timers. + This is done based on pthread primitives, especially pthread_cond_timedwait() +*/ + +#include "mysys_priv.h" +#include "thr_timer.h" +#include <m_string.h> +#include <queues.h> +#ifdef HAVE_TIMER_CREATE +#include <sys/syscall.h> +#endif + +struct timespec next_timer_expire_time; + +static my_bool thr_timer_inited= 0; +static mysql_mutex_t LOCK_timer; +static mysql_cond_t COND_timer; +static QUEUE timer_queue; +pthread_t timer_thread; + +#define set_max_time(abs_time) \ + { (abs_time)->MY_tv_sec= INT_MAX32; (abs_time)->MY_tv_nsec= 0; } + + +static void *timer_handler(void *arg __attribute__((unused))); + +/* + Compare two timespecs +*/ + +static int compare_timespec(void *not_used __attribute__((unused)), + uchar *a_ptr, uchar *b_ptr) +{ + return cmp_timespec((*(struct timespec*) a_ptr), + (*(struct timespec*) b_ptr)); +} + + +/** + Initialize timer variables and create timer thread + + @param alloc_timers Init allocation of timers. Will be autoextended + if needed + @return 0 ok + @return 1 error; Can't create thread +*/ + +static thr_timer_t max_timer_data; + +my_bool init_thr_timer(uint alloc_timers) +{ + pthread_attr_t thr_attr; + my_bool res= 0; + DBUG_ENTER("init_thr_timer"); + + init_queue(&timer_queue, alloc_timers+2, offsetof(thr_timer_t,expire_time), + 0, compare_timespec, NullS, + offsetof(thr_timer_t, index_in_queue)+1, 1); + mysql_mutex_init(key_LOCK_timer, &LOCK_timer, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_timer, &COND_timer, NULL); + + /* Set dummy element with max time into the queue to simplify usage */ + bzero(&max_timer_data, sizeof(max_timer_data)); + set_max_time(&max_timer_data.expire_time); + queue_insert(&timer_queue, (uchar*) &max_timer_data); + next_timer_expire_time= max_timer_data.expire_time; + + /* Create a thread to handle timers */ + pthread_attr_init(&thr_attr); + pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); + pthread_attr_setstacksize(&thr_attr,8196); + thr_timer_inited= 1; + if (mysql_thread_create(key_thread_timer, &timer_thread, &thr_attr, + timer_handler, NULL)) + { + thr_timer_inited= 0; + res= 1; + mysql_mutex_destroy(&LOCK_timer); + mysql_cond_destroy(&COND_timer); + delete_queue(&timer_queue); + } + pthread_attr_destroy(&thr_attr); + + DBUG_RETURN(res); +} + + +void end_thr_timer(void) +{ + DBUG_ENTER("end_thr_timer"); + + if (!thr_timer_inited) + DBUG_VOID_RETURN; + + mysql_mutex_lock(&LOCK_timer); + thr_timer_inited= 0; /* Signal abort */ + mysql_cond_signal(&COND_timer); + mysql_mutex_unlock(&LOCK_timer); + pthread_join(timer_thread, NULL); + + mysql_mutex_destroy(&LOCK_timer); + mysql_cond_destroy(&COND_timer); + delete_queue(&timer_queue); + DBUG_VOID_RETURN; +} + + +/* + Initialize a timer object + + @param timer_data Timer structure + @param function Function to be called when getting timeout + @param argument Argument for function +*/ + +void thr_timer_init(thr_timer_t *timer_data, void(*function)(void*), + void *arg) +{ + DBUG_ENTER("thr_timer_init"); + bzero(timer_data, sizeof(*timer_data)); + timer_data->func= function; + timer_data->func_arg= arg; + timer_data->expired= 1; /* Not active */ + DBUG_VOID_RETURN; +} + + +/* + Request timer after X milliseconds + + SYNOPSIS + thr_timer() + timer_data Pointer to timer structure + micro_seconds; Number of microseconds until timer + + RETURN VALUES + 0 ok + 1 If no more timers are allowed (aborted by process) + + Stores in first argument a pointer to a non-zero int which is set to 0 + when the timer has been given +*/ + +my_bool thr_timer_settime(thr_timer_t *timer_data, ulonglong micro_seconds) +{ + int reschedule; + DBUG_ENTER("thr_timer_settime"); + DBUG_PRINT("enter",("thread: %s micro_seconds: %llu",my_thread_name(), + micro_seconds)); + + DBUG_ASSERT(timer_data->expired == 1); + + set_timespec_nsec(timer_data->expire_time, micro_seconds*1000); + timer_data->expired= 0; + + mysql_mutex_lock(&LOCK_timer); /* Lock from threads & timers */ + if (queue_insert_safe(&timer_queue,(uchar*) timer_data)) + { + DBUG_PRINT("info", ("timer queue full")); + fprintf(stderr,"Warning: thr_timer queue is full\n"); + timer_data->expired= 1; + mysql_mutex_unlock(&LOCK_timer); + DBUG_RETURN(1); + } + + /* Reschedule timer if the current one has more time left than new one */ + reschedule= cmp_timespec(next_timer_expire_time, timer_data->expire_time); + mysql_mutex_unlock(&LOCK_timer); + if (reschedule > 0) + { +#if defined(MAIN) + printf("reschedule\n"); fflush(stdout); +#endif + DBUG_PRINT("info", ("reschedule")); + mysql_cond_signal(&COND_timer); + } + + DBUG_RETURN(0); +} + + +/* + Remove timer from list of timers + + notes: Timer will be marked as expired +*/ + +void thr_timer_end(thr_timer_t *timer_data) +{ + DBUG_ENTER("thr_timer_end"); + + mysql_mutex_lock(&LOCK_timer); + if (!timer_data->expired) + { + DBUG_ASSERT(timer_data->index_in_queue != 0); + DBUG_ASSERT(queue_element(&timer_queue, timer_data->index_in_queue) == + (uchar*) timer_data); + queue_remove(&timer_queue, timer_data->index_in_queue); + /* Mark as expired for asserts to work */ + timer_data->expired= 1; + } + mysql_mutex_unlock(&LOCK_timer); + DBUG_VOID_RETURN; +} + + +/* + Come here when some timer in queue is due. +*/ + +static sig_handler process_timers(struct timespec *now) +{ + thr_timer_t *timer_data; + DBUG_ENTER("process_timers"); + DBUG_PRINT("info",("active timers: %d", timer_queue.elements - 1)); + +#if defined(MAIN) + printf("process_timer\n"); fflush(stdout); +#endif + + /* We can safely remove the first one as it has already expired */ + for (;;) + { + void (*function)(void*); + void *func_arg; + + timer_data= (thr_timer_t*) queue_top(&timer_queue); + function= timer_data->func; + func_arg= timer_data->func_arg; + timer_data->expired= 1; /* Mark expired */ + /* + We remove timer before calling timer function to allow thread to + delete it's timer data any time. + */ + queue_remove_top(&timer_queue); /* Remove timer */ + (*function)(func_arg); /* Inform thread of timeout */ + + /* Check if next one has also expired */ + timer_data= (thr_timer_t*) queue_top(&timer_queue); + if (cmp_timespec(timer_data->expire_time, (*now)) > 0) + break; /* All data processed */ + } + DBUG_VOID_RETURN; +} + + +/* + set up a timer thread to handle timeouts + This will be killed when thr_timer_inited is set to false. +*/ + +static void *timer_handler(void *arg __attribute__((unused))) +{ + my_thread_init(); + + mysql_mutex_lock(&LOCK_timer); + while (likely(thr_timer_inited)) + { + int error; + struct timespec *top_time; + struct timespec now, abstime; + + set_timespec(now, 0); + + top_time= &(((thr_timer_t*) queue_top(&timer_queue))->expire_time); + + if (cmp_timespec((*top_time), now) <= 0) + { + process_timers(&now); + top_time= &(((thr_timer_t*) queue_top(&timer_queue))->expire_time); + } + + abstime= *top_time; + next_timer_expire_time= *top_time; + if ((error= mysql_cond_timedwait(&COND_timer, &LOCK_timer, &abstime)) && + error != ETIME && error != ETIMEDOUT) + { +#ifdef MAIN + printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n", + error,errno); +#endif + } + } + mysql_mutex_unlock(&LOCK_timer); + my_thread_end(); + pthread_exit(0); + return 0; /* Impossible */ +} + + +/**************************************************************************** + Testing of thr_timer (when compiled with -DMAIN) +***************************************************************************/ + +#ifdef MAIN + +static mysql_cond_t COND_thread_count; +static mysql_mutex_t LOCK_thread_count; +static uint thread_count, benchmark_runs, test_to_run= 1; + +static void send_signal(void *arg) +{ + struct st_my_thread_var *current_my_thread_var= arg; +#if defined(MAIN) + printf("sending signal\n"); fflush(stdout); +#endif + mysql_mutex_lock(¤t_my_thread_var->mutex); + mysql_cond_signal(¤t_my_thread_var->suspend); + mysql_mutex_unlock(¤t_my_thread_var->mutex); +} + + +static void run_thread_test(int param) +{ + int i,wait_time,retry; + my_hrtime_t start_time; + thr_timer_t timer_data; + struct st_my_thread_var *current_my_thread_var; + DBUG_ENTER("run_thread_test"); + + current_my_thread_var= my_thread_var; + thr_timer_init(&timer_data, send_signal, current_my_thread_var); + + for (i=1 ; i <= 10 ; i++) + { + wait_time=param ? 11-i : i; + start_time= my_hrtime(); + + mysql_mutex_lock(¤t_my_thread_var->mutex); + if (thr_timer_settime(&timer_data, wait_time * 1000000)) + { + printf("Thread: %s timers aborted\n",my_thread_name()); + break; + } + if (wait_time == 3) + { + printf("Thread: %s Simulation of no timer needed\n",my_thread_name()); + fflush(stdout); + } + else + { + for (retry=0 ; !timer_data.expired && retry < 10 ; retry++) + { + printf("Thread: %s Waiting %d sec\n",my_thread_name(),wait_time); + mysql_cond_wait(¤t_my_thread_var->suspend, + ¤t_my_thread_var->mutex); + + } + if (!timer_data.expired) + { + printf("Thread: %s didn't get an timer. Aborting!\n", + my_thread_name()); + break; + } + } + mysql_mutex_unlock(¤t_my_thread_var->mutex); + printf("Thread: %s Slept for %g (%d) sec\n",my_thread_name(), + (int) (my_hrtime().val-start_time.val)/1000000.0, wait_time); + fflush(stdout); + thr_timer_end(&timer_data); + fflush(stdout); + } + DBUG_VOID_RETURN; +} + + +static void run_thread_benchmark(int param) +{ + int i; + struct st_my_thread_var *current_my_thread_var; + thr_timer_t timer_data; + DBUG_ENTER("run_thread_benchmark"); + + current_my_thread_var= my_thread_var; + thr_timer_init(&timer_data, send_signal, current_my_thread_var); + + for (i=1 ; i <= param ; i++) + { + if (thr_timer_settime(&timer_data, 1000000)) + { + printf("Thread: %s timers aborted\n",my_thread_name()); + break; + } + thr_timer_end(&timer_data); + } + DBUG_VOID_RETURN; +} + + +#ifdef HAVE_TIMER_CREATE + +/* Test for benchmarking posix timers against thr_timer */ + +#ifndef sigev_notify_thread_id +#define sigev_notify_thread_id _sigev_un._tid +#endif + +static void run_timer_benchmark(int param) +{ + int i; + timer_t timerid; + struct sigevent sigev; + pid_t thread_id= (pid_t) syscall(SYS_gettid); + DBUG_ENTER("run_timer_benchmark"); + + /* Setup a signal that will never be signaled */ + sigev.sigev_value.sival_ptr= 0; + sigev.sigev_signo= SIGRTMIN; /* First free signal */ + sigev.sigev_notify= SIGEV_SIGNAL | SIGEV_THREAD_ID; + sigev.sigev_notify_thread_id= thread_id; + + if (timer_create(CLOCK_MONOTONIC, &sigev, &timerid)) + { + printf("Could not create timer\n"); + exit(1); + } + + for (i=1 ; i <= param ; i++) + { + struct itimerspec abstime; + abstime.it_interval.tv_sec= 0; + abstime.it_interval.tv_nsec= 0; + abstime.it_value.tv_sec= 1; + abstime.it_value.tv_nsec= 0; + + if (timer_settime(timerid, 0, &abstime, NULL)) + { + printf("Thread: %s timers aborted\n",my_thread_name()); + break; + } + abstime.it_interval.tv_sec= 0; + abstime.it_interval.tv_nsec= 0; + abstime.it_value.tv_sec= 0; + abstime.it_value.tv_nsec= 0; + timer_settime(timerid, 0, &abstime, NULL); + } + timer_delete(timerid); + DBUG_VOID_RETURN; +} +#endif /* HAVE_TIMER_CREATE */ + + +static void *start_thread(void *arg) +{ + my_thread_init(); + printf("Thread %d (%s) started\n",*((int*) arg),my_thread_name()); + fflush(stdout); + + switch (test_to_run) { + case 1: + run_thread_test(*((int*) arg)); + break; + case 2: + run_thread_benchmark(benchmark_runs); + break; + case 3: +#ifdef HAVE_TIMER_CREATE + run_timer_benchmark(benchmark_runs); +#endif + break; + } + free((uchar*) arg); + mysql_mutex_lock(&LOCK_thread_count); + thread_count--; + mysql_cond_signal(&COND_thread_count); /* Tell main we are ready */ + mysql_mutex_unlock(&LOCK_thread_count); + my_thread_end(); + return 0; +} + + +/* Start a lot of threads that will run with timers */ + +static void run_test() +{ + pthread_t tid; + pthread_attr_t thr_attr; + int i,*param,error; + DBUG_ENTER("run_test"); + + if (init_thr_timer(5)) + { + printf("Can't initialize timers\n"); + exit(1); + } + + mysql_mutex_init(0, &LOCK_thread_count, MY_MUTEX_INIT_FAST); + mysql_cond_init(0, &COND_thread_count, NULL); + + thr_setconcurrency(3); + pthread_attr_init(&thr_attr); + pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); + printf("Main thread: %s\n",my_thread_name()); + for (i=0 ; i < 2 ; i++) + { + param=(int*) malloc(sizeof(int)); + *param= i; + mysql_mutex_lock(&LOCK_thread_count); + if ((error= mysql_thread_create(0, + &tid, &thr_attr, start_thread, + (void*) param))) + { + printf("Can't create thread %d, error: %d\n",i,error); + exit(1); + } + thread_count++; + mysql_mutex_unlock(&LOCK_thread_count); + } + + pthread_attr_destroy(&thr_attr); + mysql_mutex_lock(&LOCK_thread_count); + while (thread_count) + { + mysql_cond_wait(&COND_thread_count, &LOCK_thread_count); + } + mysql_mutex_unlock(&LOCK_thread_count); + DBUG_ASSERT(timer_queue.elements == 1); + end_thr_timer(); + printf("Test succeeded\n"); + DBUG_VOID_RETURN; +} + + +int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) +{ + MY_INIT(argv[0]); + + if (argc > 1 && argv[1][0] == '-') + { + switch (argv[1][1]) { + case '#': + test_to_run= 1; + DBUG_PUSH(argv[1]+2); + break; + case 'b': + test_to_run= 2; + benchmark_runs= atoi(argv[1]+2); + break; + case 't': + test_to_run= 3; + benchmark_runs= atoi(argv[1]+2); + break; + } + } + if (!benchmark_runs) + benchmark_runs= 1000000; + + run_test(); + my_end(1); + return 0; +} + +#endif /* MAIN */ diff --git a/mysys/tree.c b/mysys/tree.c index ab810c64c67..5eaeb30037d 100644 --- a/mysys/tree.c +++ b/mysys/tree.c @@ -30,8 +30,8 @@ 3) if key_size is given to init_tree then each node will continue the key and calls to insert_key may increase length of key. if key_size > sizeof(pointer) and key_size is a multiple of 8 (double - allign) then key will be put on a 8 alligned adress. Else - the key will be on adress (element+1). This is transparent for user + align) then key will be put on a 8 aligned address. Else + the key will be on address (element+1). This is transparent for user compare and search functions uses a pointer to given key-argument. - If you use a free function for tree-elements and you are freeing diff --git a/mysys/typelib.c b/mysys/typelib.c index 75744a65ec8..9ca0847570f 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -45,18 +45,6 @@ int find_type_with_warning(const char *x, TYPELIB *typelib, const char *option) } -int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) -{ - int res; - if ((res= find_type_with_warning(x, typelib, option)) <= 0) - { - sf_leaking_memory= 1; /* no memory leak reports here */ - exit(1); - } - return res; -} - - /** Search after a string in a list of strings. Endspace in x is not compared. @@ -182,7 +170,7 @@ const char *get_type(TYPELIB *typelib, uint nr) /** - Create an integer value to represent the supplied comma-seperated + Create an integer value to represent the supplied comma-separated string where each string in the TYPELIB denotes a bit position. @param x string to decompose diff --git a/mysys/waiting_threads.c b/mysys/waiting_threads.c index f2b1bbb5993..2549bd8a587 100644 --- a/mysys/waiting_threads.c +++ b/mysys/waiting_threads.c @@ -12,7 +12,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ /** @file @@ -136,7 +136,7 @@ Status ^^^^^^ - We calculate the number of successfull waits (WT_OK returned from + We calculate the number of successful waits (WT_OK returned from wt_thd_cond_timedwait()), a number of timeouts, a deadlock cycle length distribution - number of deadlocks with every length from 1 to WT_CYCLE_STATS, and a wait time distribution - number @@ -192,19 +192,12 @@ uint32 wt_wait_stats[WT_WAIT_STATS+1]; uint32 wt_cycle_stats[2][WT_CYCLE_STATS+1]; uint32 wt_success_stats; -static my_atomic_rwlock_t cycle_stats_lock, wait_stats_lock, success_stats_lock; - #ifdef HAVE_PSI_INTERFACE extern PSI_cond_key key_WT_RESOURCE_cond; #endif #ifdef SAFE_STATISTICS -#define incr(VAR, LOCK) \ - do { \ - my_atomic_rwlock_wrlock(&(LOCK)); \ - my_atomic_add32(&(VAR), 1); \ - my_atomic_rwlock_wrunlock(&(LOCK)); \ - } while(0) +#define incr(VAR, LOCK) do { my_atomic_add32(&(VAR), 1); } while(0) #else #define incr(VAR,LOCK) do { (VAR)++; } while(0) #endif @@ -260,11 +253,7 @@ struct st_wt_resource { #ifndef DBUG_OFF mysql_mutex_t *cond_mutex; /* a mutex for the 'cond' below */ #endif - /* - before the 'lock' all elements are mutable, after (and including) - - immutable in the sense that lf_hash_insert() won't memcpy() over them. - See wt_init(). - */ + #ifdef WT_RWLOCKS_USE_MUTEXES /* we need a special rwlock-like 'lock' to allow readers bypass @@ -396,10 +385,10 @@ static LF_HASH reshash; It's called from lf_hash and takes a pointer to an LF_SLIST instance. WT_RESOURCE is located at arg+sizeof(LF_SLIST) */ -static void wt_resource_init(uchar *arg) +static void wt_resource_create(uchar *arg) { WT_RESOURCE *rc= (WT_RESOURCE*)(arg+LF_HASH_OVERHEAD); - DBUG_ENTER("wt_resource_init"); + DBUG_ENTER("wt_resource_create"); bzero(rc, sizeof(*rc)); rc_rwlock_init(rc); @@ -426,25 +415,37 @@ static void wt_resource_destroy(uchar *arg) DBUG_VOID_RETURN; } +/** + WT_RESOURCE initializer + + It's called from lf_hash when an element is inserted. +*/ +static void wt_resource_init(LF_HASH *hash __attribute__((unused)), + WT_RESOURCE *rc, WT_RESOURCE_ID *id) +{ + DBUG_ENTER("wt_resource_init"); + rc->id= *id; + rc->waiter_count= 0; + rc->state= ACTIVE; +#ifndef DBUG_OFF + rc->cond_mutex= 0; +#endif + DBUG_VOID_RETURN; +} + static int wt_init_done; void wt_init() { DBUG_ENTER("wt_init"); - DBUG_ASSERT(reshash.alloc.constructor != wt_resource_init); + DBUG_ASSERT(reshash.alloc.constructor != wt_resource_create); lf_hash_init(&reshash, sizeof(WT_RESOURCE), LF_HASH_UNIQUE, 0, sizeof_WT_RESOURCE_ID, 0, 0); - reshash.alloc.constructor= wt_resource_init; + reshash.alloc.constructor= wt_resource_create; reshash.alloc.destructor= wt_resource_destroy; - /* - Note a trick: we initialize the hash with the real element size, - but fix it later to a shortened element size. This way - the allocator will allocate elements correctly, but - lf_hash_insert() will only overwrite part of the element with memcpy(). - lock, condition, and dynamic array will be intact. - */ - reshash.element_size= offsetof(WT_RESOURCE, lock); + reshash.initializer= (lf_hash_initializer) wt_resource_init; + bzero(wt_wait_stats, sizeof(wt_wait_stats)); bzero(wt_cycle_stats, sizeof(wt_cycle_stats)); wt_success_stats= 0; @@ -458,9 +459,6 @@ void wt_init() DBUG_ASSERT(i == 0 || wt_wait_table[i-1] != wt_wait_table[i]); } } - my_atomic_rwlock_init(&cycle_stats_lock); - my_atomic_rwlock_init(&success_stats_lock); - my_atomic_rwlock_init(&wait_stats_lock); wt_init_done= 1; DBUG_VOID_RETURN; } @@ -473,9 +471,6 @@ void wt_end() DBUG_ASSERT(reshash.count == 0); lf_hash_destroy(&reshash); - my_atomic_rwlock_destroy(&cycle_stats_lock); - my_atomic_rwlock_destroy(&success_stats_lock); - my_atomic_rwlock_destroy(&wait_stats_lock); reshash.alloc.constructor= NULL; wt_init_done= 0; DBUG_VOID_RETURN; @@ -943,14 +938,9 @@ int wt_thd_will_wait_for(WT_THD *thd, WT_THD *blocker, retry: while ((rc= lf_hash_search(&reshash, thd->pins, key, keylen)) == 0) { - WT_RESOURCE tmp; - DBUG_PRINT("wt", ("failed to find rc in hash, inserting")); - bzero(&tmp, sizeof(tmp)); - tmp.id= *resid; - tmp.state= ACTIVE; - if (lf_hash_insert(&reshash, thd->pins, &tmp) == -1) /* if OOM */ + if (lf_hash_insert(&reshash, thd->pins, resid) == -1) /* if OOM */ DBUG_RETURN(WT_DEADLOCK); /* Two cases: either lf_hash_insert() failed - because another thread diff --git a/mysys/wqueue.c b/mysys/wqueue.c index 2fcced14f77..1dafc03b935 100644 --- a/mysys/wqueue.c +++ b/mysys/wqueue.c @@ -13,7 +13,7 @@ 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 */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ #include <wqueue.h> @@ -211,7 +211,7 @@ void wqueue_release_one_locktype_from_queue(WQUEUE *wqueue) /* Add thread and wait - SYNOPSYS + SYNOPSIS wqueue_add_and_wait() wqueue queue to add to thread thread which is waiting |