summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
Diffstat (limited to 'mysys')
-rw-r--r--mysys/CMakeLists.txt12
-rw-r--r--mysys/array.c41
-rw-r--r--mysys/charset-def.c10
-rw-r--r--mysys/checksum.c4
-rw-r--r--mysys/hash.c7
-rw-r--r--mysys/lf_alloc-pin.c42
-rw-r--r--mysys/lf_dynarray.c12
-rw-r--r--mysys/lf_hash.c239
-rw-r--r--mysys/ma_dyncol.c7
-rw-r--r--mysys/mf_cache.c50
-rw-r--r--mysys/mf_iocache.c427
-rw-r--r--mysys/mf_iocache2.c60
-rw-r--r--mysys/mf_keycache.c2
-rw-r--r--mysys/my_access.c9
-rw-r--r--mysys/my_addr_resolve.c93
-rw-r--r--mysys/my_alloc.c20
-rw-r--r--mysys/my_bitmap.c14
-rw-r--r--mysys/my_compress.c125
-rw-r--r--mysys/my_create.c2
-rw-r--r--mysys/my_default.c11
-rw-r--r--mysys/my_fopen.c11
-rw-r--r--mysys/my_getopt.c175
-rw-r--r--mysys/my_init.c18
-rw-r--r--mysys/my_open.c4
-rw-r--r--mysys/my_rdtsc.c16
-rw-r--r--mysys/mysys_priv.h26
-rw-r--r--mysys/ptr_cmp.c20
-rw-r--r--mysys/stacktrace.c3
-rw-r--r--mysys/thr_lock.c131
-rw-r--r--mysys/thr_timer.c570
-rw-r--r--mysys/waiting_threads.c64
31 files changed, 1551 insertions, 674 deletions
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index 4756bbccf2f..0d404586569 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
@@ -68,8 +70,8 @@ IF(HAVE_MLOCK)
ENDIF()
ADD_CONVENIENCE_LIBRARY(mysys ${MYSYS_SOURCES})
-TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY}
- ${LIBNSL} ${LIBM} ${LIBRT} ${LIBSOCKET} ${LIBEXECINFO})
+TARGET_LINK_LIBRARIES(mysys dbug strings mysys_ssl ${ZLIB_LIBRARY}
+ ${LIBNSL} ${LIBM} ${LIBRT} ${LIBDL} ${LIBSOCKET} ${LIBEXECINFO})
DTRACE_INSTRUMENT(mysys)
IF(HAVE_BFD_H)
@@ -89,6 +91,10 @@ ADD_EXECUTABLE(thr_lock thr_lock.c)
TARGET_LINK_LIBRARIES(thr_lock mysys)
SET_TARGET_PROPERTIES(thr_lock PROPERTIES COMPILE_FLAGS "-DMAIN")
+ADD_EXECUTABLE(thr_timer thr_timer.c)
+TARGET_LINK_LIBRARIES(thr_timer mysys)
+SET_TARGET_PROPERTIES(thr_timer PROPERTIES COMPILE_FLAGS "-DMAIN")
+
IF(MSVC)
INSTALL_DEBUG_TARGET(mysys DESTINATION ${INSTALL_LIBDIR}/debug)
ENDIF()
diff --git a/mysys/array.c b/mysys/array.c
index a8c5d181638..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/charset-def.c b/mysys/charset-def.c
index af1e9bae2ac..defb5c0062d 100644
--- a/mysys/charset-def.c
+++ b/mysys/charset-def.c
@@ -49,6 +49,7 @@ extern struct charset_info_st my_charset_ucs2_unicode_520_ci;
extern struct charset_info_st my_charset_ucs2_vietnamese_ci;
extern struct charset_info_st my_charset_ucs2_croatian_uca_ci;
extern struct charset_info_st my_charset_ucs2_myanmar_uca_ci;
+extern struct charset_info_st my_charset_ucs2_thai_520_w2;
#endif
@@ -78,6 +79,7 @@ extern struct charset_info_st my_charset_utf32_unicode_520_ci;
extern struct charset_info_st my_charset_utf32_vietnamese_ci;
extern struct charset_info_st my_charset_utf32_croatian_uca_ci;
extern struct charset_info_st my_charset_utf32_myanmar_uca_ci;
+extern struct charset_info_st my_charset_utf32_thai_520_w2;
#endif /* HAVE_CHARSET_utf32 */
@@ -107,6 +109,7 @@ extern struct charset_info_st my_charset_utf16_unicode_520_ci;
extern struct charset_info_st my_charset_utf16_vietnamese_ci;
extern struct charset_info_st my_charset_utf16_croatian_uca_ci;
extern struct charset_info_st my_charset_utf16_myanmar_uca_ci;
+extern struct charset_info_st my_charset_utf16_thai_520_w2;
#endif /* HAVE_CHARSET_utf16 */
@@ -136,6 +139,7 @@ extern struct charset_info_st my_charset_utf8_unicode_520_ci;
extern struct charset_info_st my_charset_utf8_vietnamese_ci;
extern struct charset_info_st my_charset_utf8_croatian_uca_ci;
extern struct charset_info_st my_charset_utf8_myanmar_uca_ci;
+extern struct charset_info_st my_charset_utf8_thai_520_w2;
#ifdef HAVE_UTF8_GENERAL_CS
extern struct charset_info_st my_charset_utf8_general_cs;
#endif
@@ -167,6 +171,7 @@ extern struct charset_info_st my_charset_utf8mb4_unicode_520_ci;
extern struct charset_info_st my_charset_utf8mb4_vietnamese_ci;
extern struct charset_info_st my_charset_utf8mb4_croatian_uca_ci;
extern struct charset_info_st my_charset_utf8mb4_myanmar_uca_ci;
+extern struct charset_info_st my_charset_utf8mb4_thai_520_w2;
#endif /* HAVE_CHARSET_utf8mb4 */
#endif /* HAVE_UCA_COLLATIONS */
@@ -261,6 +266,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_ucs2_vietnamese_ci);
add_compiled_collation(&my_charset_ucs2_croatian_uca_ci);
add_compiled_collation(&my_charset_ucs2_myanmar_uca_ci);
+ add_compiled_collation(&my_charset_ucs2_thai_520_w2);
#endif
#endif
@@ -303,6 +309,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_utf8_vietnamese_ci);
add_compiled_collation(&my_charset_utf8_croatian_uca_ci);
add_compiled_collation(&my_charset_utf8_myanmar_uca_ci);
+ add_compiled_collation(&my_charset_utf8_thai_520_w2);
#endif
#endif /* HAVE_CHARSET_utf8 */
@@ -337,6 +344,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_utf8mb4_vietnamese_ci);
add_compiled_collation(&my_charset_utf8mb4_croatian_uca_ci);
add_compiled_collation(&my_charset_utf8mb4_myanmar_uca_ci);
+ add_compiled_collation(&my_charset_utf8mb4_thai_520_w2);
#endif /* HAVE_UCA_COLLATIONS */
#endif /* HAVE_CHARSET_utf8mb4 */
@@ -373,6 +381,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_utf16_vietnamese_ci);
add_compiled_collation(&my_charset_utf16_croatian_uca_ci);
add_compiled_collation(&my_charset_utf16_myanmar_uca_ci);
+ add_compiled_collation(&my_charset_utf16_thai_520_w2);
#endif /* HAVE_UCA_COLLATIONS */
#endif /* HAVE_CHARSET_utf16 */
@@ -407,6 +416,7 @@ my_bool init_compiled_charsets(myf flags __attribute__((unused)))
add_compiled_collation(&my_charset_utf32_vietnamese_ci);
add_compiled_collation(&my_charset_utf32_croatian_uca_ci);
add_compiled_collation(&my_charset_utf32_myanmar_uca_ci);
+ add_compiled_collation(&my_charset_utf32_thai_520_w2);
#endif /* HAVE_UCA_COLLATIONS */
#endif /* HAVE_CHARSET_utf32 */
diff --git a/mysys/checksum.c b/mysys/checksum.c
index 7bc52c6a178..a948785d935 100644
--- a/mysys/checksum.c
+++ b/mysys/checksum.c
@@ -18,8 +18,6 @@
#include <my_sys.h>
#include <zlib.h>
-ulong my_crc_dbug_check= ~0; /* Cannot happen */
-
/*
Calculate a long checksum for a memoryblock.
@@ -34,7 +32,5 @@ ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length)
{
crc= (ha_checksum) crc32((uint)crc, pos, (uint) length);
DBUG_PRINT("info", ("crc: %lu", (ulong) crc));
- if ((ulong)crc == my_crc_dbug_check)
- my_debug_put_break_here();
return crc;
}
diff --git a/mysys/hash.c b/mysys/hash.c
index 344b698a433..dc03ea9a4dc 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -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 282433ea48d..b349ef88ed1 100644
--- a/mysys/lf_alloc-pin.c
+++ b/mysys/lf_alloc-pin.c
@@ -111,7 +111,7 @@
#define LF_PINBOX_MAX_PINS 65536
-static void _lf_pinbox_real_free(LF_PINS *pins);
+static void lf_pinbox_real_free(LF_PINS *pins);
/*
Initialize a pinbox. Normally called from lf_alloc_init.
@@ -150,7 +150,7 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox)
It is assumed that pins belong to a thread and are not transferable
between threads.
*/
-LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
+LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox)
{
struct st_my_thread_var *var;
uint32 pins, next, top_ver;
@@ -177,12 +177,12 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
note that the first allocated element has index 1 (pins==1).
index 0 is reserved to mean "NULL pointer"
*/
- el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins);
+ el= (LF_PINS *)lf_dynarray_lvalue(&pinbox->pinarray, pins);
if (unlikely(!el))
return 0;
break;
}
- el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins);
+ el= (LF_PINS *)lf_dynarray_value(&pinbox->pinarray, pins);
next= el->link;
} while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
(int32*) &top_ver,
@@ -212,7 +212,7 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
empty the purgatory (XXX deadlock warning below!),
push LF_PINS structure to a stack
*/
-void _lf_pinbox_put_pins(LF_PINS *pins)
+void lf_pinbox_put_pins(LF_PINS *pins)
{
LF_PINBOX *pinbox= pins->pinbox;
uint32 top_ver, nr;
@@ -229,19 +229,15 @@ void _lf_pinbox_put_pins(LF_PINS *pins)
/*
XXX this will deadlock if other threads will wait for
- the caller to do something after _lf_pinbox_put_pins(),
+ the caller to do something after lf_pinbox_put_pins(),
and they would have pinned addresses that the caller wants to free.
Thus: only free pins when all work is done and nobody can wait for you!!!
*/
while (pins->purgatory_count)
{
- _lf_pinbox_real_free(pins);
+ lf_pinbox_real_free(pins);
if (pins->purgatory_count)
- {
- my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock);
pthread_yield();
- my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock);
- }
}
top_ver= pinbox->pinstack_top_ver;
do
@@ -271,14 +267,14 @@ static int ptr_cmp(void **a, void **b)
Free an object allocated via pinbox allocator
DESCRIPTION
- add an object to purgatory. if necessary, call _lf_pinbox_real_free()
+ add an object to purgatory. if necessary, calllf_pinbox_real_free()
to actually free something.
*/
-void _lf_pinbox_free(LF_PINS *pins, void *addr)
+void lf_pinbox_free(LF_PINS *pins, void *addr)
{
add_to_purgatory(pins, addr);
if (pins->purgatory_count % LF_PURGATORY_SIZE == 0)
- _lf_pinbox_real_free(pins);
+ lf_pinbox_real_free(pins);
}
struct st_harvester {
@@ -287,7 +283,7 @@ struct st_harvester {
};
/*
- callback for _lf_dynarray_iterate:
+ callback forlf_dynarray_iterate:
scan all pins of all threads and accumulate all pins
*/
static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
@@ -314,7 +310,7 @@ static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
}
/*
- callback for _lf_dynarray_iterate:
+ callback forlf_dynarray_iterate:
scan all pins of all threads and see if addr is present there
*/
static int match_pins(LF_PINS *el, void *addr)
@@ -340,7 +336,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;
@@ -363,7 +359,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;
@@ -398,7 +394,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;
}
@@ -420,7 +416,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
@@ -502,7 +498,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;
@@ -511,7 +507,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)
{
@@ -528,7 +524,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 0699f5d49fe..6be11edbfcf 100644
--- a/mysys/lf_hash.c
+++ b/mysys/lf_hash.c
@@ -25,12 +25,13 @@
#include <my_global.h>
#include <m_string.h>
#include <my_sys.h>
+#include <mysys_err.h>
#include <my_bit.h>
#include <lf.h>
/* An element of the list */
typedef struct {
- intptr volatile link; /* a pointer to the next element in a listand a flag */
+ intptr volatile link; /* a pointer to the next element in a list and a flag */
uint32 hashnr; /* reversed hash number, for sorting */
const uchar *key;
size_t keylen;
@@ -58,63 +59,84 @@ typedef struct {
#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1))
#define DELETED(V) ((V) & 1)
-/*
- DESCRIPTION
+/** walk the list, searching for an element or invoking a callback
+
Search for hashnr/key/keylen in the list starting from 'head' and
position the cursor. The list is ORDER BY hashnr, key
- RETURN
- 0 - not found
- 1 - found
+ @param head start walking the list from this node
+ @param cs charset for comparing keys, NULL if callback is used
+ @param hashnr hash number to search for
+ @param key key to search for OR data for the callback
+ @param keylen length of the key to compare, 0 if callback is used
+ @param cursor for returning the found element
+ @param pins see lf_alloc-pin.c
+ @param callback callback action, invoked for every element
- NOTE
+ @note
cursor is positioned in either case
pins[0..2] are used, they are NOT removed on return
+ callback might see some elements twice (because of retries)
+
+ @return
+ if find: 0 - not found
+ 1 - found
+ if callback:
+ 0 - ok
+ 1 - error (callbck returned 1)
*/
static int l_find(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
- const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins)
+ const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins,
+ my_hash_walk_action callback)
{
uint32 cur_hashnr;
const uchar *cur_key;
uint cur_keylen;
intptr link;
+ DBUG_ASSERT(!cs || !callback); /* should not be set both */
+ DBUG_ASSERT(!keylen || !callback); /* should not be set both */
+
retry:
cursor->prev= (intptr *)head;
do { /* PTR() isn't necessary below, head is a dummy node */
cursor->curr= (LF_SLIST *)(*cursor->prev);
- _lf_pin(pins, 1, cursor->curr);
+ lf_pin(pins, 1, cursor->curr);
} while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
+
for (;;)
{
if (unlikely(!cursor->curr))
return 0; /* end of the list */
+
+ cur_hashnr= cursor->curr->hashnr;
+ cur_keylen= cursor->curr->keylen;
+ cur_key= cursor->curr->key;
+
do {
- /* QQ: XXX or goto retry ? */
link= cursor->curr->link;
cursor->next= PTR(link);
- _lf_pin(pins, 0, cursor->next);
+ lf_pin(pins, 0, cursor->next);
} while (link != cursor->curr->link && LF_BACKOFF);
- cur_hashnr= cursor->curr->hashnr;
- cur_key= cursor->curr->key;
- cur_keylen= cursor->curr->keylen;
- if (*cursor->prev != (intptr)cursor->curr)
- {
- (void)LF_BACKOFF;
- goto retry;
- }
+
if (!DELETED(link))
{
- if (cur_hashnr >= hashnr)
+ if (unlikely(callback))
+ {
+ if (cur_hashnr & 1 && callback(cursor->curr + 1, (void*)key))
+ return 1;
+ }
+ else if (cur_hashnr >= hashnr)
{
int r= 1;
if (cur_hashnr > hashnr ||
- (r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key,
- keylen)) >= 0)
+ (r= my_strnncoll(cs, cur_key, cur_keylen, key, keylen)) >= 0)
return !r;
}
cursor->prev= &(cursor->curr->link);
- _lf_pin(pins, 2, cursor->curr);
+ if (!(cur_hashnr & 1)) /* dummy node */
+ head= (LF_SLIST **)cursor->prev;
+ lf_pin(pins, 2, cursor->curr);
}
else
{
@@ -123,16 +145,13 @@ retry:
and remove this deleted node
*/
if (my_atomic_casptr((void **) cursor->prev,
- (void **)(char*) &cursor->curr, cursor->next))
- _lf_alloc_free(pins, cursor->curr);
+ (void **) &cursor->curr, cursor->next) && LF_BACKOFF)
+ lf_alloc_free(pins, cursor->curr);
else
- {
- (void)LF_BACKOFF;
goto retry;
- }
}
cursor->curr= cursor->next;
- _lf_pin(pins, 1, cursor->curr);
+ lf_pin(pins, 1, cursor->curr);
}
}
@@ -158,7 +177,7 @@ static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
for (;;)
{
if (l_find(head, cs, node->hashnr, node->key, node->keylen,
- &cursor, pins) &&
+ &cursor, pins, 0) &&
(flags & LF_HASH_UNIQUE))
{
res= 0; /* duplicate found */
@@ -177,9 +196,9 @@ static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
}
}
}
- _lf_unpin(pins, 0);
- _lf_unpin(pins, 1);
- _lf_unpin(pins, 2);
+ lf_unpin(pins, 0);
+ lf_unpin(pins, 1);
+ lf_unpin(pins, 2);
/*
Note that cursor.curr is not pinned here and the pointer is unreliable,
the object may dissapear anytime. But if it points to a dummy node, the
@@ -209,7 +228,7 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
for (;;)
{
- if (!l_find(head, cs, hashnr, key, keylen, &cursor, pins))
+ if (!l_find(head, cs, hashnr, key, keylen, &cursor, pins, 0))
{
res= 1; /* not found */
break;
@@ -224,7 +243,7 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
/* and remove it from the list */
if (my_atomic_casptr((void **)cursor.prev,
(void **)(char*)&cursor.curr, cursor.next))
- _lf_alloc_free(pins, cursor.curr);
+ lf_alloc_free(pins, cursor.curr);
else
{
/*
@@ -233,16 +252,16 @@ static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
(to ensure the number of "set DELETED flag" actions
is equal to the number of "remove from the list" actions)
*/
- l_find(head, cs, hashnr, key, keylen, &cursor, pins);
+ l_find(head, cs, hashnr, key, keylen, &cursor, pins, 0);
}
res= 0;
break;
}
}
}
- _lf_unpin(pins, 0);
- _lf_unpin(pins, 1);
- _lf_unpin(pins, 2);
+ lf_unpin(pins, 0);
+ lf_unpin(pins, 1);
+ lf_unpin(pins, 2);
return res;
}
@@ -264,13 +283,13 @@ static LF_SLIST *l_search(LF_SLIST * volatile *head, CHARSET_INFO *cs,
LF_PINS *pins)
{
CURSOR cursor;
- int res= l_find(head, cs, hashnr, key, keylen, &cursor, pins);
+ int res= l_find(head, cs, hashnr, key, keylen, &cursor, pins, 0);
if (res)
- _lf_pin(pins, 2, cursor.curr);
+ lf_pin(pins, 2, cursor.curr);
else
- _lf_unpin(pins, 2);
- _lf_unpin(pins, 1);
- _lf_unpin(pins, 0);
+ lf_unpin(pins, 2);
+ lf_unpin(pins, 1);
+ lf_unpin(pins, 0);
return res ? cursor.curr : 0;
}
@@ -289,18 +308,24 @@ static inline const uchar* hash_key(const LF_HASH *hash,
@note, that the hash value is limited to 2^31, because we need one
bit to distinguish between normal and dummy nodes.
*/
-static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen)
+static inline my_hash_value_type calc_hash(const CHARSET_INFO *cs,
+ const uchar *key,
+ size_t keylen)
{
ulong nr1= 1, nr2= 4;
- hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen,
- &nr1, &nr2);
- return nr1 & INT_MAX32;
+ cs->coll->hash_sort(cs, (uchar*) key, keylen, &nr1, &nr2);
+ return nr1;
}
#define MAX_LOAD 1.0 /* average number of elements in a bucket */
static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
+static void default_initializer(LF_HASH *hash, void *dst, const void *src)
+{
+ memcpy(dst, src, hash->element_size);
+}
+
/*
Initializes lf_hash, the arguments are compatible with hash_init
@@ -312,7 +337,9 @@ static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
is expensive to initialize - for example if there is a mutex or
DYNAMIC_ARRAY. In this case they should be initialize in the
LF_ALLOCATOR::constructor, and lf_hash_insert should not overwrite them.
- See wt_init() for example.
+
+ The above works well with PODS. For more complex cases (e.g. C++ classes
+ with private members) use initializer function.
*/
void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
uint key_offset, uint key_length, my_hash_get_key get_key,
@@ -329,12 +356,14 @@ void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
hash->key_offset= key_offset;
hash->key_length= key_length;
hash->get_key= get_key;
+ hash->initializer= default_initializer;
+ hash->hash_function= calc_hash;
DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length);
}
void lf_hash_destroy(LF_HASH *hash)
{
- LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0);
+ LF_SLIST *el, **head= (LF_SLIST **)lf_dynarray_value(&hash->array, 0);
if (head)
{
@@ -371,15 +400,14 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
int csize, bucket, hashnr;
LF_SLIST *node, * volatile *el;
- lf_rwlock_by_pins(pins);
- node= (LF_SLIST *)_lf_alloc_new(pins);
+ node= (LF_SLIST *)lf_alloc_new(pins);
if (unlikely(!node))
return -1;
- memcpy(node+1, data, hash->element_size);
+ hash->initializer(hash, node + 1, data);
node->key= hash_key(hash, (uchar *)(node+1), &node->keylen);
- hashnr= calc_hash(hash, node->key, node->keylen);
+ hashnr= hash->hash_function(hash->charset, node->key, node->keylen) & INT_MAX32;
bucket= hashnr % hash->size;
- el= _lf_dynarray_lvalue(&hash->array, bucket);
+ el= lf_dynarray_lvalue(&hash->array, bucket);
if (unlikely(!el))
return -1;
if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
@@ -387,14 +415,12 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */
if (l_insert(el, hash->charset, node, pins, hash->flags))
{
- _lf_alloc_free(pins, node);
- lf_rwunlock_by_pins(pins);
+ lf_alloc_free(pins, node);
return 1;
}
csize= hash->size;
if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD)
my_atomic_cas32(&hash->size, &csize, csize*2);
- lf_rwunlock_by_pins(pins);
return 0;
}
@@ -406,36 +432,31 @@ int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
RETURN
0 - deleted
1 - didn't (not found)
- -1 - out of memory
NOTE
see l_delete() for pin usage notes
*/
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
{
LF_SLIST * volatile *el;
- uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
+ uint bucket, hashnr;
- bucket= hashnr % hash->size;
- lf_rwlock_by_pins(pins);
- el= _lf_dynarray_lvalue(&hash->array, bucket);
- if (unlikely(!el))
- return -1;
- /*
- note that we still need to initialize_bucket here,
- we cannot return "node not found", because an old bucket of that
- node may've been split and the node was assigned to a new bucket
- that was never accessed before and thus is not initialized.
- */
- if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
- return -1;
+ hashnr= hash->hash_function(hash->charset, (uchar *)key, keylen) & INT_MAX32;
+
+ /* hide OOM errors - if we cannot 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 (l_delete(el, hash->charset, my_reverse_bits(hashnr) | 1,
(uchar *)key, keylen, pins))
{
- lf_rwunlock_by_pins(pins);
return 1;
}
my_atomic_add32(&hash->count, -1);
- lf_rwunlock_by_pins(pins);
return 0;
}
@@ -444,29 +465,73 @@ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
a pointer to an element with the given key (if a hash is not unique and
there're many elements with this key - the "first" matching element)
NULL if nothing is found
- MY_ERRPTR if OOM
NOTE
see l_search() for pin usage notes
*/
-void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
+void *lf_hash_search_using_hash_value(LF_HASH *hash, LF_PINS *pins,
+ my_hash_value_type hashnr,
+ const void *key, uint keylen)
{
LF_SLIST * volatile *el, *found;
- uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
+ uint bucket;
- bucket= hashnr % hash->size;
- lf_rwlock_by_pins(pins);
- el= _lf_dynarray_lvalue(&hash->array, bucket);
- if (unlikely(!el))
- return MY_ERRPTR;
- if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
- return MY_ERRPTR;
+ /* hide OOM errors - if we cannot 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= l_search(el, hash->charset, my_reverse_bits(hashnr) | 1,
(uchar *)key, keylen, pins);
- lf_rwunlock_by_pins(pins);
return found ? found+1 : 0;
}
+
+/**
+ Iterate over all elements in hash and call function with the element
+
+ @note
+ If one of 'action' invocations returns 1 the iteration aborts.
+ 'action' might see some elements twice!
+
+ @retval 0 ok
+ @retval 1 error (action returned 1)
+*/
+int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins,
+ my_hash_walk_action action, void *argument)
+{
+ CURSOR cursor;
+ uint bucket= 0;
+ int res;
+ LF_SLIST * volatile *el;
+
+ el= lf_dynarray_lvalue(&hash->array, bucket);
+ if (unlikely(!el))
+ return 0; /* if there's no bucket==0, the hash is empty */
+ if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
+ return 0; /* if there's no bucket==0, the hash is empty */
+
+ res= l_find(el, 0, 0, (uchar*)argument, 0, &cursor, pins, action);
+
+ lf_unpin(pins, 2);
+ lf_unpin(pins, 1);
+ lf_unpin(pins, 0);
+ return res;
+}
+
+void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
+{
+ return lf_hash_search_using_hash_value(hash, pins,
+ hash->hash_function(hash->charset,
+ (uchar*) key,
+ keylen) & INT_MAX32,
+ key, keylen);
+}
+
static const uchar *dummy_key= (uchar*)"";
/*
@@ -480,7 +545,7 @@ static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node,
uint parent= my_clear_highest_bit(bucket);
LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME));
LF_SLIST **tmp= 0, *cur;
- LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent);
+ LF_SLIST * volatile *el= lf_dynarray_lvalue(&hash->array, parent);
if (unlikely(!el || !dummy))
return -1;
if (*el == NULL && bucket &&
diff --git a/mysys/ma_dyncol.c b/mysys/ma_dyncol.c
index 7cd0c2b02df..92418e38c2e 100644
--- a/mysys/ma_dyncol.c
+++ b/mysys/ma_dyncol.c
@@ -2578,7 +2578,6 @@ find_place(DYN_HEADER *hdr, void *key, my_bool string_keys)
mid= 1;
while (start != end)
{
- uint val;
mid= (start + end) / 2;
hdr->entry= hdr->header + mid * hdr->entry_size;
if (!string_keys)
@@ -3895,11 +3894,11 @@ mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
}
case DYN_COL_DECIMAL:
{
- int len= sizeof(buff);
- decimal2string(&val->x.decimal.value, buff, &len,
+ int tmp_len= sizeof(buff);
+ decimal2string(&val->x.decimal.value, buff, &tmp_len,
0, val->x.decimal.value.frac,
'0');
- if (dynstr_append_mem(str, buff, len))
+ if (dynstr_append_mem(str, buff, tmp_len))
return ER_DYNCOL_RESOURCE;
break;
}
diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c
index 545084ea97f..a3426889a82 100644
--- a/mysys/mf_cache.c
+++ b/mysys/mf_cache.c
@@ -20,11 +20,12 @@
#include "my_static.h"
#include "mysys_err.h"
- /*
- Remove an open tempfile so that it doesn't survive
- if we crash; If the operating system doesn't support
- this, just remember the file name for later removal
- */
+/**
+ Remove an open tempfile so that it doesn't survive if we crash
+
+ If the operating system doesn't support this, just remember
+ the file name for later removal
+*/
static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)),
const char *name)
@@ -49,41 +50,46 @@ static my_bool cache_remove_open_tmp(IO_CACHE *cache __attribute__((unused)),
return 0;
}
- /*
- ** Open tempfile cached by IO_CACHE
- ** Should be used when no seeks are done (only reinit_io_buff)
- ** Return 0 if cache is inited ok
- ** The actual file is created when the IO_CACHE buffer gets filled
- ** If dir is not given, use TMPDIR.
- */
+/**
+ Open tempfile cached by IO_CACHE
+ Should be used when no seeks are done (only reinit_io_buff)
+ Return 0 if cache is inited ok
+ The actual file is created when the IO_CACHE buffer gets filled
+ If dir is not given, use TMPDIR.
+*/
my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
size_t cache_size, myf cache_myflags)
{
DBUG_ENTER("open_cached_file");
- cache->dir= dir ? my_strdup(dir,MYF(cache_myflags & MY_WME)) : (char*) 0;
- cache->prefix= (prefix ? my_strdup(prefix,MYF(cache_myflags & MY_WME)) :
- (char*) 0);
+ cache->dir= dir;
+ if (prefix)
+ {
+ DBUG_ASSERT(strlen(prefix) == 2);
+ memcpy(cache->prefix, prefix, 3);
+ }
+ else
+ cache->prefix[0]= 0;
cache->file_name=0;
cache->buffer=0; /* Mark that not open */
- if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0,
+ if (!init_io_cache(cache, -1, cache_size, WRITE_CACHE, 0L, 0,
MYF(cache_myflags | MY_NABP)))
{
DBUG_RETURN(0);
}
- my_free(cache->dir);
- my_free(cache->prefix);
DBUG_RETURN(1);
}
- /* Create the temporary file */
-
+/**
+ Create the temporary file
+*/
my_bool real_open_cached_file(IO_CACHE *cache)
{
char name_buff[FN_REFLEN];
int error=1;
DBUG_ENTER("real_open_cached_file");
- if ((cache->file=create_temp_file(name_buff, cache->dir, cache->prefix,
+ if ((cache->file=create_temp_file(name_buff, cache->dir,
+ cache->prefix[0] ? cache->prefix : 0,
(O_RDWR | O_BINARY | O_TRUNC |
O_TEMPORARY | O_SHORT_LIVED),
MYF(MY_WME))) >= 0)
@@ -114,8 +120,6 @@ void close_cached_file(IO_CACHE *cache)
}
#endif
}
- my_free(cache->dir);
- my_free(cache->prefix);
}
DBUG_VOID_RETURN;
}
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index f891a22b17d..4afe74da077 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates
+ Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,7 +23,6 @@
Possibly use of asyncronic io.
macros for read and writes for faster io.
Used instead of FILE when reading or writing whole files.
- This code makes mf_rec_cache obsolete (currently only used by ISAM)
One can change info->pos_in_file to a higher value to skip bytes in file if
also info->read_pos is set to info->read_end.
If called through open_cached_file(), then the temporary file will
@@ -64,6 +64,16 @@ static void my_aiowait(my_aio_result *result);
#define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1))
#define IO_ROUND_DN(X) ( (X) & ~(IO_SIZE-1))
+static int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count);
+static int _my_b_cache_read_r(IO_CACHE *info, uchar *Buffer, size_t Count);
+static int _my_b_seq_read(IO_CACHE *info, uchar *Buffer, size_t Count);
+static int _my_b_cache_write(IO_CACHE *info, const uchar *Buffer, size_t Count);
+static int _my_b_cache_write_r(IO_CACHE *info, const uchar *Buffer, size_t Count);
+
+int (*_my_b_encr_read)(IO_CACHE *info,uchar *Buffer,size_t Count)= 0;
+int (*_my_b_encr_write)(IO_CACHE *info,const uchar *Buffer,size_t Count)= 0;
+
+
/*
Setup internal pointers inside IO_CACHE
@@ -97,6 +107,8 @@ static void
init_functions(IO_CACHE* info)
{
enum cache_type type= info->type;
+ info->read_function = 0; /* Force a core if used */
+ info->write_function = 0; /* Force a core if used */
switch (type) {
case READ_NET:
/*
@@ -106,14 +118,35 @@ init_functions(IO_CACHE* info)
programs that link against mysys but know nothing about THD, such
as myisamchk
*/
+ DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
break;
case SEQ_READ_APPEND:
info->read_function = _my_b_seq_read;
- info->write_function = 0; /* Force a core if used */
+ DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
+ break;
+ case READ_CACHE:
+ if (info->myflags & MY_ENCRYPT)
+ {
+ DBUG_ASSERT(info->share == 0);
+ info->read_function = _my_b_encr_read;
+ break;
+ }
+ /* fall through */
+ case WRITE_CACHE:
+ if (info->myflags & MY_ENCRYPT)
+ {
+ info->write_function = _my_b_encr_write;
+ break;
+ }
+ /* fall through */
+ case READ_FIFO:
+ DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
+ info->read_function = info->share ? _my_b_cache_read_r : _my_b_cache_read;
+ info->write_function = info->share ? _my_b_cache_write_r : _my_b_cache_write;
+ break;
+ case TYPE_NOT_SET:
+ DBUG_ASSERT(0);
break;
- default:
- info->read_function = info->share ? _my_b_read_r : _my_b_read;
- info->write_function = _my_b_write;
}
setup_io_cache(info);
@@ -134,7 +167,7 @@ init_functions(IO_CACHE* info)
type Type of cache
seek_offset Where cache should start reading/writing
use_async_io Set to 1 of we should use async_io (if avaiable)
- cache_myflags Bitmap of differnt flags
+ cache_myflags Bitmap of different flags
MY_WME | MY_FAE | MY_NABP | MY_FNABP |
MY_DONT_CHECK_FILESIZE
@@ -145,7 +178,7 @@ init_functions(IO_CACHE* info)
int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
enum cache_type type, my_off_t seek_offset,
- pbool use_async_io, myf cache_myflags)
+ my_bool use_async_io, myf cache_myflags)
{
size_t min_cache;
my_off_t pos;
@@ -157,14 +190,13 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
info->file= file;
info->type= TYPE_NOT_SET; /* Don't set it until mutex are created */
info->pos_in_file= seek_offset;
- info->pre_close = info->pre_read = info->post_read = 0;
- info->arg = 0;
info->alloced_buffer = 0;
info->buffer=0;
info->seek_not_done= 0;
if (file >= 0)
{
+ DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT));
pos= mysql_file_tell(file, MYF(0));
if ((pos == (my_off_t) -1) && (my_errno == ESPIPE))
{
@@ -181,6 +213,12 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
else
info->seek_not_done= MY_TEST(seek_offset != pos);
}
+ else
+ if (type == WRITE_CACHE && _my_b_encr_read)
+ {
+ cache_myflags|= MY_ENCRYPT;
+ DBUG_ASSERT(seek_offset == 0);
+ }
info->disk_writes= 0;
info->share=0;
@@ -190,6 +228,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
if (type == READ_CACHE || type == SEQ_READ_APPEND)
{ /* Assume file isn't growing */
+ DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT));
if (!(cache_myflags & MY_DONT_CHECK_FILESIZE))
{
/* Calculate end of file to avoid allocating oversized buffers */
@@ -207,7 +246,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
}
}
cache_myflags &= ~MY_DONT_CHECK_FILESIZE;
- if (type != READ_NET && type != WRITE_NET)
+ if (type != READ_NET)
{
/* Retry allocating memory in smaller blocks until we get one */
cachesize= ((cachesize + min_cache-1) & ~(min_cache-1));
@@ -225,15 +264,18 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
buffer_block= cachesize;
if (type == SEQ_READ_APPEND)
buffer_block *= 2;
+ else if (cache_myflags & MY_ENCRYPT)
+ buffer_block= 2*(buffer_block + MY_AES_BLOCK_SIZE) + sizeof(IO_CACHE_CRYPT);
if (cachesize == min_cache)
flags|= (myf) MY_WME;
if ((info->buffer= (uchar*) my_malloc(buffer_block, flags)) != 0)
{
- info->write_buffer=info->buffer;
if (type == SEQ_READ_APPEND)
- info->write_buffer = info->buffer + cachesize;
- info->alloced_buffer=1;
+ info->write_buffer= info->buffer + cachesize;
+ else
+ info->write_buffer= info->buffer;
+ info->alloced_buffer= 1;
break; /* Enough memory found */
}
if (cachesize == min_cache)
@@ -277,6 +319,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
if (use_async_io && ! my_disable_async_io)
{
DBUG_PRINT("info",("Using async io"));
+ DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT));
info->read_length/=2;
info->read_function=_my_b_async_read;
}
@@ -322,18 +365,16 @@ static void my_aiowait(my_aio_result *result)
my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
my_off_t seek_offset,
- pbool use_async_io __attribute__((unused)),
- pbool clear_cache)
+ my_bool use_async_io __attribute__((unused)),
+ my_bool clear_cache)
{
DBUG_ENTER("reinit_io_cache");
DBUG_PRINT("enter",("cache: 0x%lx type: %d seek_offset: %lu clear_cache: %d",
(ulong) info, type, (ulong) seek_offset,
(int) clear_cache));
- /* One can't do reinit with the following types */
- DBUG_ASSERT(type != READ_NET && info->type != READ_NET &&
- type != WRITE_NET && info->type != WRITE_NET &&
- type != SEQ_READ_APPEND && info->type != SEQ_READ_APPEND);
+ DBUG_ASSERT(type == READ_CACHE || type == WRITE_CACHE);
+ DBUG_ASSERT(info->type == READ_CACHE || info->type == WRITE_CACHE);
/* If the whole file is in memory, avoid flushing to disk */
if (! clear_cache &&
@@ -391,8 +432,22 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
}
else
{
- info->write_end=(info->buffer + info->buffer_length -
- (seek_offset & (IO_SIZE-1)));
+ if (info->myflags & MY_ENCRYPT)
+ {
+ info->write_end = info->write_buffer + info->buffer_length;
+ if (seek_offset && info->file != -1)
+ {
+ info->read_end= info->buffer;
+ _my_b_encr_read(info, 0, 0); /* prefill the buffer */
+ info->write_pos= info->read_pos;
+ info->pos_in_file+= info->buffer_length;
+ }
+ }
+ else
+ {
+ info->write_end=(info->buffer + info->buffer_length -
+ (seek_offset & (IO_SIZE-1)));
+ }
info->end_of_file= ~(my_off_t) 0;
}
}
@@ -405,6 +460,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
((ulong) info->buffer_length <
(ulong) (info->end_of_file - seek_offset)))
{
+ DBUG_ASSERT(!(cache_myflags & MY_ENCRYPT));
info->read_length=info->buffer_length/2;
info->read_function=_my_b_async_read;
}
@@ -414,12 +470,72 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
} /* reinit_io_cache */
+int _my_b_read(IO_CACHE *info, uchar *Buffer, size_t Count)
+{
+ size_t left_length;
+ int res;
+
+ /* If the buffer is not empty yet, copy what is available. */
+ if ((left_length= (size_t) (info->read_end - info->read_pos)))
+ {
+ DBUG_ASSERT(Count > left_length);
+ memcpy(Buffer, info->read_pos, left_length);
+ Buffer+=left_length;
+ Count-=left_length;
+ }
+ res= info->read_function(info, Buffer, Count);
+ if (res && info->error >= 0)
+ info->error+= left_length; /* update number or read bytes */
+ return res;
+}
+
+int _my_b_write(IO_CACHE *info, const uchar *Buffer, size_t Count)
+{
+ size_t rest_length;
+ int res;
+
+ /* Always use my_b_flush_io_cache() to flush write_buffer! */
+ DBUG_ASSERT(Buffer != info->write_buffer);
+
+ if (info->pos_in_file + info->buffer_length > info->end_of_file)
+ {
+ my_errno=errno=EFBIG;
+ return info->error = -1;
+ }
+
+ rest_length= (size_t) (info->write_end - info->write_pos);
+ DBUG_ASSERT(Count >= rest_length);
+ memcpy(info->write_pos, Buffer, (size_t) rest_length);
+ Buffer+=rest_length;
+ Count-=rest_length;
+ info->write_pos+=rest_length;
+
+ if (my_b_flush_io_cache(info, 1))
+ return 1;
+
+ if (Count)
+ {
+ my_off_t old_pos_in_file= info->pos_in_file;
+ res= info->write_function(info, Buffer, Count);
+ Count-= info->pos_in_file - old_pos_in_file;
+ Buffer+= info->pos_in_file - old_pos_in_file;
+ }
+ else
+ res= 0;
+
+ if (!res && Count)
+ {
+ memcpy(info->write_pos, Buffer, Count);
+ info->write_pos+= Count;
+ }
+ return res;
+}
/*
Read buffered.
SYNOPSIS
- _my_b_read()
+ _my_b_cache_read()
info IO_CACHE pointer
Buffer Buffer to retrieve count bytes from file
Count Number of bytes to read into Buffer
@@ -435,7 +551,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
types than my_off_t unless you can be sure that their value fits.
Same applies to differences of file offsets.
- When changing this function, check _my_b_read_r(). It might need the
+ When changing this function, check _my_b_cache_read_r(). It might need the
same change.
RETURN
@@ -445,20 +561,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
Otherwise info->error contains the number of bytes in Buffer.
*/
-int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
+int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count)
{
- size_t length,diff_length,left_length, max_length;
+ size_t length, diff_length, left_length= 0, max_length;
my_off_t pos_in_file;
- DBUG_ENTER("_my_b_read");
-
- /* If the buffer is not empty yet, copy what is available. */
- if ((left_length= (size_t) (info->read_end-info->read_pos)))
- {
- DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
- memcpy(Buffer,info->read_pos, left_length);
- Buffer+=left_length;
- Count-=left_length;
- }
+ DBUG_ENTER("_my_b_cache_read");
/* pos_in_file always point on where info->buffer was read */
pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer);
@@ -515,7 +622,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
what we did already read from a block. That way, the read will
end aligned with a block.
*/
- length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
+ length= IO_ROUND_DN(Count) - diff_length;
if ((read_length= mysql_file_read(info->file,Buffer, length, info->myflags))
!= length)
{
@@ -558,7 +665,11 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
info->error= (int) left_length;
DBUG_RETURN(1);
}
- length=0; /* Didn't read any chars */
+ else
+ {
+ info->error= 0;
+ DBUG_RETURN(0); /* EOF */
+ }
}
else if ((length= mysql_file_read(info->file,info->buffer, max_length,
info->myflags)) < Count ||
@@ -685,12 +796,15 @@ void init_io_cache_share(IO_CACHE *read_cache, IO_CACHE_SHARE *cshare,
cshare->source_cache= write_cache; /* Can be NULL. */
read_cache->share= cshare;
- read_cache->read_function= _my_b_read_r;
+ read_cache->read_function= _my_b_cache_read_r;
read_cache->current_pos= NULL;
read_cache->current_end= NULL;
if (write_cache)
+ {
write_cache->share= cshare;
+ write_cache->write_function= _my_b_cache_write_r;
+ }
DBUG_VOID_RETURN;
}
@@ -958,7 +1072,7 @@ static void unlock_io_cache(IO_CACHE *cache)
Read from IO_CACHE when it is shared between several threads.
SYNOPSIS
- _my_b_read_r()
+ _my_b_cache_read_r()
cache IO_CACHE pointer
Buffer Buffer to retrieve count bytes from file
Count Number of bytes to read into Buffer
@@ -983,7 +1097,7 @@ static void unlock_io_cache(IO_CACHE *cache)
types than my_off_t unless you can be sure that their value fits.
Same applies to differences of file offsets. (Bug #11527)
- When changing this function, check _my_b_read(). It might need the
+ When changing this function, check _my_b_cache_read(). It might need the
same change.
RETURN
@@ -991,20 +1105,14 @@ static void unlock_io_cache(IO_CACHE *cache)
1 Error: can't read requested characters
*/
-int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
+static int _my_b_cache_read_r(IO_CACHE *cache, uchar *Buffer, size_t Count)
{
my_off_t pos_in_file;
- size_t length, diff_length, left_length;
+ size_t length, diff_length, left_length= 0;
IO_CACHE_SHARE *cshare= cache->share;
- DBUG_ENTER("_my_b_read_r");
+ DBUG_ENTER("_my_b_cache_read_r");
+ DBUG_ASSERT(!(cache->myflags & MY_ENCRYPT));
- if ((left_length= (size_t) (cache->read_end - cache->read_pos)))
- {
- DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */
- memcpy(Buffer, cache->read_pos, left_length);
- Buffer+= left_length;
- Count-= left_length;
- }
while (Count)
{
size_t cnt, len;
@@ -1119,21 +1227,22 @@ int _my_b_read_r(register IO_CACHE *cache, uchar *Buffer, size_t Count)
*/
static void copy_to_read_buffer(IO_CACHE *write_cache,
- const uchar *write_buffer, size_t write_length)
+ const uchar *write_buffer, my_off_t pos_in_file)
{
+ size_t write_length= write_cache->pos_in_file - pos_in_file;
IO_CACHE_SHARE *cshare= write_cache->share;
DBUG_ASSERT(cshare->source_cache == write_cache);
/*
write_length is usually less or equal to buffer_length.
- It can be bigger if _my_b_write() is called with a big length.
+ It can be bigger if _my_b_cache_write_r() is called with a big length.
*/
while (write_length)
{
size_t copy_length= MY_MIN(write_length, write_cache->buffer_length);
int __attribute__((unused)) rc;
- rc= lock_io_cache(write_cache, write_cache->pos_in_file);
+ rc= lock_io_cache(write_cache, pos_in_file);
/* The writing thread does always have the lock when it awakes. */
DBUG_ASSERT(rc);
@@ -1141,7 +1250,7 @@ static void copy_to_read_buffer(IO_CACHE *write_cache,
cshare->error= 0;
cshare->read_end= cshare->buffer + copy_length;
- cshare->pos_in_file= write_cache->pos_in_file;
+ cshare->pos_in_file= pos_in_file;
/* Mark all threads as running and wake them. */
unlock_io_cache(write_cache);
@@ -1165,20 +1274,12 @@ static void copy_to_read_buffer(IO_CACHE *write_cache,
1 Failed to read
*/
-int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
+static int _my_b_seq_read(IO_CACHE *info, uchar *Buffer, size_t Count)
{
- size_t length, diff_length, left_length, save_count, max_length;
+ size_t length, diff_length, left_length= 0, save_count, max_length;
my_off_t pos_in_file;
save_count=Count;
- /* first, read the regular buffer */
- if ((left_length=(size_t) (info->read_end-info->read_pos)))
- {
- DBUG_ASSERT(Count > left_length); /* User is not using my_b_read() */
- memcpy(Buffer,info->read_pos, left_length);
- Buffer+=left_length;
- Count-=left_length;
- }
lock_append_buffer(info);
/* pos_in_file always point on where info->buffer was read */
@@ -1206,7 +1307,7 @@ int _my_b_seq_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
/* Fill first intern buffer */
size_t read_length;
- length=(Count & (size_t) ~(IO_SIZE-1))-diff_length;
+ length= IO_ROUND_DN(Count) - diff_length;
if ((read_length= mysql_file_read(info->file,Buffer, length,
info->myflags)) == (size_t) -1)
{
@@ -1323,18 +1424,14 @@ read_append_buffer:
1 An error has occurred; IO_CACHE to error state.
*/
-int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
+int _my_b_async_read(IO_CACHE *info, uchar *Buffer, size_t Count)
{
- size_t length,read_length,diff_length,left_length,use_length,org_Count;
+ size_t length, read_length, diff_length, left_length=0, use_length, org_Count;
size_t max_length;
my_off_t next_pos_in_file;
uchar *read_buffer;
- memcpy(Buffer,info->read_pos,
- (left_length= (size_t) (info->read_end-info->read_pos)));
- Buffer+=left_length;
org_Count=Count;
- Count-=left_length;
if (info->inited)
{ /* wait for read block */
@@ -1488,7 +1585,7 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
info->read_end-=info->read_length;
}
info->read_length=info->buffer_length; /* Use hole buffer */
- info->read_function=_my_b_read; /* Use normal IO_READ next */
+ info->read_function=_my_b_cache_read; /* Use normal IO_READ next */
}
else
info->inited=info->aio_result.pending=1;
@@ -1503,13 +1600,8 @@ int _my_b_async_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
int _my_b_get(IO_CACHE *info)
{
uchar buff;
- IO_CACHE_CALLBACK pre_read,post_read;
- if ((pre_read = info->pre_read))
- (*pre_read)(info);
if ((*(info)->read_function)(info,&buff,1))
return my_b_EOF;
- if ((post_read = info->post_read))
- (*post_read)(info);
return (int) (uchar) buff;
}
@@ -1523,70 +1615,61 @@ int _my_b_get(IO_CACHE *info)
-1 On error; my_errno contains error code.
*/
-int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count)
+int _my_b_cache_write(IO_CACHE *info, const uchar *Buffer, size_t Count)
{
- size_t rest_length,length;
- my_off_t pos_in_file= info->pos_in_file;
-
- DBUG_EXECUTE_IF("simulate_huge_load_data_file",
- {
- pos_in_file=(my_off_t)(5000000000ULL);
- });
- if (pos_in_file+info->buffer_length > info->end_of_file)
+ if (Buffer != info->write_buffer)
{
- my_errno=errno=EFBIG;
- return info->error = -1;
+ Count= IO_ROUND_DN(Count);
+ if (!Count)
+ return 0;
}
- rest_length= (size_t) (info->write_end - info->write_pos);
- memcpy(info->write_pos,Buffer,(size_t) rest_length);
- Buffer+=rest_length;
- Count-=rest_length;
- info->write_pos+=rest_length;
-
- if (my_b_flush_io_cache(info,1))
- return 1;
- if (Count >= IO_SIZE)
- { /* Fill first intern buffer */
- length=Count & (size_t) ~(IO_SIZE-1);
- if (info->seek_not_done)
+ if (info->seek_not_done)
+ {
+ /*
+ Whenever a function which operates on IO_CACHE flushes/writes
+ some part of the IO_CACHE to disk it will set the property
+ "seek_not_done" to indicate this to other functions operating
+ on the IO_CACHE.
+ */
+ if (mysql_file_seek(info->file, info->pos_in_file, MY_SEEK_SET,
+ MYF(info->myflags & MY_WME)) == MY_FILEPOS_ERROR)
{
- /*
- Whenever a function which operates on IO_CACHE flushes/writes
- some part of the IO_CACHE to disk it will set the property
- "seek_not_done" to indicate this to other functions operating
- on the IO_CACHE.
- */
- if (mysql_file_seek(info->file, info->pos_in_file, MY_SEEK_SET, MYF(0)))
- {
- info->error= -1;
- return (1);
- }
- info->seek_not_done=0;
+ info->error= -1;
+ return 1;
}
- if (mysql_file_write(info->file, Buffer, length, info->myflags | MY_NABP))
- return info->error= -1;
+ info->seek_not_done=0;
+ }
+ if (mysql_file_write(info->file, Buffer, Count, info->myflags | MY_NABP))
+ return info->error= -1;
- /*
- In case of a shared I/O cache with a writer we normally do direct
- write cache to read cache copy. Simulate this here by direct
- caller buffer to read cache copy. Do it after the write so that
- the cache readers actions on the flushed part can go in parallel
- with the write of the extra stuff. copy_to_read_buffer()
- synchronizes writer and readers so that after this call the
- readers can act on the extra stuff while the writer can go ahead
- and prepare the next output. copy_to_read_buffer() relies on
- info->pos_in_file.
- */
- if (info->share)
- copy_to_read_buffer(info, Buffer, length);
+ info->pos_in_file+= Count;
+ return 0;
+}
+
+
+/*
+ In case of a shared I/O cache with a writer we normally do direct
+ write cache to read cache copy. Simulate this here by direct
+ caller buffer to read cache copy. Do it after the write so that
+ the cache readers actions on the flushed part can go in parallel
+ with the write of the extra stuff. copy_to_read_buffer()
+ synchronizes writer and readers so that after this call the
+ readers can act on the extra stuff while the writer can go ahead
+ and prepare the next output. copy_to_read_buffer() relies on
+ info->pos_in_file.
+*/
+static int _my_b_cache_write_r(IO_CACHE *info, const uchar *Buffer, size_t Count)
+{
+ my_off_t old_pos_in_file= info->pos_in_file;
+ int res= _my_b_cache_write(info, Buffer, Count);
+ if (res)
+ return res;
+
+ DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
+ DBUG_ASSERT(info->share);
+ copy_to_read_buffer(info, Buffer, old_pos_in_file);
- Count-=length;
- Buffer+=length;
- info->pos_in_file+=length;
- }
- memcpy(info->write_pos,Buffer,(size_t) Count);
- info->write_pos+=Count;
return 0;
}
@@ -1597,7 +1680,7 @@ int _my_b_write(register IO_CACHE *info, const uchar *Buffer, size_t Count)
the write buffer before we are ready with it.
*/
-int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
+int my_b_append(IO_CACHE *info, const uchar *Buffer, size_t Count)
{
size_t rest_length,length;
@@ -1606,6 +1689,7 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
day, we might need to add a call to copy_to_read_buffer().
*/
DBUG_ASSERT(!info->share);
+ DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
lock_append_buffer(info);
rest_length= (size_t) (info->write_end - info->write_pos);
@@ -1622,7 +1706,7 @@ int my_b_append(register IO_CACHE *info, const uchar *Buffer, size_t Count)
}
if (Count >= IO_SIZE)
{ /* Fill first intern buffer */
- length=Count & (size_t) ~(IO_SIZE-1);
+ length= IO_ROUND_DN(Count);
if (mysql_file_write(info->file,Buffer, length, info->myflags | MY_NABP))
{
unlock_append_buffer(info);
@@ -1661,7 +1745,7 @@ int my_b_safe_write(IO_CACHE *info, const uchar *Buffer, size_t Count)
we will never get a seek over the end of the buffer
*/
-int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
+int my_block_write(IO_CACHE *info, const uchar *Buffer, size_t Count,
my_off_t pos)
{
size_t length;
@@ -1672,6 +1756,7 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
day, we might need to add a call to copy_to_read_buffer().
*/
DBUG_ASSERT(!info->share);
+ DBUG_ASSERT(!(info->myflags & MY_ENCRYPT));
if (pos < info->pos_in_file)
{
@@ -1719,11 +1804,9 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
#define UNLOCK_APPEND_BUFFER if (need_append_buffer_lock) \
unlock_append_buffer(info);
-int my_b_flush_io_cache(IO_CACHE *info,
- int need_append_buffer_lock __attribute__((unused)))
+int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock)
{
size_t length;
- my_off_t pos_in_file;
my_bool append_cache= (info->type == SEQ_READ_APPEND);
DBUG_ENTER("my_b_flush_io_cache");
DBUG_PRINT("enter", ("cache: 0x%lx", (long) info));
@@ -1742,52 +1825,30 @@ int my_b_flush_io_cache(IO_CACHE *info,
if ((length=(size_t) (info->write_pos - info->write_buffer)))
{
- /*
- In case of a shared I/O cache with a writer we do direct write
- cache to read cache copy. Do it before the write here so that
- the readers can work in parallel with the write.
- copy_to_read_buffer() relies on info->pos_in_file.
- */
- if (info->share)
- copy_to_read_buffer(info, info->write_buffer, length);
-
- pos_in_file=info->pos_in_file;
- /*
- If we have append cache, we always open the file with
- O_APPEND which moves the pos to EOF automatically on every write
- */
- if (!append_cache && info->seek_not_done)
- { /* File touched, do seek */
- if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(info->myflags & MY_WME)) ==
- MY_FILEPOS_ERROR)
- {
- UNLOCK_APPEND_BUFFER;
- DBUG_RETURN((info->error= -1));
- }
- if (!append_cache)
- info->seek_not_done=0;
- }
- if (!append_cache)
- info->pos_in_file+=length;
- info->write_end= (info->write_buffer+info->buffer_length-
- ((pos_in_file+length) & (IO_SIZE-1)));
-
- if (mysql_file_write(info->file,info->write_buffer,length,
- info->myflags | MY_NABP))
- info->error= -1;
- else
- info->error= 0;
- if (!append_cache)
+ if (append_cache)
{
- set_if_bigger(info->end_of_file,(pos_in_file+length));
+
+ if (mysql_file_write(info->file, info->write_buffer, length,
+ info->myflags | MY_NABP))
+ info->error= -1;
+ else
+ info->error= 0;
+
+ info->end_of_file+= info->write_pos - info->append_read_pos;
+ info->append_read_pos= info->write_buffer;
+ DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0)));
}
else
{
- info->end_of_file+=(info->write_pos-info->append_read_pos);
- DBUG_ASSERT(info->end_of_file == mysql_file_tell(info->file, MYF(0)));
- }
+ int res= info->write_function(info, info->write_buffer, length);
+ if (res)
+ DBUG_RETURN(res);
- info->append_read_pos=info->write_pos=info->write_buffer;
+ set_if_bigger(info->end_of_file, info->pos_in_file);
+ }
+ info->write_end= (info->write_buffer + info->buffer_length -
+ ((info->pos_in_file + length) & (IO_SIZE - 1)));
+ info->write_pos= info->write_buffer;
++info->disk_writes;
UNLOCK_APPEND_BUFFER;
DBUG_RETURN(info->error);
@@ -1824,7 +1885,6 @@ int my_b_flush_io_cache(IO_CACHE *info,
int end_io_cache(IO_CACHE *info)
{
int error=0;
- IO_CACHE_CALLBACK pre_close;
DBUG_ENTER("end_io_cache");
DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info));
@@ -1834,11 +1894,6 @@ int end_io_cache(IO_CACHE *info)
*/
DBUG_ASSERT(!info->share || !info->share->total_threads);
- if ((pre_close=info->pre_close))
- {
- (*pre_close)(info);
- info->pre_close= 0;
- }
if (info->alloced_buffer)
{
info->alloced_buffer=0;
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index 9e693209445..2499094037d 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -61,7 +61,6 @@ my_b_copy_to_file(IO_CACHE *cache, FILE *file)
if (my_fwrite(file, cache->read_pos, bytes_in_cache,
MYF(MY_WME | MY_NABP)) == (size_t) -1)
DBUG_RETURN(1);
- cache->read_pos= cache->read_end;
} while ((bytes_in_cache= my_b_fill(cache)));
if(cache->error == -1)
DBUG_RETURN(1);
@@ -181,60 +180,19 @@ void my_b_seek(IO_CACHE *info,my_off_t pos)
DBUG_VOID_RETURN;
}
-
-/*
- Fill buffer of the cache.
-
- NOTES
- This assumes that you have already used all characters in the CACHE,
- independent of the read_pos value!
-
- RETURN
- 0 On error or EOF (info->error = -1 on error)
- # Number of characters
-*/
-
-
-size_t my_b_fill(IO_CACHE *info)
+int my_b_pread(IO_CACHE *info, uchar *Buffer, size_t Count, my_off_t pos)
{
- my_off_t pos_in_file=(info->pos_in_file+
- (size_t) (info->read_end - info->buffer));
- size_t diff_length, length, max_length;
-
- if (info->seek_not_done)
- { /* File touched, do seek */
- if (mysql_file_seek(info->file, pos_in_file, MY_SEEK_SET, MYF(0)) ==
- MY_FILEPOS_ERROR)
- {
- info->error= 0;
- return 0;
- }
- info->seek_not_done=0;
- }
- diff_length=(size_t) (pos_in_file & (IO_SIZE-1));
- max_length=(info->read_length-diff_length);
- if (max_length >= (info->end_of_file - pos_in_file))
- max_length= (size_t) (info->end_of_file - pos_in_file);
-
- if (!max_length)
- {
- info->error= 0;
- return 0; /* EOF */
- }
- DBUG_EXECUTE_IF ("simulate_my_b_fill_error",
- {DBUG_SET("+d,simulate_file_read_error");});
- if ((length= mysql_file_read(info->file, info->buffer, max_length,
- info->myflags)) == (size_t) -1)
+ if (info->myflags & MY_ENCRYPT)
{
- info->error= -1;
- return 0;
+ my_b_seek(info, pos);
+ return my_b_read(info, Buffer, Count);
}
- info->read_pos=info->buffer;
- info->read_end=info->buffer+length;
- info->pos_in_file=pos_in_file;
- return length;
-}
+ /* backward compatibility behavior. XXX remove it? */
+ if (mysql_file_pread(info->file, Buffer, Count, pos, info->myflags | MY_NABP))
+ return info->error= -1;
+ return 0;
+}
/*
Read a string ended by '\n' into a buffer of 'max_length' size.
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 0e7c43cc4c4..3263459bd72 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -4166,10 +4166,10 @@ restart:
if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
{
- BLOCK_LINK *last_for_update= NULL;
BLOCK_LINK *last_in_switch= NULL;
uint total_found= 0;
uint found;
+ last_for_update= NULL;
/*
Finally free all clean blocks for this file.
diff --git a/mysys/my_access.c b/mysys/my_access.c
index 68cd01d33e6..0da5e7f0bf0 100644
--- a/mysys/my_access.c
+++ b/mysys/my_access.c
@@ -173,6 +173,11 @@ static my_bool does_drive_exists(char drive_letter)
file names with a colon (:) are not allowed because such file names
store data in Alternate Data Streams which can be used to hide
the data.
+ Apart from colon, other characters that are not allowed in filenames
+ on Windows are greater/less sign, double quotes, forward slash, backslash,
+ pipe and star characters.
+
+ See MSDN documentation on filename restrictions.
@param name contains the file name with or without path
@param length contains the length of file name
@@ -181,6 +186,8 @@ static my_bool does_drive_exists(char drive_letter)
@return TRUE if the file name is allowed, FALSE otherwise.
*/
+#define ILLEGAL_FILENAME_CHARS "<>:\"/\|?*"
+
my_bool is_filename_allowed(const char *name __attribute__((unused)),
size_t length __attribute__((unused)),
my_bool allow_current_dir __attribute__((unused)))
@@ -205,6 +212,8 @@ my_bool is_filename_allowed(const char *name __attribute__((unused)),
return (allow_current_dir && (ch - name == 1) &&
does_drive_exists(*name));
}
+ else if (strchr(ILLEGAL_FILENAME_CHARS, *ch))
+ return FALSE;
}
return TRUE;
} /* is_filename_allowed */
diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c
index 90e6f43f390..72b04119855 100644
--- a/mysys/my_addr_resolve.c
+++ b/mysys/my_addr_resolve.c
@@ -126,41 +126,94 @@ err:
*/
#elif defined(MY_ADDR_RESOLVE_FORK)
/*
- yet another - just execute addr2line or eu-addr2line, whatever available,
- pipe the addresses to it, and parse the output
+ yet another - just execute addr2line pipe the addresses to it, and parse the
+ output
*/
#include <m_string.h>
#include <ctype.h>
+
+#if defined(HAVE_LINK_H) && defined(HAVE_DLOPEN)
+#include <link.h>
+static ptrdiff_t offset= 0;
+#else
+#define offset 0
+#endif
+
static int in[2], out[2];
static int initialized= 0;
static char output[1024];
int my_addr_resolve(void *ptr, my_addr_loc *loc)
{
- char input[32], *s;
+ char input[32];
size_t len;
- len= my_snprintf(input, sizeof(input), "%p\n", ptr);
+ ssize_t total_bytes_read = 0;
+ ssize_t extra_bytes_read = 0;
+
+ fd_set set;
+ struct timeval timeout;
+
+ int filename_start = -1;
+ int line_number_start = -1;
+ ssize_t i;
+
+ FD_ZERO(&set);
+ FD_SET(out[0], &set);
+
+ len= my_snprintf(input, sizeof(input), "%p\n", ptr - offset);
if (write(in[1], input, len) <= 0)
return 1;
- if (read(out[0], output, sizeof(output)) <= 0)
+
+ /* 10 ms should be plenty of time for addr2line to issue a response. */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ /* Read in a loop till all the output from addr2line is complete. */
+ while (select(out[0] + 1, &set, NULL, NULL, &timeout) > 0)
+ {
+ extra_bytes_read= read(out[0], output + total_bytes_read,
+ sizeof(output) - total_bytes_read);
+ if (extra_bytes_read < 0)
+ return 1;
+ /* Timeout or max bytes read. */
+ if (extra_bytes_read == 0)
+ break;
+
+ total_bytes_read += extra_bytes_read;
+ }
+
+ /* Failed starting addr2line. */
+ if (total_bytes_read == 0)
return 1;
- loc->func= s= output;
- while (*s != '\n')
- s++;
- *s++= 0;
- loc->file= s;
- while (*s != ':')
- s++;
- *s++= 0;
+ /* Go through the addr2line response and get the required data.
+ The response is structured in 2 lines. The first line contains the function
+ name, while the second one contains <filename>:<line number> */
+ for (i = 0; i < total_bytes_read; i++) {
+ if (output[i] == '\n') {
+ filename_start = i + 1;
+ output[i] = '\0';
+ }
+ if (filename_start != -1 && output[i] == ':') {
+ line_number_start = i + 1;
+ output[i] = '\0';
+ }
+ if (line_number_start != -1) {
+ loc->line= atoi(output + line_number_start);
+ break;
+ }
+ }
+ /* Response is malformed. */
+ if (filename_start == -1 || line_number_start == -1)
+ return 1;
+
+ loc->func= output;
+ loc->file= output + filename_start;
+
+ /* Addr2line was unable to extract any meaningful information. */
if (strcmp(loc->file, "??") == 0)
return 1;
- loc->line= 0;
- while (isdigit(*s))
- loc->line = loc->line * 10 + (*s++ - '0');
- *s = 0;
loc->file= strip_path(loc->file);
return 0;
@@ -172,6 +225,12 @@ const char *my_addr_resolve_init()
{
pid_t pid;
+#if defined(HAVE_LINK_H) && defined(HAVE_DLOPEN)
+ struct link_map *lm = (struct link_map*) dlopen(0, RTLD_NOW);
+ if (lm)
+ offset= lm->l_addr;
+#endif
+
if (pipe(in) < 0)
return "pipe(in)";
if (pipe(out) < 0)
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index fc30185eb5a..664a7380ca4 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;
@@ -104,6 +105,7 @@ void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
size_t pre_alloc_size __attribute__((unused)))
{
+ DBUG_ENTER("reset_root_defaults");
DBUG_ASSERT(alloc_root_inited(mem_root));
mem_root->block_size= (((block_size - ALLOC_ROOT_MIN_BLOCK_SIZE) & ~1) |
@@ -126,7 +128,7 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
{
/* We found a suitable block, no need to do anything else */
mem_root->pre_alloc= mem;
- return;
+ DBUG_VOID_RETURN;
}
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
{
@@ -156,6 +158,8 @@ void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
else
#endif
mem_root->pre_alloc= 0;
+
+ DBUG_VOID_RETURN;
}
@@ -164,7 +168,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 +192,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 +201,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 +260,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 +372,7 @@ void free_root(MEM_ROOT *root, myf MyFlags)
{
reg1 USED_MEM *next,*old;
DBUG_ENTER("free_root");
- DBUG_PRINT("enter",("root: 0x%lx flags: %u", (long) root, (uint) MyFlags));
+ DBUG_PRINT("enter",("root: %p flags: %u", root, (uint) MyFlags));
if (MyFlags & MY_MARK_BLOCKS_FREE)
{
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index 67c478659b5..0eaf1a88aa1 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -306,6 +306,12 @@ uint bitmap_set_next(MY_BITMAP *map)
}
+/**
+ Set the specified number of bits in the bitmap buffer.
+
+ @param map [IN] Bitmap
+ @param prefix_size [IN] Number of bits to be set
+*/
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
{
uint prefix_bytes, prefix_bits, d;
@@ -319,11 +325,12 @@ void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
m+= prefix_bytes;
if ((prefix_bits= prefix_size & 7))
{
- *m++= (1 << prefix_bits)-1;
- prefix_bytes++;
+ *(m++)= (1 << prefix_bits)-1;
+ // As the prefix bits are set, lets count this byte too as a prefix byte.
+ prefix_bytes ++;
}
if ((d= no_bytes_in_map(map)-prefix_bytes))
- bzero(m, d);
+ memset(m, 0, d);
}
@@ -373,6 +380,7 @@ my_bool bitmap_is_clear_all(const MY_BITMAP *map)
my_bitmap_map *data_ptr= map->bitmap;
my_bitmap_map *end= map->last_word_ptr;
+ DBUG_ASSERT(map->n_bits > 0);
for (; data_ptr < end; data_ptr++)
if (*data_ptr)
return FALSE;
diff --git a/mysys/my_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_create.c b/mysys/my_create.c
index 51de343d4a1..6a3bcd63557 100644
--- a/mysys/my_create.c
+++ b/mysys/my_create.c
@@ -43,7 +43,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
#if defined(_WIN32)
fd= my_win_open(FileName, access_flags | O_CREAT);
#else
- fd= open((char *) FileName, access_flags | O_CREAT,
+ fd= open((char *) FileName, access_flags | O_CREAT | O_CLOEXEC,
CreateFlags ? CreateFlags : my_umask);
#endif
diff --git a/mysys/my_default.c b/mysys/my_default.c
index 0f9b70ca326..7f41551f779 100644
--- a/mysys/my_default.c
+++ b/mysys/my_default.c
@@ -102,8 +102,7 @@ static const char *f_extensions[]= { ".cnf", 0 };
#define NEWLINE "\n"
#endif
-static int handle_default_option(void *in_ctx, const char *group_name,
- const char *option);
+static int handle_default_option(void *, const char *, const char *);
/*
This structure defines the context that we pass to callback
@@ -410,14 +409,13 @@ int get_defaults_options(int argc, char **argv,
char **extra_defaults,
char **group_suffix)
{
- int org_argc= argc, prev_argc= 0;
+ int org_argc= argc;
*defaults= *extra_defaults= *group_suffix= 0;
- while (argc >= 2 && argc != prev_argc)
+ while (argc >= 2)
{
/* Skip program name or previously handled argument */
argv++;
- prev_argc= argc; /* To check if we found */
if (!*defaults && is_prefix(*argv,"--defaults-file="))
{
*defaults= *argv + sizeof("--defaults-file=")-1;
@@ -436,6 +434,7 @@ int get_defaults_options(int argc, char **argv,
argc--;
continue;
}
+ break;
}
return org_argc - argc;
}
@@ -918,7 +917,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
end= remove_end_comment(ptr);
if ((value= strchr(ptr, '=')))
- end= value; /* Option without argument */
+ end= value;
for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
if (!value)
{
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index b6027a99c90..2ac033c8264 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -42,7 +42,7 @@ static void make_ftype(char * to,int flag);
FILE *my_fopen(const char *filename, int flags, myf MyFlags)
{
FILE *fd;
- char type[5];
+ char type[10];
DBUG_ENTER("my_fopen");
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %lu",
filename, flags, MyFlags));
@@ -87,8 +87,7 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
my_errno=errno;
DBUG_PRINT("error",("Got error %d on open",my_errno));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
- my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND :
- EE_CANTCREATEFILE,
+ my_error((flags & O_RDONLY) ? EE_FILENOTFOUND : EE_CANTCREATEFILE,
MYF(ME_BELL+ME_WAITTANG), filename, my_errno);
DBUG_RETURN((FILE*) 0);
} /* my_fopen */
@@ -351,9 +350,11 @@ static void make_ftype(register char * to, register int flag)
else
*to++= 'r';
-#if FILE_BINARY /* If we have binary-files */
if (flag & FILE_BINARY)
*to++='b';
-#endif
+
+ if (O_CLOEXEC)
+ *to++= 'e';
+
*to='\0';
} /* make_ftype */
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index 2a4557118b0..3f75f6553a2 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -47,16 +47,17 @@ static char *check_struct_option(char *cur_arg, char *key_name);
order of their arguments must correspond to each other.
*/
static const char *special_opt_prefix[]=
-{"skip", "disable", "enable", "maximum", "loose", 0};
+{"skip", "disable", "enable", "maximum", "loose", "autoset", 0};
static const uint special_opt_prefix_lengths[]=
-{ 4, 7, 6, 7, 5, 0};
+{ 4, 7, 6, 7, 5, 7, 0};
enum enum_special_opt
-{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE};
+{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE, OPT_AUTOSET};
char *disabled_my_option= (char*) "0";
char *enabled_my_option= (char*) "1";
+char *autoset_my_option= (char*) "auto";
-/*
+/*
This is a flag that can be set in client programs. 0 means that
my_getopt will not print error messages, but the client should do
it by itself
@@ -64,13 +65,21 @@ char *enabled_my_option= (char*) "1";
my_bool my_getopt_print_errors= 1;
-/*
+/*
This is a flag that can be set in client programs. 1 means that
my_getopt will skip over options it does not know how to handle.
*/
my_bool my_getopt_skip_unknown= 0;
+
+/*
+ This is a flag that can be set in client programs. 1 means that
+ my_getopt will reconize command line options by their unambiguous
+ prefixes. 0 means an option must be always specified in full.
+*/
+my_bool my_getopt_prefix_matching= 1;
+
static void default_reporter(enum loglevel level,
const char *format, ...)
{
@@ -190,7 +199,7 @@ int handle_options(int *argc, char ***argv,
{
uint UNINIT_VAR(opt_found), argvpos= 0, length;
my_bool end_of_options= 0, must_be_var, set_maximum_value,
- option_is_loose;
+ option_is_loose, option_is_autoset;
char **pos, **pos_end, *optend, *opt_str, key_name[FN_REFLEN];
const char *UNINIT_VAR(prev_found);
const struct my_option *optp;
@@ -241,6 +250,7 @@ int handle_options(int *argc, char ***argv,
must_be_var= 0;
set_maximum_value= 0;
option_is_loose= 0;
+ option_is_autoset= 0;
cur_arg++; /* skip '-' */
if (*cur_arg == '-') /* check for long option, */
@@ -289,6 +299,8 @@ int handle_options(int *argc, char ***argv,
length-= special_opt_prefix_lengths[i] + 1;
if (i == OPT_LOOSE)
option_is_loose= 1;
+ else if (i == OPT_AUTOSET)
+ option_is_autoset= 1;
if ((opt_found= findopt(opt_str, length, &optp, &prev_found)))
{
if (opt_found > 1)
@@ -450,6 +462,36 @@ int handle_options(int *argc, char ***argv,
}
argument= optend;
}
+ else if (option_is_autoset)
+ {
+ if (optend)
+ {
+ my_getopt_error_reporter(ERROR_LEVEL,
+ "%s: automatically set "
+ "option '--%s' cannot take an argument",
+ my_progname, optp->name);
+
+ DBUG_RETURN(EXIT_NO_ARGUMENT_ALLOWED);
+ }
+ /*
+ We support automatic setup only via get_one_option and only for
+ marked options.
+ */
+ if (!get_one_option ||
+ !(optp->var_type & GET_AUTO))
+ {
+ my_getopt_error_reporter(option_is_loose ?
+ WARNING_LEVEL : ERROR_LEVEL,
+ "%s: automatic setup request is "
+ "unsupported by option '--%s'",
+ my_progname, optp->name);
+ if (!option_is_loose)
+ DBUG_RETURN(EXIT_ARGUMENT_INVALID);
+ continue;
+ }
+ else
+ argument= autoset_my_option;
+ }
else if (optp->arg_type == REQUIRED_ARG && !optend)
{
/* Check if there are more arguments after this one,
@@ -577,7 +619,8 @@ int handle_options(int *argc, char ***argv,
(*argc)--; /* option handled (short), decrease argument count */
continue;
}
- if (((error= setval(optp, value, argument, set_maximum_value))) &&
+ if ((!option_is_autoset) &&
+ ((error= setval(optp, value, argument, set_maximum_value))) &&
!option_is_loose)
DBUG_RETURN(error);
if (get_one_option && get_one_option(optp->id, optp, argument))
@@ -851,6 +894,9 @@ static int findopt(char *optpat, uint length,
if (!opt->name[length]) /* Exact match */
DBUG_RETURN(1);
+ if (!my_getopt_prefix_matching)
+ continue;
+
if (!count)
{
/* We only need to know one prev */
@@ -867,6 +913,14 @@ static int findopt(char *optpat, uint length,
}
}
}
+
+ if (count == 1)
+ my_getopt_error_reporter(INFORMATION_LEVEL,
+ "Using unique option prefix '%.*s' is error-prone "
+ "and can break in the future. "
+ "Please use the full name '%s' instead.",
+ length, optpat, *ffname);
+
DBUG_RETURN(count);
}
@@ -1259,7 +1313,8 @@ void my_cleanup_options(const struct my_option *options)
SYNOPSIS
init_variables()
- options Array of options
+ options Array of options
+ func_init_one_value Call this function to init the variable
NOTES
We will initialize the value that is pointed to by options->value.
@@ -1268,7 +1323,7 @@ void my_cleanup_options(const struct my_option *options)
*/
static void init_variables(const struct my_option *options,
- init_func_p init_one_value)
+ init_func_p func_init_one_value)
{
DBUG_ENTER("init_variables");
for (; options->name; options++)
@@ -1281,11 +1336,11 @@ static void init_variables(const struct my_option *options,
set the value to default value.
*/
if (options->u_max_value)
- init_one_value(options, options->u_max_value, options->max_value);
+ func_init_one_value(options, options->u_max_value, options->max_value);
value= (options->var_type & GET_ASK_ADDR ?
(*getopt_get_addr)("", 0, options, 0) : options->value);
if (value)
- init_one_value(options, value, options->def_value);
+ func_init_one_value(options, value, options->def_value);
}
DBUG_VOID_RETURN;
}
@@ -1300,6 +1355,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 +1406,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 +1450,51 @@ void my_print_help(const struct my_option *options)
optp->arg_type == OPT_ARG ? "]" : "");
col+= (optp->arg_type == OPT_ARG) ? 5 : 3;
}
- if (col > name_space && optp->comment && *optp->comment)
- {
- putchar('\n');
- col= 0;
- }
}
- for (; col < name_space; col++)
- putchar(' ');
if (optp->comment && *optp->comment)
{
- const char *comment= optp->comment, *end= strend(comment);
+ uint count;
- while ((uint) (end - comment) > comment_space)
+ if (col > name_space)
{
- for (line_end= comment + comment_space; *line_end != ' '; line_end--);
- for (; comment != line_end; comment++)
- putchar(*comment);
- comment++; /* skip the space, as a newline will take it's place now */
putchar('\n');
- for (col= 0; col < name_space; col++)
- putchar(' ');
+ col= 0;
+ }
+
+ col= print_comment(optp->comment, col, name_space, comment_space);
+ if (optp->var_type & GET_AUTO)
+ {
+ col= print_comment(" (Automatically configured unless set explicitly)",
+ col, name_space, comment_space);
+ }
+
+ switch (optp->var_type & GET_TYPE_MASK) {
+ case GET_ENUM:
+ typelib_help= ". One of: ";
+ count= optp->typelib->count;
+ break;
+ case GET_SET:
+ typelib_help= ". Any combination of: ";
+ count= optp->typelib->count;
+ break;
+ case GET_FLAGSET:
+ typelib_help= ". Takes a comma-separated list of option=value pairs, "
+ "where value is on, off, or default, and options are: ";
+ count= optp->typelib->count - 1;
+ break;
+ }
+ if (typelib_help &&
+ strstr(optp->comment, optp->typelib->type_names[0]) == NULL)
+ {
+ uint i;
+ col= print_comment(typelib_help, col, name_space, comment_space);
+ col= print_comment(optp->typelib->type_names[0], col, name_space, comment_space);
+ for (i= 1; i < count; i++)
+ {
+ col= print_comment(", ", col, name_space, comment_space);
+ col= print_comment(optp->typelib->type_names[i], col, name_space, comment_space);
+ }
}
- printf("%s", comment);
}
putchar('\n');
if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
diff --git a/mysys/my_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/my_open.c b/mysys/my_open.c
index 5263ba4b5c8..b6d8f08bfc1 100644
--- a/mysys/my_open.c
+++ b/mysys/my_open.c
@@ -46,9 +46,9 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
#if defined(_WIN32)
fd= my_win_open(FileName, Flags);
#elif !defined(NO_OPEN_3)
- fd = open(FileName, Flags, my_umask); /* Normal unix */
+ fd = open(FileName, Flags | O_CLOEXEC, my_umask); /* Normal unix */
#else
- fd = open((char *) FileName, Flags);
+ fd = open((char *) FileName, Flags | O_CLOEXEC);
#endif
fd= my_register_filename(fd, FileName, FILE_BY_OPEN,
diff --git a/mysys/my_rdtsc.c b/mysys/my_rdtsc.c
index ad11e8c6a6c..4228973caa8 100644
--- a/mysys/my_rdtsc.c
+++ b/mysys/my_rdtsc.c
@@ -249,6 +249,13 @@ ulonglong my_timer_cycles(void)
clock_gettime(CLOCK_SGI_CYCLE, &tp);
return (ulonglong) tp.tv_sec * 1000000000 + (ulonglong) tp.tv_nsec;
}
+#elif defined(__GNUC__) && defined(__s390__)
+ /* covers both s390 and s390x */
+ {
+ ulonglong result;
+ __asm__ __volatile__ ("stck %0" : "=Q" (result) : : "cc");
+ return result;
+ }
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
/* gethrtime may appear as either cycle or nanosecond counter */
return (ulonglong) gethrtime();
@@ -558,6 +565,8 @@ void my_timer_init(MY_TIMER_INFO *mti)
mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC32;
#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE)
mti->cycles.routine= MY_TIMER_ROUTINE_SGI_CYCLE;
+#elif defined(__GNUC__) && defined(__s390__)
+ mti->cycles.routine= MY_TIMER_ROUTINE_ASM_S390;
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME;
#else
@@ -753,7 +762,6 @@ void my_timer_init(MY_TIMER_INFO *mti)
mti->cycles.frequency= mti->microseconds.frequency;
else
{
- ulonglong time1, time2;
time1= my_timer_init_frequency(mti);
/* Repeat once in case there was an interruption. */
time2= my_timer_init_frequency(mti);
@@ -775,8 +783,7 @@ void my_timer_init(MY_TIMER_INFO *mti)
&& mti->microseconds.routine
&& mti->cycles.routine)
{
- int i;
- ulonglong time1, time2, time3, time4;
+ ulonglong time3, time4;
time1= my_timer_cycles();
time2= my_timer_milliseconds();
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
@@ -801,8 +808,7 @@ void my_timer_init(MY_TIMER_INFO *mti)
&& mti->microseconds.routine
&& mti->cycles.routine)
{
- int i;
- ulonglong time1, time2, time3, time4;
+ ulonglong time3, time4;
time1= my_timer_cycles();
time2= my_timer_ticks();
time3= time2; /* Avoids a Microsoft/IBM compiler warning */
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index 9c6855bb92f..d080aca7404 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -13,8 +13,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+#ifndef MYSYS_PRIV_INCLUDED
+#define MYSYS_PRIV_INCLUDED
+
#include <my_global.h>
#include <my_sys.h>
+#include <my_crypt.h>
+
+C_MODE_START
#ifdef USE_SYSTEM_WRAPPERS
#include "system_wrappers.h"
@@ -42,16 +48,16 @@ extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_THR_LOCK_lock, key_THR_LOCK_malloc,
key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
key_THR_LOCK_open, key_THR_LOCK_threads, key_LOCK_uuid_generator,
- key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
+ key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap, key_LOCK_timer;
-extern PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond,
+extern PSI_cond_key key_COND_alarm, key_COND_timer, key_IO_CACHE_SHARE_cond,
key_IO_CACHE_SHARE_cond_writer, key_my_thread_var_suspend,
key_THR_COND_threads;
#ifdef USE_ALARM_THREAD
extern PSI_thread_key key_thread_alarm;
#endif /* USE_ALARM_THREAD */
-
+extern PSI_thread_key key_thread_timer;
extern PSI_rwlock_key key_SAFEHASH_mutex;
#endif /* HAVE_PSI_INTERFACE */
@@ -71,6 +77,16 @@ extern PSI_file_key key_file_proc_meminfo;
extern PSI_file_key key_file_charset, key_file_cnf;
#endif /* HAVE_PSI_INTERFACE */
+typedef struct {
+ ulonglong counter;
+ uint block_length, last_block_length;
+ uchar key[MY_AES_BLOCK_SIZE];
+ ulonglong inbuf_counter;
+} IO_CACHE_CRYPT;
+
+extern int (*_my_b_encr_read)(IO_CACHE *info,uchar *Buffer,size_t Count);
+extern int (*_my_b_encr_write)(IO_CACHE *info,const uchar *Buffer,size_t Count);
+
#ifdef SAFEMALLOC
void *sf_malloc(size_t size, myf my_flags);
void *sf_realloc(void *ptr, size_t size, myf my_flags);
@@ -116,3 +132,7 @@ extern File my_win_dup(File fd);
extern File my_win_sopen(const char *path, int oflag, int shflag, int perm);
extern File my_open_osfhandle(HANDLE handle, int oflag);
#endif
+
+C_MODE_END
+
+#endif
diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c
index 6e373e98972..6d853a8db25 100644
--- a/mysys/ptr_cmp.c
+++ b/mysys/ptr_cmp.c
@@ -88,8 +88,8 @@ qsort2_cmp get_ptr_compare (size_t size)
static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
{
- reg3 int length= *compare_length;
- reg1 uchar *first,*last;
+ size_t length= *compare_length;
+ uchar *first,*last;
DBUG_ASSERT(length > 0);
first= *a; last= *b;
@@ -104,8 +104,8 @@ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b)
{
- reg3 int length= *compare_length;
- reg1 uchar *first,*last;
+ size_t length= *compare_length;
+ uchar *first,*last;
first= *a; last= *b;
loop:
@@ -125,8 +125,8 @@ static int ptr_compare_0(size_t *compare_length,uchar **a, uchar **b)
static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b)
{
- reg3 int length= *compare_length-1;
- reg1 uchar *first,*last;
+ size_t length= *compare_length-1;
+ uchar *first,*last;
first= *a+1; last= *b+1;
cmp(-1);
@@ -146,8 +146,8 @@ static int ptr_compare_1(size_t *compare_length,uchar **a, uchar **b)
static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b)
{
- reg3 int length= *compare_length-2;
- reg1 uchar *first,*last;
+ size_t length= *compare_length-2;
+ uchar *first,*last;
first= *a +2 ; last= *b +2;
cmp(-2);
@@ -168,8 +168,8 @@ static int ptr_compare_2(size_t *compare_length,uchar **a, uchar **b)
static int ptr_compare_3(size_t *compare_length,uchar **a, uchar **b)
{
- reg3 int length= *compare_length-3;
- reg1 uchar *first,*last;
+ size_t length= *compare_length-3;
+ uchar *first,*last;
first= *a +3 ; last= *b +3;
cmp(-3);
diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c
index 746b99d6112..395659238b3 100644
--- a/mysys/stacktrace.c
+++ b/mysys/stacktrace.c
@@ -336,12 +336,11 @@ inline uint32* find_prev_pc(uint32* pc, uchar** fp)
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack)
{
- uchar** fp;
+ uchar** UNINIT_VAR(fp);
uint frame_count = 0, sigreturn_frame_count;
#if defined(__alpha__) && defined(__GNUC__)
uint32* pc;
#endif
- LINT_INIT(fp);
#ifdef __i386__
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 8dce58dd58a..8990cbd5a14 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -95,6 +95,24 @@ my_bool thr_lock_inited=0;
ulong locks_immediate = 0L, locks_waited = 0L;
enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
+#ifdef WITH_WSREP
+static wsrep_thd_is_brute_force_fun wsrep_thd_is_brute_force= NULL;
+static wsrep_abort_thd_fun wsrep_abort_thd= NULL;
+static my_bool wsrep_debug;
+static my_bool wsrep_convert_LOCK_to_trx;
+static wsrep_on_fun wsrep_on = NULL;
+
+void wsrep_thr_lock_init(
+ wsrep_thd_is_brute_force_fun bf_fun, wsrep_abort_thd_fun abort_fun,
+ my_bool debug, my_bool convert_LOCK_to_trx, wsrep_on_fun on_fun
+) {
+ wsrep_thd_is_brute_force = bf_fun;
+ wsrep_abort_thd = abort_fun;
+ wsrep_debug = debug;
+ wsrep_convert_LOCK_to_trx= convert_LOCK_to_trx;
+ wsrep_on = on_fun;
+}
+#endif
/* The following constants are only for debug output */
#define MAX_THREADS 1000
#define MAX_LOCKS 1000
@@ -327,15 +345,14 @@ static void check_locks(THR_LOCK *lock, const char *where,
"Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
DBUG_PRINT("warning", ("Warning at '%s': Write lock %d waiting while no exclusive read locks",where,(int) lock->write_wait.data->type));
}
- }
+ }
}
else
{
/* We have at least one write lock */
if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
{
- THR_LOCK_DATA *data;
- uint count= 0;
+ count= 0;
for (data=lock->write.data->next;
data && count < MAX_LOCKS;
data=data->next)
@@ -368,7 +385,6 @@ static void check_locks(THR_LOCK *lock, const char *where,
}
if (lock->read.data)
{
- THR_LOCK_DATA *data;
for (data=lock->read.data ; data ; data=data->next)
{
if (!thr_lock_owner_equal(lock->write.data->owner,
@@ -646,6 +662,92 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
DBUG_RETURN(result);
}
+#ifdef WITH_WSREP
+/*
+ * If brute force applier would need to wait for a thr lock,
+ * it needs to make sure that it will get the lock without (too much)
+ * delay.
+ * We identify here the owners of blocking locks and ask them to
+ * abort. We then put our lock request in the first place in the
+ * wait queue. When lock holders abort (one by one) the lock release
+ * algorithm should grant the lock to us. We rely on this and proceed
+ * to wait_for_locks().
+ * wsrep_break_locks() should be called in all the cases, where lock
+ * wait would happen.
+ *
+ * TODO: current implementation might not cover all possible lock wait
+ * situations. This needs an review still.
+ * TODO: lock release, might favor some other lock (instead our bf).
+ * This needs an condition to check for bf locks first.
+ * TODO: we still have a debug fprintf, this should be removed
+ */
+static my_bool
+wsrep_break_lock(
+ THR_LOCK_DATA *data, struct st_lock_list *lock_queue1,
+ struct st_lock_list *wait_queue)
+{
+ if (wsrep_on && wsrep_on(data->owner->mysql_thd) &&
+ wsrep_thd_is_brute_force &&
+ wsrep_thd_is_brute_force(data->owner->mysql_thd, TRUE))
+ {
+ THR_LOCK_DATA *holder;
+
+ /* if locking session conversion to transaction has been enabled,
+ we know that this conflicting lock must be read lock and furthermore,
+ lock holder is read-only. It is safe to wait for him.
+ */
+#ifdef TODO_WHEN_LOCK_TABLES_IS_A_TRANSACTION
+ if (wsrep_convert_LOCK_to_trx &&
+ (THD*)(data->owner->mysql_thd)->in_lock_tables)
+ {
+ if (wsrep_debug)
+ fprintf(stderr,"WSREP wsrep_break_lock read lock untouched\n");
+ return FALSE;
+ }
+#endif
+ if (wsrep_debug)
+ fprintf(stderr,"WSREP wsrep_break_lock aborting locks\n");
+
+ /* aborting lock holder(s) here */
+ for (holder=(lock_queue1) ? lock_queue1->data : NULL;
+ holder;
+ holder=holder->next)
+ {
+ if (!wsrep_thd_is_brute_force(holder->owner->mysql_thd, TRUE))
+ {
+ wsrep_abort_thd(data->owner->mysql_thd,
+ holder->owner->mysql_thd, FALSE);
+ }
+ else
+ {
+ if (wsrep_debug)
+ fprintf(stderr,"WSREP wsrep_break_lock skipping BF lock conflict\n");
+ return FALSE;
+ }
+ }
+
+ /* Add our lock to the head of the wait queue */
+ if (*(wait_queue->last)==wait_queue->data)
+ {
+ wait_queue->last=&data->next;
+ assert(wait_queue->data==0);
+ }
+ else
+ {
+ assert(wait_queue->data!=0);
+ wait_queue->data->prev=&data->next;
+ }
+ data->next=wait_queue->data;
+ data->prev=&wait_queue->data;
+ wait_queue->data=data;
+ data->cond=get_cond();
+
+ statistic_increment(locks_immediate,&THR_LOCK_lock);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
static enum enum_thr_lock_result
thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
@@ -654,6 +756,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
struct st_lock_list *wait_queue;
enum thr_lock_type lock_type= data->type;
+#ifdef WITH_WSREP
+ my_bool wsrep_lock_inserted= FALSE;
+#endif
MYSQL_TABLE_WAIT_VARIABLES(locker, state) /* no ';' */
DBUG_ENTER("thr_lock");
@@ -750,6 +855,13 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
lock but a high priority write waiting in the write_wait queue.
In the latter case we should yield the lock to the writer.
*/
+#ifdef WITH_WSREP
+ if (wsrep_break_lock(data, &lock->write, &lock->read_wait))
+ {
+ wsrep_lock_inserted= TRUE;
+ }
+#endif
+
wait_queue= &lock->read_wait;
}
else /* Request for WRITE lock */
@@ -894,9 +1006,20 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, ulong lock_wait_timeout)
DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d",
lock->read.data->owner->thread_id, data->type));
}
+#ifdef WITH_WSREP
+ if (wsrep_break_lock(data, &lock->write, &lock->write_wait))
+ {
+ wsrep_lock_inserted= TRUE;
+ }
+#endif
+
wait_queue= &lock->write_wait;
}
/* Can't get lock yet; Wait for it */
+#ifdef WITH_WSREP
+ if (wsrep_lock_inserted && wsrep_on(data->owner->mysql_thd))
+ DBUG_RETURN(wait_for_lock(wait_queue, data, 1, lock_wait_timeout));
+#endif
result= wait_for_lock(wait_queue, data, 0, lock_wait_timeout);
MYSQL_END_TABLE_LOCK_WAIT(locker);
DBUG_RETURN(result);
diff --git a/mysys/thr_timer.c b/mysys/thr_timer.c
new file mode 100644
index 00000000000..b8726617f44
--- /dev/null
+++ b/mysys/thr_timer.c
@@ -0,0 +1,570 @@
+/*
+ Copyright (c) 2012 Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 or later of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+/*
+ Implementation if OS independent timers.
+ This is done based on pthread primitives, especially pthread_cond_timedwait()
+*/
+
+#include "mysys_priv.h"
+#include "thr_timer.h"
+#include <m_string.h>
+#include <queues.h>
+#ifdef HAVE_TIMER_CREATE
+#include <sys/syscall.h>
+#endif
+
+struct timespec next_timer_expire_time;
+
+static my_bool thr_timer_inited= 0;
+static mysql_mutex_t LOCK_timer;
+static mysql_cond_t COND_timer;
+static QUEUE timer_queue;
+pthread_t timer_thread;
+
+#define set_max_time(abs_time) \
+ { (abs_time)->MY_tv_sec= INT_MAX32; (abs_time)->MY_tv_nsec= 0; }
+
+
+static void *timer_handler(void *arg __attribute__((unused)));
+
+/*
+ Compare two timespecs
+*/
+
+static int compare_timespec(void *not_used __attribute__((unused)),
+ uchar *a_ptr, uchar *b_ptr)
+{
+ return cmp_timespec((*(struct timespec*) a_ptr),
+ (*(struct timespec*) b_ptr));
+}
+
+
+/**
+ Initialize timer variables and create timer thread
+
+ @param alloc_timers Init allocation of timers. Will be autoextended
+ if needed
+ @return 0 ok
+ @return 1 error; Can't create thread
+*/
+
+static thr_timer_t max_timer_data;
+
+my_bool init_thr_timer(uint alloc_timers)
+{
+ pthread_attr_t thr_attr;
+ my_bool res= 0;
+ DBUG_ENTER("init_thr_timer");
+
+ init_queue(&timer_queue, alloc_timers+2, offsetof(thr_timer_t,expire_time),
+ 0, compare_timespec, NullS,
+ offsetof(thr_timer_t, index_in_queue)+1, 1);
+ mysql_mutex_init(key_LOCK_timer, &LOCK_timer, MY_MUTEX_INIT_FAST);
+ mysql_cond_init(key_COND_timer, &COND_timer, NULL);
+
+ /* Set dummy element with max time into the queue to simplify usage */
+ bzero(&max_timer_data, sizeof(max_timer_data));
+ set_max_time(&max_timer_data.expire_time);
+ queue_insert(&timer_queue, (uchar*) &max_timer_data);
+ next_timer_expire_time= max_timer_data.expire_time;
+
+ /* Create a thread to handle timers */
+ pthread_attr_init(&thr_attr);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setstacksize(&thr_attr,8196);
+ thr_timer_inited= 1;
+ if (mysql_thread_create(key_thread_timer, &timer_thread, &thr_attr,
+ timer_handler, NULL))
+ {
+ thr_timer_inited= 0;
+ res= 1;
+ mysql_mutex_destroy(&LOCK_timer);
+ mysql_cond_destroy(&COND_timer);
+ delete_queue(&timer_queue);
+ }
+ pthread_attr_destroy(&thr_attr);
+
+ DBUG_RETURN(res);
+}
+
+
+void end_thr_timer(void)
+{
+ DBUG_ENTER("end_thr_timer");
+
+ if (!thr_timer_inited)
+ DBUG_VOID_RETURN;
+
+ mysql_mutex_lock(&LOCK_timer);
+ thr_timer_inited= 0; /* Signal abort */
+ mysql_cond_signal(&COND_timer);
+ mysql_mutex_unlock(&LOCK_timer);
+ pthread_join(timer_thread, NULL);
+
+ mysql_mutex_destroy(&LOCK_timer);
+ mysql_cond_destroy(&COND_timer);
+ delete_queue(&timer_queue);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Initialize a timer object
+
+ @param timer_data Timer structure
+ @param function Function to be called when getting timeout
+ @param argument Argument for function
+*/
+
+void thr_timer_init(thr_timer_t *timer_data, void(*function)(void*),
+ void *arg)
+{
+ DBUG_ENTER("thr_timer_init");
+ bzero(timer_data, sizeof(*timer_data));
+ timer_data->func= function;
+ timer_data->func_arg= arg;
+ timer_data->expired= 1; /* Not active */
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Request timer after X milliseconds
+
+ SYNOPSIS
+ thr_timer()
+ timer_data Pointer to timer structure
+ micro_seconds; Number of microseconds until timer
+
+ RETURN VALUES
+ 0 ok
+ 1 If no more timers are allowed (aborted by process)
+
+ Stores in first argument a pointer to a non-zero int which is set to 0
+ when the timer has been given
+*/
+
+my_bool thr_timer_settime(thr_timer_t *timer_data, ulonglong micro_seconds)
+{
+ int reschedule;
+ DBUG_ENTER("thr_timer_settime");
+ DBUG_PRINT("enter",("thread: %s micro_seconds: %llu",my_thread_name(),
+ micro_seconds));
+
+ DBUG_ASSERT(timer_data->expired == 1);
+
+ set_timespec_nsec(timer_data->expire_time, micro_seconds*1000);
+ timer_data->expired= 0;
+
+ mysql_mutex_lock(&LOCK_timer); /* Lock from threads & timers */
+ if (queue_insert_safe(&timer_queue,(uchar*) timer_data))
+ {
+ DBUG_PRINT("info", ("timer queue full"));
+ fprintf(stderr,"Warning: thr_timer queue is full\n");
+ timer_data->expired= 1;
+ mysql_mutex_unlock(&LOCK_timer);
+ DBUG_RETURN(1);
+ }
+
+ /* Reschedule timer if the current one has more time left than new one */
+ reschedule= cmp_timespec(next_timer_expire_time, timer_data->expire_time);
+ mysql_mutex_unlock(&LOCK_timer);
+ if (reschedule > 0)
+ {
+#if defined(MAIN)
+ printf("reschedule\n"); fflush(stdout);
+#endif
+ DBUG_PRINT("info", ("reschedule"));
+ mysql_cond_signal(&COND_timer);
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Remove timer from list of timers
+
+ notes: Timer will be marked as expired
+*/
+
+void thr_timer_end(thr_timer_t *timer_data)
+{
+ DBUG_ENTER("thr_timer_end");
+
+ mysql_mutex_lock(&LOCK_timer);
+ if (!timer_data->expired)
+ {
+ DBUG_ASSERT(timer_data->index_in_queue != 0);
+ DBUG_ASSERT(queue_element(&timer_queue, timer_data->index_in_queue) ==
+ (uchar*) timer_data);
+ queue_remove(&timer_queue, timer_data->index_in_queue);
+ /* Mark as expired for asserts to work */
+ timer_data->expired= 1;
+ }
+ mysql_mutex_unlock(&LOCK_timer);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Come here when some timer in queue is due.
+*/
+
+static sig_handler process_timers(struct timespec *now)
+{
+ thr_timer_t *timer_data;
+ DBUG_ENTER("process_timers");
+ DBUG_PRINT("info",("active timers: %d", timer_queue.elements - 1));
+
+#if defined(MAIN)
+ printf("process_timer\n"); fflush(stdout);
+#endif
+
+ /* We can safely remove the first one as it has already expired */
+ for (;;)
+ {
+ void (*function)(void*);
+ void *func_arg;
+
+ timer_data= (thr_timer_t*) queue_top(&timer_queue);
+ function= timer_data->func;
+ func_arg= timer_data->func_arg;
+ timer_data->expired= 1; /* Mark expired */
+ /*
+ We remove timer before calling timer function to allow thread to
+ delete it's timer data any time.
+ */
+ queue_remove_top(&timer_queue); /* Remove timer */
+ (*function)(func_arg); /* Inform thread of timeout */
+
+ /* Check if next one has also expired */
+ timer_data= (thr_timer_t*) queue_top(&timer_queue);
+ if (cmp_timespec(timer_data->expire_time, (*now)) > 0)
+ break; /* All data processed */
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ set up a timer thread to handle timeouts
+ This will be killed when thr_timer_inited is set to false.
+*/
+
+static void *timer_handler(void *arg __attribute__((unused)))
+{
+ my_thread_init();
+
+ mysql_mutex_lock(&LOCK_timer);
+ while (likely(thr_timer_inited))
+ {
+ int error;
+ struct timespec *top_time;
+ struct timespec now, abstime;
+
+ set_timespec(now, 0);
+
+ top_time= &(((thr_timer_t*) queue_top(&timer_queue))->expire_time);
+
+ if (cmp_timespec((*top_time), now) <= 0)
+ {
+ process_timers(&now);
+ top_time= &(((thr_timer_t*) queue_top(&timer_queue))->expire_time);
+ }
+
+ abstime= *top_time;
+ next_timer_expire_time= *top_time;
+ if ((error= mysql_cond_timedwait(&COND_timer, &LOCK_timer, &abstime)) &&
+ error != ETIME && error != ETIMEDOUT)
+ {
+#ifdef MAIN
+ printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n",
+ error,errno);
+#endif
+ }
+ }
+ mysql_mutex_unlock(&LOCK_timer);
+ my_thread_end();
+ pthread_exit(0);
+ return 0; /* Impossible */
+}
+
+
+/****************************************************************************
+ Testing of thr_timer (when compiled with -DMAIN)
+***************************************************************************/
+
+#ifdef MAIN
+
+static mysql_cond_t COND_thread_count;
+static mysql_mutex_t LOCK_thread_count;
+static uint thread_count, benchmark_runs, test_to_run= 1;
+
+static void send_signal(void *arg)
+{
+ struct st_my_thread_var *current_my_thread_var= arg;
+#if defined(MAIN)
+ printf("sending signal\n"); fflush(stdout);
+#endif
+ mysql_mutex_lock(&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..ae0ffe7f7eb 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
@@ -260,11 +253,7 @@ struct st_wt_resource {
#ifndef DBUG_OFF
mysql_mutex_t *cond_mutex; /* a mutex for the 'cond' below */
#endif
- /*
- before the 'lock' all elements are mutable, after (and including) -
- immutable in the sense that lf_hash_insert() won't memcpy() over them.
- See wt_init().
- */
+
#ifdef WT_RWLOCKS_USE_MUTEXES
/*
we need a special rwlock-like 'lock' to allow readers bypass
@@ -396,10 +385,10 @@ static LF_HASH reshash;
It's called from lf_hash and takes a pointer to an LF_SLIST instance.
WT_RESOURCE is located at arg+sizeof(LF_SLIST)
*/
-static void wt_resource_init(uchar *arg)
+static void wt_resource_create(uchar *arg)
{
WT_RESOURCE *rc= (WT_RESOURCE*)(arg+LF_HASH_OVERHEAD);
- DBUG_ENTER("wt_resource_init");
+ DBUG_ENTER("wt_resource_create");
bzero(rc, sizeof(*rc));
rc_rwlock_init(rc);
@@ -426,25 +415,37 @@ static void wt_resource_destroy(uchar *arg)
DBUG_VOID_RETURN;
}
+/**
+ WT_RESOURCE initializer
+
+ It's called from lf_hash when an element is inserted.
+*/
+static void wt_resource_init(LF_HASH *hash __attribute__((unused)),
+ WT_RESOURCE *rc, WT_RESOURCE_ID *id)
+{
+ DBUG_ENTER("wt_resource_init");
+ rc->id= *id;
+ rc->waiter_count= 0;
+ rc->state= ACTIVE;
+#ifndef DBUG_OFF
+ rc->cond_mutex= 0;
+#endif
+ DBUG_VOID_RETURN;
+}
+
static int wt_init_done;
void wt_init()
{
DBUG_ENTER("wt_init");
- DBUG_ASSERT(reshash.alloc.constructor != wt_resource_init);
+ DBUG_ASSERT(reshash.alloc.constructor != wt_resource_create);
lf_hash_init(&reshash, sizeof(WT_RESOURCE), LF_HASH_UNIQUE, 0,
sizeof_WT_RESOURCE_ID, 0, 0);
- reshash.alloc.constructor= wt_resource_init;
+ reshash.alloc.constructor= wt_resource_create;
reshash.alloc.destructor= wt_resource_destroy;
- /*
- Note a trick: we initialize the hash with the real element size,
- but fix it later to a shortened element size. This way
- the allocator will allocate elements correctly, but
- lf_hash_insert() will only overwrite part of the element with memcpy().
- lock, condition, and dynamic array will be intact.
- */
- reshash.element_size= offsetof(WT_RESOURCE, lock);
+ reshash.initializer= (lf_hash_initializer) wt_resource_init;
+
bzero(wt_wait_stats, sizeof(wt_wait_stats));
bzero(wt_cycle_stats, sizeof(wt_cycle_stats));
wt_success_stats= 0;
@@ -458,9 +459,6 @@ void wt_init()
DBUG_ASSERT(i == 0 || wt_wait_table[i-1] != wt_wait_table[i]);
}
}
- my_atomic_rwlock_init(&cycle_stats_lock);
- my_atomic_rwlock_init(&success_stats_lock);
- my_atomic_rwlock_init(&wait_stats_lock);
wt_init_done= 1;
DBUG_VOID_RETURN;
}
@@ -473,9 +471,6 @@ void wt_end()
DBUG_ASSERT(reshash.count == 0);
lf_hash_destroy(&reshash);
- my_atomic_rwlock_destroy(&cycle_stats_lock);
- my_atomic_rwlock_destroy(&success_stats_lock);
- my_atomic_rwlock_destroy(&wait_stats_lock);
reshash.alloc.constructor= NULL;
wt_init_done= 0;
DBUG_VOID_RETURN;
@@ -943,14 +938,9 @@ int wt_thd_will_wait_for(WT_THD *thd, WT_THD *blocker,
retry:
while ((rc= lf_hash_search(&reshash, thd->pins, key, keylen)) == 0)
{
- WT_RESOURCE tmp;
-
DBUG_PRINT("wt", ("failed to find rc in hash, inserting"));
- bzero(&tmp, sizeof(tmp));
- tmp.id= *resid;
- tmp.state= ACTIVE;
- if (lf_hash_insert(&reshash, thd->pins, &tmp) == -1) /* if OOM */
+ if (lf_hash_insert(&reshash, thd->pins, resid) == -1) /* if OOM */
DBUG_RETURN(WT_DEADLOCK);
/*
Two cases: either lf_hash_insert() failed - because another thread