mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-14526: MariaDB keeps crashing under load when query_cache_type is changed
The problem was in such scenario: T1 - starts registering query and locked QC T2 - starts disabling QC and wait for UNLOCK T1 - unlock QC T2 - disable QC and destroy signals without waiting for query unlock T1 a) - not yet unlocked query in qc and crash on attempt to unlock because QC signals are destroyed b) if above was done before destruction, it execute end_of results first time at exit on after try_lock which see QC disables and return TRUE. But it do not reset query_cache_tls->first_query_block which lead to second call of end_of_result when diagnostic arena has already inappropriate status (not is_eof()). Fix is: 1) wait for all queries unlocked before destroying them by locking and unlocking 2) remove query_cache_tls->first_query_block if QC disabled
This commit is contained in:
@@ -220,3 +220,29 @@ RESET QUERY CACHE;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET GLOBAL query_cache_size= DEFAULT;
|
SET GLOBAL query_cache_size= DEFAULT;
|
||||||
SET GLOBAL query_cache_type= DEFAULT;
|
SET GLOBAL query_cache_type= DEFAULT;
|
||||||
|
#
|
||||||
|
# MDEV-14526: MariaDB keeps crashing under load when
|
||||||
|
# query_cache_type is changed
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
`id` int(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`k` int(10) default '0',
|
||||||
|
PRIMARY KEY (`id`))
|
||||||
|
ENGINE=MyISAM;
|
||||||
|
INSERT IGNORE INTO t1 VALUES
|
||||||
|
(NULL,1),(NULL,8),(NULL,NULL),(NULL,NULL),(NULL,4),(NULL,9),(NULL,7),
|
||||||
|
(NULL,3),(NULL,NULL),(NULL,2),(NULL,3),(NULL,NULL),(NULL,2),(NULL,7),
|
||||||
|
(NULL,1),(NULL,2),(NULL,4),(NULL,NULL),(NULL,1),(NULL,1),(NULL,4);
|
||||||
|
SET GLOBAL query_cache_size= 1024*1024;
|
||||||
|
SET GLOBAL query_cache_type= 1;
|
||||||
|
set debug_sync="wait_in_query_cache_store_query SIGNAL parked WAIT_FOR go";
|
||||||
|
SELECT DISTINCT id FROM t1 WHERE id BETWEEN 5603 AND 16218 ORDER BY k;
|
||||||
|
set debug_sync="now WAIT_FOR parked";
|
||||||
|
SET GLOBAL query_cache_type= 0;
|
||||||
|
set debug_sync="now SIGNAL go";
|
||||||
|
id
|
||||||
|
set debug_sync= 'RESET';
|
||||||
|
DROP TABLE t1;
|
||||||
|
SEt GLOBAL query_cache_size= DEFAULT;
|
||||||
|
SEt GLOBAL query_cache_type= DEFAULT;
|
||||||
|
# End of 5.5 tests
|
||||||
|
@@ -319,3 +319,55 @@ RESET QUERY CACHE;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SET GLOBAL query_cache_size= DEFAULT;
|
SET GLOBAL query_cache_size= DEFAULT;
|
||||||
SET GLOBAL query_cache_type= DEFAULT;
|
SET GLOBAL query_cache_type= DEFAULT;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-14526: MariaDB keeps crashing under load when
|
||||||
|
--echo # query_cache_type is changed
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
`id` int(10) NOT NULL AUTO_INCREMENT,
|
||||||
|
`k` int(10) default '0',
|
||||||
|
PRIMARY KEY (`id`))
|
||||||
|
ENGINE=MyISAM;
|
||||||
|
|
||||||
|
INSERT IGNORE INTO t1 VALUES
|
||||||
|
(NULL,1),(NULL,8),(NULL,NULL),(NULL,NULL),(NULL,4),(NULL,9),(NULL,7),
|
||||||
|
(NULL,3),(NULL,NULL),(NULL,2),(NULL,3),(NULL,NULL),(NULL,2),(NULL,7),
|
||||||
|
(NULL,1),(NULL,2),(NULL,4),(NULL,NULL),(NULL,1),(NULL,1),(NULL,4);
|
||||||
|
|
||||||
|
SET GLOBAL query_cache_size= 1024*1024;
|
||||||
|
SET GLOBAL query_cache_type= 1;
|
||||||
|
|
||||||
|
--connect (con2,localhost,root,,test)
|
||||||
|
--connect (con1,localhost,root,,test)
|
||||||
|
set debug_sync="wait_in_query_cache_store_query SIGNAL parked WAIT_FOR go";
|
||||||
|
--send
|
||||||
|
|
||||||
|
SELECT DISTINCT id FROM t1 WHERE id BETWEEN 5603 AND 16218 ORDER BY k;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
|
||||||
|
set debug_sync="now WAIT_FOR parked";
|
||||||
|
--connection con2
|
||||||
|
--send
|
||||||
|
SET GLOBAL query_cache_type= 0;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
set debug_sync="now SIGNAL go";
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
--reap
|
||||||
|
--connection con2
|
||||||
|
--reap
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
--disconnect con1
|
||||||
|
--disconnect con2
|
||||||
|
--connection default
|
||||||
|
set debug_sync= 'RESET';
|
||||||
|
DROP TABLE t1;
|
||||||
|
SEt GLOBAL query_cache_size= DEFAULT;
|
||||||
|
SEt GLOBAL query_cache_type= DEFAULT;
|
||||||
|
|
||||||
|
--echo # End of 5.5 tests
|
||||||
|
@@ -1184,7 +1184,11 @@ void Query_cache::end_of_result(THD *thd)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (try_lock(thd, Query_cache::WAIT))
|
if (try_lock(thd, Query_cache::WAIT))
|
||||||
|
{
|
||||||
|
if (is_disabled())
|
||||||
|
query_cache_tls->first_query_block= NULL; // do not try again with QC
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
query_block= query_cache_tls->first_query_block;
|
query_block= query_cache_tls->first_query_block;
|
||||||
if (query_block)
|
if (query_block)
|
||||||
@@ -1556,6 +1560,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
|||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
|
|
||||||
|
DEBUG_SYNC(thd, "wait_in_query_cache_store_query");
|
||||||
|
|
||||||
// init_n_lock make query block locked
|
// init_n_lock make query block locked
|
||||||
BLOCK_UNLOCK_WR(query_block);
|
BLOCK_UNLOCK_WR(query_block);
|
||||||
}
|
}
|
||||||
@@ -2679,13 +2685,17 @@ void Query_cache::make_disabled()
|
|||||||
|
|
||||||
This function frees all resources allocated by the cache. You
|
This function frees all resources allocated by the cache. You
|
||||||
have to call init_cache() before using the cache again. This function
|
have to call init_cache() before using the cache again. This function
|
||||||
requires the structure_guard_mutex to be locked.
|
requires the cache to be locked (LOCKED_NO_WAIT, lock_and_suspend) or
|
||||||
|
disabling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void Query_cache::free_cache()
|
void Query_cache::free_cache()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Query_cache::free_cache");
|
DBUG_ENTER("Query_cache::free_cache");
|
||||||
|
|
||||||
|
DBUG_ASSERT(m_cache_lock_status == LOCKED_NO_WAIT ||
|
||||||
|
m_cache_status == DISABLE_REQUEST);
|
||||||
|
|
||||||
/* Destroy locks */
|
/* Destroy locks */
|
||||||
Query_cache_block *block= queries_blocks;
|
Query_cache_block *block= queries_blocks;
|
||||||
if (block)
|
if (block)
|
||||||
@@ -2693,6 +2703,13 @@ void Query_cache::free_cache()
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
Query_cache_query *query= block->query();
|
Query_cache_query *query= block->query();
|
||||||
|
/*
|
||||||
|
There will not be new requests but some maybe not finished yet,
|
||||||
|
so wait for them by trying lock/unlock
|
||||||
|
*/
|
||||||
|
BLOCK_LOCK_WR(block);
|
||||||
|
BLOCK_UNLOCK_WR(block);
|
||||||
|
|
||||||
mysql_rwlock_destroy(&query->lock);
|
mysql_rwlock_destroy(&query->lock);
|
||||||
block= block->next;
|
block= block->next;
|
||||||
} while (block != queries_blocks);
|
} while (block != queries_blocks);
|
||||||
|
Reference in New Issue
Block a user