--source include/not_embedded.inc --source include/have_query_cache.inc --source include/have_debug_sync.inc --source include/long_test.inc set global query_cache_type= ON; set @save_query_cache_size=@@global.query_cache_size; SET @save_concurrent_insert= @@GLOBAL.concurrent_insert; # # Bug #30887 Server crashes on SET GLOBAL query_cache_size=0 # flush status; set query_cache_type=DEMAND; set global query_cache_size= 1024*768; --disable_warnings drop table if exists t1; --enable_warnings create table t1 (a varchar(100)); insert into t1 values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); connect (bug30887con1, localhost, root, ,test); connect (bug30887con2, localhost, root, ,test); connection bug30887con1; --echo Activate debug hook and attempt to retrieve the statement from the cache. set debug_sync="wait_in_query_cache_insert SIGNAL parked WAIT_FOR go"; --send select SQL_CACHE * from t1; connection default; set debug_sync="now WAIT_FOR parked"; connection bug30887con2; --echo clear the query cache. show status like 'Qcache_queries_in_cache'; set global query_cache_size= 0; connection default; --echo Signal the debug hook to release the lock. set debug_sync="now SIGNAL go"; --echo Show query cache status. show status like 'Qcache_queries_in_cache'; connection bug30887con1; --reap disconnect bug30887con1; disconnect bug30887con2; connection default; set debug_sync= 'RESET'; set global query_cache_size= 0; use test; drop table t1; # # Bug#41098: Query Cache returns wrong result with concurrent insert # --disable_warnings DROP TABLE IF EXISTS t1, t2; --enable_warnings CREATE TABLE t1 (a INT); CREATE TABLE t2 (a INT); INSERT INTO t1 VALUES (1),(2),(3); SET GLOBAL concurrent_insert= 1; SET GLOBAL query_cache_size= 1024*512; SET GLOBAL query_cache_type= ON; connect(con1,localhost,root,,test,,); connect(con2,localhost,root,,test,,); connection con1; SET DEBUG_SYNC = "wait_after_query_cache_invalidate SIGNAL parked WAIT_FOR go"; --echo # Send concurrent insert, will wait in the query cache table invalidate --send INSERT INTO t1 VALUES (4) connection default; --echo # Wait for concurrent insert to reach the debug point SET DEBUG_SYNC = "now WAIT_FOR parked"; connection con2; --echo # Send SELECT that shouldn't be cached SELECT * FROM t1; connection default; --echo # Notify the concurrent insert to proceed SET DEBUG_SYNC = "now SIGNAL go"; connection con1; --echo # Gather insert result --reap SHOW STATUS LIKE "Qcache_queries_in_cache"; --echo # Test that it's cacheable SELECT * FROM t1; SHOW STATUS LIKE "Qcache_queries_in_cache"; disconnect con1; disconnect con2; connection default; --echo # Restore defaults SET DEBUG_SYNC= 'RESET'; RESET QUERY CACHE; DROP TABLE t1,t2; SET GLOBAL concurrent_insert= DEFAULT; SET GLOBAL query_cache_size= DEFAULT; SET GLOBAL query_cache_type= DEFAULT; --echo # --echo # Bug43758 Query cache can lock up threads in 'freeing items' state --echo # FLUSH STATUS; SET GLOBAL query_cache_type=DEMAND; SET GLOBAL query_cache_size= 1024*768; --disable_warnings DROP TABLE IF EXISTS t1,t2,t3,t4,t5; --enable_warnings CREATE TABLE t1 (a VARCHAR(100)); CREATE TABLE t2 (a VARCHAR(100)); CREATE TABLE t3 (a VARCHAR(100)); CREATE TABLE t4 (a VARCHAR(100)); CREATE TABLE t5 (a VARCHAR(100)); INSERT INTO t1 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); INSERT INTO t2 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); INSERT INTO t3 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); INSERT INTO t4 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); INSERT INTO t5 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); connect (thd2, localhost, root, ,test); connect (thd3, localhost, root, ,test); connect (thd1, localhost, root, ,test); connection thd1; --echo ** --echo ** Load Query Cache with a result set and one table. --echo ** SELECT SQL_CACHE * FROM t1; --echo ************************************************************************* --echo ** We want to accomplish the following state: --echo ** - Query cache status: TABLE_FLUSH_IN_PROGRESS --echo ** - THD1: invalidate_table_internal (iterating query blocks) --echo ** - THD2: query_cache_insert (cond_wait) --echo ** - THD3: query_cache_insert (cond_wait) --echo ** - No thread should be holding the structure_guard_mutex. --echo ** --echo ** First step is to place a DELETE-statement on the debug hook just --echo ** before the mutex lock in invalidate_table_internal. --echo ** This will allow new result sets to be written into the QC. --echo ** SET DEBUG_SYNC="wait_in_query_cache_invalidate1 SIGNAL parked1_1 WAIT_FOR go1_1"; SET DEBUG_SYNC="wait_in_query_cache_invalidate2 SIGNAL parked1_2 WAIT_FOR go1_2"; --send DELETE FROM t1 WHERE a like '%a%'; connection default; --echo ** Assert that the expect process status is obtained. SET DEBUG_SYNC="now WAIT_FOR parked1_1"; -- echo ** connection thd2; --echo ** On THD2: Insert a result into the cache. This attempt will be blocked --echo ** because of a debug hook placed just before the mutex lock after which --echo ** the first part of the result set is written. SET DEBUG_SYNC="wait_in_query_cache_insert SIGNAL parked2 WAIT_FOR go2 EXECUTE 1"; --send SELECT SQL_CACHE * FROM t2 UNION SELECT * FROM t3 connection default; --echo ** Assert that the SELECT-stmt thread reaches the sync point. SET DEBUG_SYNC="now WAIT_FOR parked2"; --echo ** --echo ** connection thd3; --echo ** On THD3: Insert another result into the cache and block on the same --echo ** debug hook. SET DEBUG_SYNC="wait_in_query_cache_insert SIGNAL parked3 WAIT_FOR go3 EXECUTE 1"; --send SELECT SQL_CACHE * FROM t4 UNION SELECT * FROM t5 connection default; --echo ** Assert that the SELECT-stmt thread reaches the sync point. SET DEBUG_SYNC="now WAIT_FOR parked3"; --echo ** --echo ** --echo ** Signal the DELETE thread, THD1, to continue. It will enter the mutex --echo ** lock and set query cache status to TABLE_FLUSH_IN_PROGRESS and then --echo ** unlock the mutex before stopping on the next debug hook. SET DEBUG_SYNC="now SIGNAL go1_1"; --echo ** Assert that we reach the next debug hook. SET DEBUG_SYNC="now WAIT_FOR parked1_2"; --echo ** --echo ** Signal the remaining debug hooks blocking THD2 and THD3. --echo ** The threads will grab the guard mutex enter the wait condition and --echo ** and finally release the mutex. The threads will continue to wait --echo ** until a broadcast signal reaches them causing both threads to --echo ** come alive and check the condition. SET DEBUG_SYNC="now SIGNAL go2"; SET DEBUG_SYNC="now SIGNAL go3"; --echo ** --echo ** Finally signal the DELETE statement on THD1 one last time. --echo ** The stmt will complete the query cache invalidation and return --echo ** cache status to NO_FLUSH_IN_PROGRESS. On the status change --echo ** One signal will be sent to the thread group waiting for executing --echo ** invalidations and a broadcast signal will be sent to the thread --echo ** group holding result set writers. SET DEBUG_SYNC="now SIGNAL go1_2"; --echo ** --echo ************************************************************************* --echo ** No tables should be locked connection thd2; reap; DELETE FROM t1; DELETE FROM t2; DELETE FROM t3; connection thd3; reap; DELETE FROM t4; DELETE FROM t5; connection thd1; reap; --echo ** Done. connection default; disconnect thd1; disconnect thd2; disconnect thd3; SET DEBUG_SYNC= 'RESET'; SET GLOBAL query_cache_size= 0; connection default; --echo # Restore defaults RESET QUERY CACHE; FLUSH STATUS; DROP TABLE t1,t2,t3,t4,t5; SET GLOBAL query_cache_size= DEFAULT; SET GLOBAL query_cache_type= DEFAULT; --echo # --echo # Bug#56822: Add a thread state for sessions waiting on the query cache lock --echo # --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); SET GLOBAL concurrent_insert= 1; SET GLOBAL query_cache_size= 1024*512; SET GLOBAL query_cache_type= ON; connect(con1,localhost,root,,test,,); connect(con2,localhost,root,,test,,); connection con1; SET DEBUG_SYNC = "wait_in_query_cache_invalidate2 SIGNAL parked WAIT_FOR go"; --echo # Send INSERT, will wait in the query cache table invalidation --send INSERT INTO t1 VALUES (4); connection default; --echo # Wait for insert to reach the debug point SET DEBUG_SYNC = "now WAIT_FOR parked"; connection con2; --echo # Send a query that should wait on the query cache lock --send RESET QUERY CACHE connection default; --echo # Wait for the state to be reflected in the processlist let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE state = "Waiting for query cache lock" AND info = "RESET QUERY CACHE"; --source include/wait_condition.inc --echo # Signal that the query cache can be unlocked SET DEBUG_SYNC="now SIGNAL go"; connection con1; --reap disconnect con1; connection con2; --reap disconnect con2; connection default; --echo # Restore defaults SET DEBUG_SYNC= 'RESET'; RESET QUERY CACHE; DROP TABLE t1; SET GLOBAL query_cache_size= @save_query_cache_size; 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=@save_query_cache_size; SET GLOBAL query_cache_type= DEFAULT; SET @@GLOBAL.concurrent_insert=@save_concurrent_insert; --echo # End of 5.5 tests