182 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
		
		
			
		
	
	
			182 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| 
								 | 
							
								flush status;
							 | 
						||
| 
								 | 
							
								set query_cache_type=DEMAND;
							 | 
						||
| 
								 | 
							
								set global query_cache_size= 1024*768;
							 | 
						||
| 
								 | 
							
								drop table if exists t1;
							 | 
						||
| 
								 | 
							
								create table t1 (a varchar(100));
							 | 
						||
| 
								 | 
							
								insert into t1 values ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
							 | 
						||
| 
								 | 
							
								Activate debug hook and attempt to retrieve the statement from the cache.
							 | 
						||
| 
								 | 
							
								set session debug='+d,wait_in_query_cache_insert';
							 | 
						||
| 
								 | 
							
								select SQL_CACHE * from t1;;
							 | 
						||
| 
								 | 
							
								On a second connection; clear the query cache.
							 | 
						||
| 
								 | 
							
								show status like 'Qcache_queries_in_cache';
							 | 
						||
| 
								 | 
							
								Variable_name	Value
							 | 
						||
| 
								 | 
							
								Qcache_queries_in_cache	1
							 | 
						||
| 
								 | 
							
								set global query_cache_size= 0;
							 | 
						||
| 
								 | 
							
								Signal the debug hook to release the lock.
							 | 
						||
| 
								 | 
							
								select id from information_schema.processlist where state='wait_in_query_cache_insert' into @thread_id;
							 | 
						||
| 
								 | 
							
								kill query @thread_id;
							 | 
						||
| 
								 | 
							
								Show query cache status.
							 | 
						||
| 
								 | 
							
								show status like 'Qcache_queries_in_cache';
							 | 
						||
| 
								 | 
							
								Variable_name	Value
							 | 
						||
| 
								 | 
							
								Qcache_queries_in_cache	0
							 | 
						||
| 
								 | 
							
								set global query_cache_size= 0;
							 | 
						||
| 
								 | 
							
								use test;
							 | 
						||
| 
								 | 
							
								drop table t1;
							 | 
						||
| 
								 | 
							
								SET @old_concurrent_insert= @@GLOBAL.concurrent_insert;
							 | 
						||
| 
								 | 
							
								SET @old_query_cache_size= @@GLOBAL.query_cache_size;
							 | 
						||
| 
								 | 
							
								DROP TABLE IF EXISTS t1, t2;
							 | 
						||
| 
								 | 
							
								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;
							 | 
						||
| 
								 | 
							
								# Switch to connection con1
							 | 
						||
| 
								 | 
							
								SET SESSION debug='+d,wait_after_query_cache_invalidate';
							 | 
						||
| 
								 | 
							
								# Send concurrent insert, will wait in the query cache table invalidate
							 | 
						||
| 
								 | 
							
								INSERT INTO t1 VALUES (4);
							 | 
						||
| 
								 | 
							
								# Switch to connection default
							 | 
						||
| 
								 | 
							
								# Wait for concurrent insert to reach the debug point
							 | 
						||
| 
								 | 
							
								# Switch to connection con2
							 | 
						||
| 
								 | 
							
								# Send SELECT that shouldn't be cached
							 | 
						||
| 
								 | 
							
								SELECT * FROM t1;
							 | 
						||
| 
								 | 
							
								a
							 | 
						||
| 
								 | 
							
								1
							 | 
						||
| 
								 | 
							
								2
							 | 
						||
| 
								 | 
							
								3
							 | 
						||
| 
								 | 
							
								# Switch to connection default
							 | 
						||
| 
								 | 
							
								# Notify the concurrent insert to proceed
							 | 
						||
| 
								 | 
							
								SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST
							 | 
						||
| 
								 | 
							
								WHERE STATE = 'wait_after_query_cache_invalidate' INTO @thread_id;
							 | 
						||
| 
								 | 
							
								KILL QUERY @thread_id;
							 | 
						||
| 
								 | 
							
								# Switch to connection con1
							 | 
						||
| 
								 | 
							
								# Gather insert result
							 | 
						||
| 
								 | 
							
								SHOW STATUS LIKE "Qcache_queries_in_cache";
							 | 
						||
| 
								 | 
							
								Variable_name	Value
							 | 
						||
