diff options
author | Vladislav Vaintroub <wlad@montyprogram.com> | 2013-07-09 22:24:57 +0200 |
---|---|---|
committer | Vladislav Vaintroub <wlad@montyprogram.com> | 2013-07-09 22:24:57 +0200 |
commit | 6bef652d91b9dc78af4794a87edfd760503d6d6d (patch) | |
tree | a8e7e56681b1097ad7421c81ae0ef443da897eab | |
parent | 762d3cb8ede0b46f101f045d862ebb64f9148771 (diff) | |
download | mariadb-git-6bef652d91b9dc78af4794a87edfd760503d6d6d.tar.gz |
MDEV-4409 - Fix deadlock in MySQL key cache code, that can happen if there is a key cache resize running in parallel with an update.
If there is a key cache resize,a thread writing to key cache, will pause waiting until resize finishes. However this thread is won't be woken, because resize does not signaling waiters anymore. This is a regression introduced in WL#86(segmented MyISAM key cache)
The fix is to unconditionally release threads waiting on resize_queue when resize finishes, as in pre-WL#86 code.
-rw-r--r-- | mysys/mf_keycache.c | 37 |
1 files changed, 14 insertions, 23 deletions
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index dc2d7fdd127..cccf6b52d9a 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -651,8 +651,7 @@ err: SYNOPSIS prepare_resize_simple_key_cache() - keycache pointer to the control block of a simple key cache - with_resize_queue <=> resize queue is used + keycache pointer to the control block of a simple key cache release_lock <=> release the key cache lock before return DESCRIPTION @@ -660,10 +659,8 @@ err: this it destroys the key cache calling end_simple_key_cache. The function takes the parameter keycache as a pointer to the control block structure of the type SIMPLE_KEY_CACHE_CB for this key cache. - The parameter with_resize_queue determines weather the resize queue is - involved (MySQL server never uses this queue). The parameter release_lock - says weather the key cache lock must be released before return from - the function. + The parameter release_lock says whether the key cache lock must be + released before return from the function. RETURN VALUE 0 - on success, @@ -677,7 +674,6 @@ err: static int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, - my_bool with_resize_queue, my_bool release_lock) { int res= 0; @@ -692,7 +688,7 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, one resizer only. In set_var.cc keycache->in_init is used to block multiple attempts. */ - while (with_resize_queue && keycache->in_resize) + while (keycache->in_resize) { /* purecov: begin inspected */ wait_on_queue(&keycache->resize_queue, &keycache->cache_lock); @@ -759,8 +755,7 @@ finish: SYNOPSIS finish_resize_simple_key_cache() - keycache pointer to the control block of a simple key cache - with_resize_queue <=> resize queue is used + keycache pointer to the control block of a simple key cache acquire_lock <=> acquire the key cache lock at start DESCRIPTION @@ -769,9 +764,7 @@ finish: keycache as a pointer to the control block structure of the type SIMPLE_KEY_CACHE_CB for this key cache. The function sets the flag in_resize in this structure to FALSE. - The parameter with_resize_queue determines weather the resize queue - is involved (MySQL server never uses this queue). - The parameter acquire_lock says weather the key cache lock must be + The parameter acquire_lock says whether the key cache lock must be acquired at the start of the function. RETURN VALUE @@ -785,7 +778,6 @@ finish: static void finish_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, - my_bool with_resize_queue, my_bool acquire_lock) { DBUG_ENTER("finish_resize_simple_key_cache"); @@ -801,11 +793,10 @@ void finish_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, */ keycache->in_resize= 0; - if (with_resize_queue) - { - /* Signal waiting threads. */ - release_whole_queue(&keycache->resize_queue); - } + + /* Signal waiting threads. */ + release_whole_queue(&keycache->resize_queue); + keycache_pthread_mutex_unlock(&keycache->cache_lock); @@ -872,7 +863,7 @@ int resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, uint key_cache_block_ We do not lose the cache_lock and will release it only at the end of this function. */ - if (prepare_resize_simple_key_cache(keycache, 1, 0)) + if (prepare_resize_simple_key_cache(keycache, 0)) goto finish; /* The following will work even if use_mem is 0 */ @@ -880,7 +871,7 @@ int resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, uint key_cache_block_ division_limit, age_threshold); finish: - finish_resize_simple_key_cache(keycache, 1, 0); + finish_resize_simple_key_cache(keycache, 0); DBUG_RETURN(blocks); } @@ -5279,7 +5270,7 @@ int resize_partitioned_key_cache(PARTITIONED_KEY_CACHE_CB *keycache, } for (i= 0; i < partitions; i++) { - err|= prepare_resize_simple_key_cache(keycache->partition_array[i], 0, 1); + err|= prepare_resize_simple_key_cache(keycache->partition_array[i], 1); } if (!err) blocks= init_partitioned_key_cache(keycache, key_cache_block_size, @@ -5288,7 +5279,7 @@ int resize_partitioned_key_cache(PARTITIONED_KEY_CACHE_CB *keycache, { for (i= 0; i < partitions; i++) { - finish_resize_simple_key_cache(keycache->partition_array[i], 0, 1); + finish_resize_simple_key_cache(keycache->partition_array[i], 1); } } DBUG_RETURN(blocks); |