summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2018-01-12 18:17:55 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2018-01-12 18:17:55 +0100
commitf26192559161143c7c0880cf24c63ced1cf9655e (patch)
treec2d1b46c6a02ecac0eeae962de854d757c1fb118
parent5ea28015d5864bec1e44722bbc7a3d1f2371c85d (diff)
downloadmariadb-git-bb-5.5-MDEV-14526.tar.gz
MDEV-14526: MariaDB keeps crashing under load when query_cache_type is changedbb-5.5-MDEV-14526
The problem was in such scenatio: T1 - starts geristering query and locked QC T2 - starts disabling QC and wait for UNLOCK T1 - unlock QC T2 - disable QC and destroy sugnals without waitiung for query unlock T1 a) - not yet unlocked query in qc and crach on attempt to unlock because QC signals are destroyed b) if above was done before distruction, it execute end_of results first time it 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 inapropriate staus (not is_eof()). Fix is: 1) wait for all queries unlocked before destroing them by locking and unlockin 2) remove query_cache_tls->first_query_block if QC disabled
-rw-r--r--mysql-test/r/query_cache_debug.result32
-rw-r--r--mysql-test/t/query_cache_debug.test52
-rw-r--r--sql/sql_cache.cc13
3 files changed, 97 insertions, 0 deletions
diff --git a/mysql-test/r/query_cache_debug.result b/mysql-test/r/query_cache_debug.result
index 50a3a02fe4d..82d7d936f43 100644
--- a/mysql-test/r/query_cache_debug.result
+++ b/mysql-test/r/query_cache_debug.result
@@ -220,3 +220,35 @@ RESET QUERY CACHE;
DROP TABLE t1;
SET GLOBAL query_cache_size= 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) NOT NULL 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);
+Warnings:
+Warning 1048 Column 'k' cannot be null
+Warning 1048 Column 'k' cannot be null
+Warning 1048 Column 'k' cannot be null
+Warning 1048 Column 'k' cannot be null
+Warning 1048 Column 'k' cannot be null
+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
diff --git a/mysql-test/t/query_cache_debug.test b/mysql-test/t/query_cache_debug.test
index 854af85f3fb..51df5ce48da 100644
--- a/mysql-test/t/query_cache_debug.test
+++ b/mysql-test/t/query_cache_debug.test
@@ -319,3 +319,55 @@ RESET QUERY CACHE;
DROP TABLE t1;
SET GLOBAL query_cache_size= 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) NOT NULL 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
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 2ec870f314f..eb6aec8b15a 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1184,7 +1184,11 @@ void Query_cache::end_of_result(THD *thd)
#endif
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;
+ }
query_block= query_cache_tls->first_query_block;
if (query_block)
@@ -1556,6 +1560,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
unlock();
+ DEBUG_SYNC(thd, "wait_in_query_cache_store_query");
+
// init_n_lock make query block locked
BLOCK_UNLOCK_WR(query_block);
}
@@ -2693,6 +2699,13 @@ void Query_cache::free_cache()
do
{
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);
block= block->next;
} while (block != queries_blocks);