| 
								 | 
							
								Qcache_queries_in_cache	0
							 | 
						||
| 
								 | 
							
								# Test that it's cacheable
							 | 
						||
| 
								 | 
							
								SELECT * FROM t1;
							 | 
						||
| 
								 | 
							
								a
							 | 
						||
| 
								 | 
							
								1
							 | 
						||
| 
								 | 
							
								2
							 | 
						||
| 
								 | 
							
								3
							 | 
						||
| 
								 | 
							
								4
							 | 
						||
| 
								 | 
							
								SHOW STATUS LIKE "Qcache_queries_in_cache";
							 | 
						||
| 
								 | 
							
								Variable_name	Value
							 | 
						||
| 
								 | 
							
								Qcache_queries_in_cache	1
							 | 
						||
| 
								 | 
							
								# Disconnect
							 | 
						||
| 
								 | 
							
								# Restore defaults
							 | 
						||
| 
								 | 
							
								RESET QUERY CACHE;
							 | 
						||
| 
								 | 
							
								DROP TABLE t1,t2;
							 | 
						||
| 
								 | 
							
								SET GLOBAL concurrent_insert= DEFAULT;
							 | 
						||
| 
								 | 
							
								SET GLOBAL query_cache_size= DEFAULT;
							 | 
						||
| 
								 | 
							
								SET GLOBAL query_cache_type= DEFAULT;
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Bug43758 Query cache can lock up threads in 'freeing items' state
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								FLUSH STATUS;
							 | 
						||
| 
								 | 
							
								SET GLOBAL query_cache_type=DEMAND;
							 | 
						||
| 
								 | 
							
								SET GLOBAL query_cache_size= 1024*768;
							 | 
						||
| 
								 | 
							
								DROP TABLE IF EXISTS t1,t2,t3,t4,t5;
							 | 
						||
| 
								 | 
							
								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');
							 | 
						||
| 
								 | 
							
								=================================== Connection thd1
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								** Load Query Cache with a result set and one table.
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								SELECT SQL_CACHE * FROM t1;
							 | 
						||
| 
								 | 
							
								a
							 | 
						||
| 
								 | 
							
								aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
							 | 
						||
| 
								 | 
							
								bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
							 | 
						||
| 
								 | 
							
								*************************************************************************
							 | 
						||
| 
								 | 
							
								** We want to accomplish the following state:
							 | 
						||
| 
								 | 
							
								**  - Query cache status: TABLE_FLUSH_IN_PROGRESS
							 | 
						||
| 
								 | 
							
								**  - THD1: invalidate_table_internal (iterating query blocks)
							 | 
						||
| 
								 | 
							
								**  - THD2: query_cache_insert (cond_wait)
							 | 
						||
| 
								 | 
							
								**  - THD3: query_cache_insert (cond_wait)
							 | 
						||
| 
								 | 
							
								**  - No thread should be holding the structure_guard_mutex.
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								** First step is to place a DELETE-statement on the debug hook just
							 | 
						||
| 
								 | 
							
								** before the mutex lock in invalidate_table_internal.
							 | 
						||
| 
								 | 
							
								** This will allow new result sets to be written into the QC.
							 | 
						||
| 
								 | 
							
								** 
							 | 
						||
| 
								 | 
							
								SET SESSION debug='+d,wait_in_query_cache_invalidate1';
							 | 
						||
| 
								 | 
							
								SET SESSION debug='+d,wait_in_query_cache_invalidate2';
							 | 
						||
| 
								 | 
							
								DELETE FROM t1 WHERE a like '%a%';;
							 | 
						||
| 
								 | 
							
								=================================== Connection default
							 | 
						||
| 
								 | 
							
								** Assert that the expect process status is obtained.
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								=================================== Connection thd2
							 | 
						||
| 
								 | 
							
								** On THD2: Insert a result into the cache. This attempt will be blocked
							 | 
						||
| 
								 | 
							
								** because of a debug hook placed just before the mutex lock after which
							 | 
						||
| 
								 | 
							
								** the first part of the result set is written.
							 | 
						||
| 
								 | 
							
								SET SESSION debug='+d,wait_in_query_cache_insert';
							 | 
						||
| 
								 | 
							
								SELECT SQL_CACHE * FROM t2 UNION SELECT * FROM t3;
							 | 
						||
| 
								 | 
							
								=================================== Connection thd3
							 | 
						||
| 
								 | 
							
								** On THD3: Insert another result into the cache and block on the same
							 | 
						||
| 
								 | 
							
								** debug hook.
							 | 
						||
| 
								 | 
							
								SET SESSION debug='+d,wait_in_query_cache_insert';
							 | 
						||
| 
								 | 
							
								SELECT SQL_CACHE * FROM t4 UNION SELECT * FROM t5;;
							 | 
						||
| 
								 | 
							
								=================================== Connection default
							 | 
						||
| 
								 | 
							
								** Assert that the two SELECT-stmt threads to reach the hook.
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								** Signal the DELETE thread, THD1, to continue. It will enter the mutex
							 | 
						||
| 
								 | 
							
								** lock and set query cache status to TABLE_FLUSH_IN_PROGRESS and then
							 | 
						||
| 
								 | 
							
								** unlock the mutex before stopping on the next debug hook.
							 | 
						||
| 
								 | 
							
								SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate1' LIMIT 1 INTO @flush_thread_id;
							 | 
						||
| 
								 | 
							
								KILL QUERY @flush_thread_id;
							 | 
						||
| 
								 | 
							
								** Assert that we reach the next debug hook.
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								** Signal the remaining debug hooks blocking THD2 and THD3.
							 | 
						||
| 
								 | 
							
								** The threads will grab the guard mutex enter the wait condition and
							 | 
						||
| 
								 | 
							
								** and finally release the mutex. The threads will continue to wait
							 | 
						||
| 
								 | 
							
								** until a broadcast signal reaches them causing both threads to 
							 | 
						||
| 
								 | 
							
								** come alive and check the condition.
							 | 
						||
| 
								 | 
							
								SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_insert' ORDER BY id ASC LIMIT 1 INTO @thread_id;
							 | 
						||
| 
								 | 
							
								KILL QUERY @thread_id;
							 | 
						||
| 
								 | 
							
								SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_insert' ORDER BY id DESC LIMIT 1 INTO @thread_id;
							 | 
						||
| 
								 | 
							
								KILL QUERY @thread_id;
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								** Finally signal the DELETE statement on THD1 one last time.
							 | 
						||
| 
								 | 
							
								** The stmt will complete the query cache invalidation and return 
							 | 
						||
| 
								 | 
							
								** cache status to NO_FLUSH_IN_PROGRESS. On the status change
							 | 
						||
| 
								 | 
							
								** One signal will be sent to the thread group waiting for executing
							 | 
						||
| 
								 | 
							
								** invalidations and a broadcast signal will be sent to the thread 
							 | 
						||
| 
								 | 
							
								** group holding result set writers.
							 | 
						||
| 
								 | 
							
								SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate2' LIMIT 1 INTO @flush_thread_id;
							 | 
						||
| 
								 | 
							
								KILL QUERY @flush_thread_id;
							 | 
						||
| 
								 | 
							
								**
							 | 
						||
| 
								 | 
							
								*************************************************************************
							 | 
						||
| 
								 | 
							
								** No tables should be locked
							 | 
						||
| 
								 | 
							
								=================================== Connection thd2
							 | 
						||
| 
								 | 
							
								a
							 | 
						||
| 
								 | 
							
								aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
							 | 
						||
| 
								 | 
							
								bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
							 | 
						||
| 
								 | 
							
								DELETE FROM t1;
							 | 
						||
| 
								 | 
							
								DELETE FROM t2;
							 | 
						||
| 
								 | 
							
								DELETE FROM t3;
							 | 
						||
| 
								 | 
							
								=================================== Connection thd3
							 | 
						||
| 
								 | 
							
								a
							 | 
						||
| 
								 | 
							
								aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
							 | 
						||
| 
								 | 
							
								bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
							 | 
						||
| 
								 | 
							
								DELETE FROM t4;
							 | 
						||
| 
								 | 
							
								DELETE FROM t5;
							 | 
						||
| 
								 | 
							
								=================================== Connection thd1
							 | 
						||
| 
								 | 
							
								** Done.
							 | 
						||
| 
								 | 
							
								SET GLOBAL query_cache_size= 0;
							 | 
						||
| 
								 | 
							
								# 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;
							 |