summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
Diffstat (limited to 'mysys')
-rw-r--r--mysys/CMakeLists.txt8
-rw-r--r--mysys/array.c41
-rw-r--r--mysys/hash.c9
-rw-r--r--mysys/lf_alloc-pin.c42
-rw-r--r--mysys/lf_dynarray.c12
-rw-r--r--mysys/lf_hash.c209
-rw-r--r--mysys/mf_cache.c18
-rw-r--r--mysys/my_alloc.c15
-rw-r--r--mysys/my_compress.c125
-rw-r--r--mysys/my_getopt.c93
-rw-r--r--mysys/my_init.c18
-rw-r--r--mysys/mysys_priv.h6
-rw-r--r--mysys/ptr_cmp.c20
-rw-r--r--mysys/thr_lock.c125
-rw-r--r--mysys/thr_timer.c589
-rw-r--r--mysys/waiting_threads.c15
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(&current_my_thread_var->mutex);
+ mysql_cond_signal(&current_my_thread_var->suspend);
+ mysql_mutex_unlock(&current_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(&current_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(&current_my_thread_var->suspend,
+ &current_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(&current_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;