2008-01-11 14:16:46 +01:00
--source include/not_embedded.inc
2008-01-07 21:06:18 +01:00
--source include/have_query_cache.inc
2010-10-08 00:51:37 +02:00
--source include/have_debug_sync.inc
2012-02-07 16:22:36 +01:00
--source include/long_test.inc
2022-10-04 10:26:50 +02:00
--source include/no_valgrind_without_big.inc
2008-01-07 21:06:18 +01:00
2015-08-11 18:45:38 +02:00
set global query_cache_type= ON;
2019-08-30 15:06:54 +02:00
set @save_query_cache_size=@@global.query_cache_size;
SET @save_concurrent_insert= @@GLOBAL.concurrent_insert;
2008-01-07 21:06:18 +01:00
#
# Bug #30887 Server crashes on SET GLOBAL query_cache_size=0
#
flush status;
set query_cache_type=DEMAND;
2008-04-02 00:43:17 +02:00
set global query_cache_size= 1024*768;
2008-01-07 21:06:18 +01:00
--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.
2010-10-08 00:51:37 +02:00
set debug_sync="wait_in_query_cache_insert SIGNAL parked WAIT_FOR go";
2008-01-07 21:06:18 +01:00
--send select SQL_CACHE * from t1;
connection default;
2010-10-08 00:51:37 +02:00
set debug_sync="now WAIT_FOR parked";
2008-01-07 21:06:18 +01:00
connection bug30887con2;
2016-03-25 17:51:22 +01:00
--echo clear the query cache.
2008-01-07 21:06:18 +01:00
show status like 'Qcache_queries_in_cache';
2008-01-11 14:16:46 +01:00
set global query_cache_size= 0;
2008-01-07 21:06:18 +01:00
connection default;
--echo Signal the debug hook to release the lock.
2010-10-08 00:51:37 +02:00
set debug_sync="now SIGNAL go";
2008-01-07 21:06:18 +01:00
--echo Show query cache status.
show status like 'Qcache_queries_in_cache';
2010-10-08 00:51:37 +02:00
connection bug30887con1;
--reap
2008-01-07 21:06:18 +01:00
disconnect bug30887con1;
disconnect bug30887con2;
2010-10-08 00:51:37 +02:00
connection default;
set debug_sync= 'RESET';
2008-01-07 21:06:18 +01:00
set global query_cache_size= 0;
use test;
drop table t1;
2009-02-19 22:09:35 +01:00
#
# Bug#41098: Query Cache returns wrong result with concurrent insert
#
2022-06-09 05:32:51 +02:00
--disable_view_protocol
2009-02-19 22:09:35 +01:00
--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;
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC = "wait_after_query_cache_invalidate SIGNAL parked WAIT_FOR go";
2009-02-19 22:09:35 +01:00
--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
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC = "now WAIT_FOR parked";
2009-02-19 22:09:35 +01:00
connection con2;
--echo # Send SELECT that shouldn't be cached
SELECT * FROM t1;
connection default;
--echo # Notify the concurrent insert to proceed
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC = "now SIGNAL go";
2009-02-19 22:09:35 +01:00
connection con1;
--echo # Gather insert result
--reap
SHOW STATUS LIKE "Qcache_queries_in_cache";
--echo # Test that it's cacheable
2024-05-23 03:54:14 +02:00
--disable_cursor_protocol
2009-02-19 22:09:35 +01:00
SELECT * FROM t1;
2024-05-23 03:54:14 +02:00
--enable_cursor_protocol
2009-02-19 22:09:35 +01:00
SHOW STATUS LIKE "Qcache_queries_in_cache";
disconnect con1;
disconnect con2;
connection default;
--echo # Restore defaults
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC= 'RESET';
2009-02-19 22:09:35 +01:00
RESET QUERY CACHE;
DROP TABLE t1,t2;
SET GLOBAL concurrent_insert= DEFAULT;
SET GLOBAL query_cache_size= DEFAULT;
SET GLOBAL query_cache_type= DEFAULT;
2022-06-09 05:32:51 +02:00
--enable_view_protocol
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--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 **
2010-10-08 00:51:37 +02:00
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";
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--send DELETE FROM t1 WHERE a like '%a%';
connection default;
--echo ** Assert that the expect process status is obtained.
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now WAIT_FOR parked1_1";
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
-- 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.
2010-10-08 14:16:20 +02:00
SET DEBUG_SYNC="wait_in_query_cache_insert SIGNAL parked2 WAIT_FOR go2 EXECUTE 1";
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--send SELECT SQL_CACHE * FROM t2 UNION SELECT * FROM t3
2010-10-08 14:16:20 +02:00
connection default;
--echo ** Assert that the SELECT-stmt thread reaches the sync point.
SET DEBUG_SYNC="now WAIT_FOR parked2";
--echo **
--echo **
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
connection thd3;
--echo ** On THD3: Insert another result into the cache and block on the same
--echo ** debug hook.
2010-10-08 14:16:20 +02:00
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
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
connection default;
2010-10-08 14:16:20 +02:00
--echo ** Assert that the SELECT-stmt thread reaches the sync point.
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now WAIT_FOR parked3";
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--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.
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now SIGNAL go1_1";
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--echo ** Assert that we reach the next debug hook.
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now WAIT_FOR parked1_2";
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--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.
2022-02-22 16:54:54 +01:00
# Before sending signals back-to-back, we have to ensure the previous signal
# was received
let $wait_condition= select count(*)=3 from information_schema.processlist where state like "%debug%";
source include/wait_condition.inc;
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now SIGNAL go2";
2022-02-22 16:54:54 +01:00
let $wait_condition= select count(*)=2 from information_schema.processlist where state like "%debug%";
source include/wait_condition.inc;
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now SIGNAL go3";
2022-02-22 16:54:54 +01:00
let $wait_condition= select count(*)=1 from information_schema.processlist where state like "%debug%";
source include/wait_condition.inc;
2009-06-17 16:28:11 +02:00
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--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.
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC="now SIGNAL go1_2";
2022-02-22 16:54:54 +01:00
let $wait_condition= select count(*)=0 from information_schema.processlist where state like "%debug%";
source include/wait_condition.inc;
2010-04-30 14:12:41 +02:00
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
--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;
2010-10-08 00:51:37 +02:00
SET DEBUG_SYNC= 'RESET';
Bug#43758 Query cache can lock up threads in 'freeing items' state
Early patch submitted for discussion.
It is possible for more than one thread to enter the condition
in query_cache_insert(), but the condition predicate is to
signal one thread each time the cache status changes between
the following states: {NO_FLUSH_IN_PROGRESS,FLUSH_IN_PROGRESS,
TABLE_FLUSH_IN_PROGRESS}
Consider three threads THD1, THD2, THD3
THD2: select ... => Got a writer in ::store_query
THD3: select ... => Got a writer in ::store_query
THD1: flush tables => qc status= FLUSH_IN_PROGRESS;
new writers are blocked.
THD2: select ... => Still got a writer and enters cond in
query_cache_insert
THD3: select ... => Still got a writer and enters cond in
query_cache_insert
THD1: flush tables => finished and signal status change.
THD2: select ... => Wakes up and completes the insert.
THD3: select ... => Happily waiting for better times. Why hurry?
This patch is a refactoring of this lock system. It introduces four new methods:
Query_cache::try_lock()
Query_cache::lock()
Query_cache::lock_and_suspend()
Query_cache::unlock()
This change also deprecates wait_while_table_flush_is_in_progress(). All threads are
queued and put on a conditional wait. On each unlock the queue is signalled. This resolve
the issues with left over threads. To assure that no threads are spending unnecessary
time waiting a signal broadcast is issued every time a lock is taken before a full
cache flush.
mysql-test/r/query_cache_debug.result:
* Added test case for bug43758
mysql-test/t/query_cache_debug.test:
* Added test case for bug43758
sql/sql_cache.cc:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
sql/sql_cache.h:
* Replaced calls to wait_while_table_flush_is_in_progress() with
calls to try_lock(), lock_and_suspend() and unlock().
* Renamed enumeration Cache_status to Cache_lock_status.
* Renamed enumeration items to UNLOCKED, LOCKED_NO_WAIT and LOCKED.
If the LOCKED_NO_WAIT lock type is used to lock the query cache, other
threads using try_lock() will fail to acquire the lock.
This is useful if the query cache is temporary disabled due to
a full table flush.
2009-06-16 10:34:47 +02:00
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;
2010-10-08 00:51:37 +02:00
--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;
2019-08-30 15:06:54 +02:00
SET GLOBAL query_cache_size= @save_query_cache_size;
2010-10-08 00:51:37 +02:00
SET GLOBAL query_cache_type= DEFAULT;
2018-01-12 18:17:55 +01:00
--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";
2019-08-30 15:06:54 +02:00
--send SELECT DISTINCT id FROM t1 WHERE id BETWEEN 5603 AND 16218 ORDER BY k
2018-01-12 18:17:55 +01:00
--connection default
set debug_sync="now WAIT_FOR parked";
--connection con2
2019-08-30 15:06:54 +02:00
--send SET GLOBAL query_cache_type= 0;
2018-01-12 18:17:55 +01:00
--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;
2019-08-30 15:06:54 +02:00
SET GLOBAL query_cache_size=@save_query_cache_size;
SET GLOBAL query_cache_type= DEFAULT;
SET @@GLOBAL.concurrent_insert=@save_concurrent_insert;
2018-01-12 18:17:55 +01:00
--echo # End of 5.5 tests