diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0794d7fee6159..0cb42d485233f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8212,6 +8212,7 @@ SHOW_VAR status_vars[]= { {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG}, {"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG}, {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG}, + {"Qcache_concurrency_refused", (char*) &query_cache.concurrency_refused, SHOW_LONG}, {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_NOFLUSH}, {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_NOFLUSH}, #endif /*HAVE_QUERY_CACHE*/ diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index cf68ba369978e..95771c3facc70 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -586,7 +586,7 @@ void inline fix_local_query_cache_mode(THD *thd) effect by another thread. This enables a quick path in execution to skip waits when the outcome is known. - @param mode TIMEOUT the lock can abort because of a timeout + @param mode TIMEOUT_WRITE/TIMEOUT_READ the lock can abort because of a timeout TRY the lock can abort because it is locked now WAIT wait for lock (default) @@ -643,10 +643,29 @@ bool Query_cache::try_lock(THD *thd, Cache_try_lock_mode mode) { mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); } - else if (mode == TIMEOUT) + else if (mode == TIMEOUT_READ || mode == TIMEOUT_WRITE) { struct timespec waittime; - set_timespec_nsec(waittime,(ulong)(50000000L)); /* Wait for 50 msec */ + if(mode == TIMEOUT_WRITE){ + if(thd->variables.query_cache_write_timeout<=0) + /* Default: wait for 50 msec (nano time value=> 50.000.000ns = 50ms) */ + thd->variables.query_cache_write_timeout=50000000L; + if(thd->variables.query_cache_write_timeout>1000000000L; + /* Max value of 1s (1.000.000.000) */ + thd->variables.query_cache_write_timeout=1000000000L; + + set_timespec_nsec(waittime,(ulong)(thd->variables.query_cache_write_timeout)); + } + else + { + if(thd->variables.query_cache_read_timeout<=0) + /* Default: wait for 50 msec (nano time value=> 50.000.000ns = 50ms) */ + thd->variables.query_cache_read_timeout=50000000L; + if(thd->variables.query_cache_read_timeout>1000000000L; + /* Max value of 1s (1.000.000.000) */ + thd->variables.query_cache_read_timeout=1000000000L; + set_timespec_nsec(waittime,(ulong)(thd->variables.query_cache_read_timeout)); + } int res= mysql_cond_timedwait(&COND_cache_status_changed, &structure_guard_mutex, &waittime); if (res == ETIMEDOUT) @@ -1275,6 +1294,7 @@ Query_cache::Query_cache(ulong query_cache_limit_arg, query_cache_limit(query_cache_limit_arg), queries_in_cache(0), hits(0), inserts(0), refused(0), total_blocks(0), lowmem_prunes(0), + concurrency_refused(0), m_cache_status(OK), min_allocation_unit(ALIGN_SIZE(min_allocation_unit_arg)), min_result_data_size(ALIGN_SIZE(min_result_data_size_arg)), @@ -1474,10 +1494,10 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", In case the wait time can't be determined there is an upper limit which causes try_lock() to abort with a time out. - The 'TIMEOUT' parameter indicate that the lock is allowed to timeout + The TIMEOUT_WRITE parameter indicate that the lock is allowed to timeout */ - if (try_lock(thd, Query_cache::TIMEOUT)) + if (try_lock(thd, Query_cache::TIMEOUT_WRITE)) DBUG_VOID_RETURN; if (query_cache_size == 0) { @@ -1576,6 +1596,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", } else { + // Concorrency counter + concurrency_refused++; // Another thread is processing the same query => do nothing refused++; unlock(); @@ -1853,9 +1875,9 @@ Query_cache::send_result_to_client(THD *thd, char *org_sql, uint query_length) disabled or if a full cache flush is in progress, the attempt to get the lock is aborted. - The TIMEOUT parameter indicate that the lock is allowed to timeout. + The TIMEOUT_READ parameter indicate that the lock is allowed to timeout. */ - if (try_lock(thd, Query_cache::TIMEOUT)) + if (try_lock(thd, Query_cache::TIMEOUT_READ)) goto err; if (query_cache_size == 0) diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 69520d668acdb..5b85a09e2987a 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -294,7 +294,8 @@ class Query_cache ulong query_cache_size, query_cache_limit; /* statistics */ ulong free_memory, queries_in_cache, hits, inserts, refused, - free_memory_blocks, total_blocks, lowmem_prunes; + free_memory_blocks, total_blocks, lowmem_prunes, + concurrency_refused; private: @@ -524,7 +525,7 @@ class Query_cache static uint filename_2_table_key (char *key, const char *filename, uint32 *db_langth); - enum Cache_try_lock_mode {WAIT, TIMEOUT, TRY}; + enum Cache_try_lock_mode {WAIT, TIMEOUT_WRITE, TIMEOUT_READ, TRY}; bool try_lock(THD *thd, Cache_try_lock_mode mode= WAIT); void lock(THD *thd); void lock_and_suspend(void); diff --git a/sql/sql_class.h b/sql/sql_class.h index 3424a3380f029..1f7395bd030ba 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -570,6 +570,8 @@ typedef struct system_variables ulong progress_report_time; ulong completion_type; ulong query_cache_type; + ulong query_cache_write_timeout; + ulong query_cache_read_timeout; ulong tx_isolation; ulong updatable_views_with_limit; int max_user_connections; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 0c68409dd2567..d4708f39ac6eb 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2539,6 +2539,18 @@ static Sys_var_enum Sys_thread_handling( ); #ifdef HAVE_QUERY_CACHE +static Sys_var_ulong Sys_query_cache_write_timeout( + "query_cache_write_timeout", + "Timeout in nanoseconds waiting lock in query cache insert, " + "default of 50000000 ns = 50ms", + SESSION_VAR(query_cache_write_timeout), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 1000000000L), DEFAULT(50000000), BLOCK_SIZE(1)); +static Sys_var_ulong Sys_query_cache_read_timeout( + "query_cache_read_timeout", + "Timeout in nanoseconds waiting lock in query cache fetch, " + "default of 50000000 ns = 50ms", + SESSION_VAR(query_cache_read_timeout), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, 1000000000L), DEFAULT(50000000), BLOCK_SIZE(1)); static bool check_query_cache_size(sys_var *self, THD *thd, set_var *var) { if (global_system_variables.query_cache_type == 0 &&