diff options
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/CMakeLists.txt | 8 | ||||
-rw-r--r-- | mysys/array.c | 41 | ||||
-rw-r--r-- | mysys/hash.c | 9 | ||||
-rw-r--r-- | mysys/lf_alloc-pin.c | 42 | ||||
-rw-r--r-- | mysys/lf_dynarray.c | 12 | ||||
-rw-r--r-- | mysys/lf_hash.c | 209 | ||||
-rw-r--r-- | mysys/mf_cache.c | 18 | ||||
-rw-r--r-- | mysys/my_alloc.c | 15 | ||||
-rw-r--r-- | mysys/my_compress.c | 125 | ||||
-rw-r--r-- | mysys/my_getopt.c | 93 | ||||
-rw-r--r-- | mysys/my_init.c | 18 | ||||
-rw-r--r-- | mysys/mysys_priv.h | 6 | ||||
-rw-r--r-- | mysys/ptr_cmp.c | 20 | ||||
-rw-r--r-- | mysys/thr_lock.c | 125 | ||||
-rw-r--r-- | mysys/thr_timer.c | 589 | ||||
-rw-r--r-- | mysys/waiting_threads.c | 15 |
16 files changed, 1021 insertions, 324 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 4756bbccf2f..d432c22b966 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -33,7 +33,9 @@ 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 @@ -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..35a41f2222c 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 @@ -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/hash.c b/mysys/hash.c index 4ef731cde15..dc03ea9a4dc 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -40,7 +40,7 @@ static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink); static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key, size_t length); -my_hash_value_type my_hash_sort(const CHARSET_INFO *cs, const uchar *key, +my_hash_value_type my_hash_sort(CHARSET_INFO *cs, const uchar *key, size_t length) { ulong nr1= 1, nr2= 4; @@ -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); } diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index b599b455ff5..f8a15829fb1 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -105,7 +105,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. @@ -144,7 +144,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; @@ -171,12 +171,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, @@ -206,7 +206,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; @@ -223,19 +223,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 @@ -265,14 +261,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 { @@ -281,7 +277,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) @@ -308,7 +304,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; @@ -356,7 +352,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; @@ -391,7 +387,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; } @@ -413,7 +409,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 @@ -495,7 +491,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; @@ -504,7 +500,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) { @@ -521,7 +517,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 aa96ca94198..b08cdc2b4c6 100644 --- a/mysys/lf_hash.c +++ b/mysys/lf_hash.c @@ -24,12 +24,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; @@ -57,63 +58,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 lfind(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 { @@ -122,16 +144,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); } } @@ -157,7 +176,7 @@ static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs, for (;;) { if (lfind(head, cs, node->hashnr, node->key, node->keylen, - &cursor, pins) && + &cursor, pins, 0) && (flags & LF_HASH_UNIQUE)) { res= 0; /* duplicate found */ @@ -176,9 +195,9 @@ static LF_SLIST *linsert(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 @@ -208,7 +227,7 @@ static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr, for (;;) { - if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins)) + if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins, 0)) { res= 1; /* not found */ break; @@ -223,7 +242,7 @@ static int ldelete(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 { /* @@ -232,16 +251,16 @@ static int ldelete(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) */ - lfind(head, cs, hashnr, key, keylen, &cursor, pins); + lfind(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; } @@ -263,13 +282,13 @@ static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs, LF_PINS *pins) { CURSOR cursor; - int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins); + int res= lfind(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; } @@ -333,7 +352,7 @@ void lf_hash_init(LF_HASH *hash, uint element_size, uint flags, 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) { @@ -370,15 +389,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); node->key= hash_key(hash, (uchar *)(node+1), &node->keylen); hashnr= calc_hash(hash, node->key, node->keylen); 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))) @@ -386,14 +404,12 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data) node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */ if (linsert(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; } @@ -405,7 +421,6 @@ 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 ldelete() for pin usage notes */ @@ -414,27 +429,21 @@ 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); - 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; + /* hide OOM errors - if we cannot initalize 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 (ldelete(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; } @@ -443,29 +452,71 @@ 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 lsearch() 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 initalize 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= lsearch(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= lfind(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, + calc_hash(hash, (uchar*) key, keylen), + key, keylen); +} + static const uchar *dummy_key= (uchar*)""; /* @@ -479,7 +530,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/mf_cache.c b/mysys/mf_cache.c index 545084ea97f..299e4e5f478 100644 --- a/mysys/mf_cache.c +++ b/mysys/mf_cache.c @@ -61,9 +61,14 @@ 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, @@ -71,8 +76,6 @@ my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix, { DBUG_RETURN(0); } - my_free(cache->dir); - my_free(cache->prefix); DBUG_RETURN(1); } @@ -83,7 +86,8 @@ 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 +118,6 @@ void close_cached_file(IO_CACHE *cache) } #endif } - my_free(cache->dir); - my_free(cache->prefix); } DBUG_VOID_RETURN; } diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index fc30185eb5a..1e687a3dec2 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -56,7 +56,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; @@ -164,7 +165,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)); @@ -188,8 +189,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; @@ -197,7 +198,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", @@ -256,7 +257,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 } @@ -368,7 +369,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_compress.c b/mysys/my_compress.c index 4cd43596031..78d09bb5f36 100644 --- a/mysys/my_compress.c +++ b/mysys/my_compress.c @@ -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_getopt.c b/mysys/my_getopt.c index 2e97417340d..abcfcfc41cc 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -1300,6 +1300,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 @@ -1309,12 +1351,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) @@ -1353,29 +1395,46 @@ 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); + + 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) + { + int 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_init.c b/mysys/my_init.c index 2c06425f6fb..32289dbed7a 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -454,7 +454,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, @@ -474,6 +475,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}, @@ -489,13 +491,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}, @@ -512,12 +515,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; @@ -552,10 +560,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/mysys_priv.h b/mysys/mysys_priv.h index 9c6855bb92f..4ea6d081107 100644 --- a/mysys/mysys_priv.h +++ b/mysys/mysys_priv.h @@ -42,16 +42,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 */ diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index a481b4d961c..d4daf2b1ec5 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; first= *a; last= *b; while (--length) @@ -103,8 +103,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: @@ -124,8 +124,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); @@ -145,8 +145,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); @@ -167,8 +167,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/thr_lock.c b/mysys/thr_lock.c index 1782aecd4df..37dad48396a 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 @@ -646,6 +664,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 +758,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"); @@ -750,6 +857,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 +1008,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); diff --git a/mysys/thr_timer.c b/mysys/thr_timer.c new file mode 100644 index 00000000000..6414ee6f246 --- /dev/null +++ b/mysys/thr_timer.c @@ -0,0 +1,589 @@ +/* + 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 + +enum thread_state +{ + NOT_RUNNING= -1, RUNNING= 0, ABORTING=1 +}; + +static enum thread_state timer_thread_state= NOT_RUNNING; + +volatile my_bool timer_thread_running= 0; +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; + 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_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&thr_attr,8196); + res= mysql_thread_create(key_thread_timer, + &timer_thread, &thr_attr, timer_handler, NULL) != 0; + pthread_attr_destroy(&thr_attr); + + thr_timer_inited= 1; + DBUG_RETURN(res); +} + + +void end_thr_timer(void) +{ + struct timespec abstime; + DBUG_ENTER("end_thr_timer"); + + if (!thr_timer_inited) + DBUG_VOID_RETURN; + + mysql_mutex_lock(&LOCK_timer); + timer_thread_state= ABORTING; /* Signal abort */ + mysql_cond_signal(&COND_timer); + + /* Wait until timer thread dies */ + set_timespec(abstime, 10*1000); /* Wait up to 10 seconds */ + while (timer_thread_state == ABORTING) + { + int error= mysql_cond_timedwait(&COND_timer, &LOCK_timer, &abstime); + if (error == ETIME || error == ETIMEDOUT) + break; /* Don't wait forever */ + } + mysql_mutex_unlock(&LOCK_timer); + if (timer_thread_state == NOT_RUNNING) + { + mysql_mutex_destroy(&LOCK_timer); + mysql_cond_destroy(&COND_timer); + delete_queue(&timer_queue); + thr_timer_inited= 0; + } + 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 timer_thread_state is set to ABORTING. + At end timer_aborted will be set to NOT_RUNNING +*/ + +static void *timer_handler(void *arg __attribute__((unused))) +{ + my_thread_init(); + + timer_thread_state= RUNNING; + + mysql_mutex_lock(&LOCK_timer); + while (likely(timer_thread_state == RUNNING)) + { + 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 + } + } + timer_thread_state= NOT_RUNNING; /* Mark thread ended */ + mysql_cond_signal(&COND_timer); /* signal end_thr_timer() */ + 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/waiting_threads.c b/mysys/waiting_threads.c index 1fe6a0f9a1c..23b4026b8f1 100644 --- a/mysys/waiting_threads.c +++ b/mysys/waiting_threads.c @@ -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 @@ -458,9 +451,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 +463,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; |