Commit 2a499f75 authored by thek@adventure.(none)'s avatar thek@adventure.(none)

Merge adventure.(none):/home/thek/Development/cpp/bug30887/my51-bug30887

into  adventure.(none):/home/thek/Development/cpp/mysql-5.1-runtime
parents 4b8c6e49 96146a39
......@@ -1669,4 +1669,28 @@ SELECT 1 FROM t1 GROUP BY
1
1
DROP TABLE t1;
flush status;
set query_cache_type=DEMAND;
set global query_cache_size= 1024*1024*512;
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 1
set global query_cache_size= 0;
use test;
drop table t1;
End of 5.1 tests
......@@ -1316,6 +1316,47 @@ SELECT 1 FROM t1 GROUP BY
(SELECT LAST_INSERT_ID() FROM t1 ORDER BY MIN(a) ASC LIMIT 1);
DROP TABLE t1;
#
# Bug #30887 Server crashes on SET GLOBAL query_cache_size=0
#
flush status;
set query_cache_type=DEMAND;
set global query_cache_size= 1024*1024*512;
--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 session debug='+d,wait_in_query_cache_insert';
--send select SQL_CACHE * from t1;
connection default;
let $wait_condition= select count(*)= 1 from information_schema.processlist where state= 'wait_in_query_cache_insert';
--source include/wait_condition.inc
connection bug30887con2;
--echo On a second connection; clear the query cache.
show status like 'Qcache_queries_in_cache';
--send set global query_cache_size= 0;
connection default;
--echo 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;
--echo Show query cache status.
show status like 'Qcache_queries_in_cache';
disconnect bug30887con1;
disconnect bug30887con2;
set global query_cache_size= 0;
use test;
drop table t1;
--echo End of 5.1 tests
......@@ -371,6 +371,32 @@ TODO list:
__LINE__,(ulong)(B)));B->query()->unlock_reading();}
#define DUMP(C) DBUG_EXECUTE("qcache", {\
(C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
/**
Causes the thread to wait in a spin lock for a query kill signal.
This function is used by the test frame work to identify race conditions.
The signal is caught and ignored and the thread is not killed.
*/
static void debug_wait_for_kill(const char *info)
{
DBUG_ENTER("debug_wait_for_kill");
const char *prev_info;
THD *thd;
thd= current_thd;
prev_info= thd->proc_info;
thd->proc_info= info;
sql_print_information(info);
while(!thd->killed)
my_sleep(1000);
thd->killed= THD::NOT_KILLED;
sql_print_information("Exit debug_wait_for_kill");
thd->proc_info= prev_info;
DBUG_VOID_RETURN;
}
#else
#define MUTEX_LOCK(M) pthread_mutex_lock(M)
#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
......@@ -647,13 +673,16 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
if (net->query_cache_query == 0)
DBUG_VOID_RETURN;
DBUG_EXECUTE_IF("wait_in_query_cache_insert",
debug_wait_for_kill("wait_in_query_cache_insert"); );
STRUCT_LOCK(&query_cache.structure_guard_mutex);
bool interrupt;
query_cache.wait_while_table_flush_is_in_progress(&interrupt);
if (interrupt)
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
return;
DBUG_VOID_RETURN;
}
Query_cache_block *query_block= (Query_cache_block*)net->query_cache_query;
......@@ -667,11 +696,11 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
DBUG_VOID_RETURN;
}
BLOCK_LOCK_WR(query_block);
Query_cache_query *header= query_block->query();
Query_cache_block *result= header->result();
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
DBUG_PRINT("qcache", ("insert packet %lu bytes long",length));
/*
......@@ -687,6 +716,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block));
// The following call will remove the lock on query_block
query_cache.free_query(query_block);
query_cache.refused++;
// append_result_data no success => we need unlock
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
......@@ -883,6 +913,31 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
m_cache_status= Query_cache::FLUSH_IN_PROGRESS;
STRUCT_UNLOCK(&structure_guard_mutex);
/*
Wait for all readers and writers to exit. When the list of all queries
is iterated over with a block level lock, we are done.
*/
Query_cache_block *block= queries_blocks;
if (block)
{
do
{
BLOCK_LOCK_WR(block);
Query_cache_query *query= block->query();
if (query && query->writer())
{
/*
Drop the writer; this will cancel any attempts to store
the processed statement associated with this writer.
*/
query->writer()->query_cache_query= 0;
query->writer(0);
refused++;
}
BLOCK_UNLOCK_WR(block);
block= block->next;
} while (block != queries_blocks);
}
free_cache();
query_cache_size= query_cache_size_arg;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment