mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
BUG#21051: RESET QUERY CACHE very slow when query_cache_type=0
There were two problems: RESET QUERY CACHE took a long time to complete
and other threads were blocked during this time.
The patch does three things:
1 fixes a bug with improper use of test-lock-test_again technique.
AKA Double-Checked Locking is applicable here only in few places.
2 Somewhat improves performance of RESET QUERY CACHE.
Do my_hash_reset() instead of deleting elements one by one. Note
however that the slowdown also happens when inserting into sorted
list of free blocks, should be rewritten using balanced tree.
3 Makes RESET QUERY CACHE non-blocking.
The patch adjusts the locking protocol of the query cache in the
following way: it introduces a flag flush_in_progress, which is
set when Query_cache::flush_cache() is in progress. This call
sets the flag on enter, and then releases the lock. Every other
call is able to acquire the lock, but does nothing if
flush_in_progress is set (as if the query cache is disabled).
The only exception is the concurrent calls to
Query_cache::flush_cache(), that are blocked until the flush is
over. When leaving Query_cache::flush_cache(), the lock is
acquired and the flag is reset, and one thread waiting on
Query_cache::flush_cache() (if any) is notified that it may
proceed.
include/mysql_com.h:
Add comment for NET::query_cache_query.
sql/net_serv.cc:
Use query_cache_init_query() for initialization of
NET::query_cache_query if query cache is used.
Do not access net->query_cache_query without a lock.
sql/sql_cache.cc:
Fix bug with accessing query_cache_size, Query_cache_query::wri and
thd->net.query_cache_query before acquiring the lock---leave
double-check locking only in safe places.
Wherever we check that cache is usable (query_cache_size > 0) we now
also check that flush_in_progress is false, i.e. we are not in the
middle of cache flush.
Add Query_cache::not_in_flush_or_wait() method and use it in
Query_cache::flush_cache(), so that threads doing cache flush will
wait it to finish, while other threads will bypass the cache as if
it is disabled.
Extract Query_cache::free_query_internal() from Query_cache::free_query(),
which does not removes elements from the hash, and use it together with
my_hash_reset() in Query_cache::flush_cache().
sql/sql_cache.h:
Add declarations for new members and methods.
Make is_cacheable() a static method.
Add query_cache_init_query() function.
sql/sql_class.cc:
Use query_cache_init_query() for initialization of
NET::query_cache_query.
This commit is contained in:
@@ -195,7 +195,6 @@ extern "C"
|
||||
byte *query_cache_table_get_key(const byte *record, uint *length,
|
||||
my_bool not_used);
|
||||
}
|
||||
void query_cache_insert(NET *thd, const char *packet, ulong length);
|
||||
extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
|
||||
|
||||
|
||||
@@ -241,6 +240,12 @@ public:
|
||||
ulong free_memory, queries_in_cache, hits, inserts, refused,
|
||||
free_memory_blocks, total_blocks, lowmem_prunes;
|
||||
|
||||
private:
|
||||
pthread_cond_t COND_flush_finished;
|
||||
bool flush_in_progress;
|
||||
|
||||
void free_query_internal(Query_cache_block *point);
|
||||
|
||||
protected:
|
||||
/*
|
||||
The following mutex is locked when searching or changing global
|
||||
@@ -249,6 +254,12 @@ protected:
|
||||
LOCK SEQUENCE (to prevent deadlocks):
|
||||
1. structure_guard_mutex
|
||||
2. query block (for operation inside query (query block/results))
|
||||
|
||||
Thread doing cache flush releases the mutex once it sets
|
||||
flush_in_progress flag, so other threads may bypass the cache as
|
||||
if it is disabled, not waiting for reset to finish. The exception
|
||||
is other threads that were going to do cache flush---they'll wait
|
||||
till the end of a flush operation.
|
||||
*/
|
||||
pthread_mutex_t structure_guard_mutex;
|
||||
byte *cache; // cache memory
|
||||
@@ -358,6 +369,7 @@ protected:
|
||||
If query is cacheable return number tables in query
|
||||
(query without tables not cached)
|
||||
*/
|
||||
static
|
||||
TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
|
||||
LEX *lex, TABLE_LIST *tables_used,
|
||||
uint8 *tables_type);
|
||||
@@ -410,6 +422,7 @@ protected:
|
||||
|
||||
void destroy();
|
||||
|
||||
friend void query_cache_init_query(NET *net);
|
||||
friend void query_cache_insert(NET *net, const char *packet, ulong length);
|
||||
friend void query_cache_end_of_result(THD *thd);
|
||||
friend void query_cache_abort(NET *net);
|
||||
@@ -435,6 +448,8 @@ protected:
|
||||
|
||||
extern Query_cache query_cache;
|
||||
extern TYPELIB query_cache_type_typelib;
|
||||
void query_cache_init_query(NET *net);
|
||||
void query_cache_insert(NET *net, const char *packet, ulong length);
|
||||
void query_cache_end_of_result(THD *thd);
|
||||
void query_cache_abort(NET *net);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user