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; |