diff options
Diffstat (limited to 'sql/sql_cache.cc')
-rw-r--r-- | sql/sql_cache.cc | 125 |
1 files changed, 70 insertions, 55 deletions
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 30dd835e9eb..feb9614efe7 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -334,6 +334,7 @@ TODO list: #include "tztime.h" // struct Time_zone #include "sql_acl.h" // SELECT_ACL #include "sql_base.h" // TMP_TABLE_KEY_EXTRA +#include "debug_sync.h" // DEBUG_SYNC #ifdef HAVE_QUERY_CACHE #include <m_ctype.h> #include <my_dir.h> @@ -342,6 +343,7 @@ TODO list: #include "../storage/myisammrg/myrg_def.h" #include "probes_mysql.h" #include "log_slow.h" +#include "transaction.h" #ifdef EMBEDDED_LIBRARY #include "emb_qcache.h" @@ -371,42 +373,6 @@ 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) -{ - const char *prev_info; - THD *thd; - char buff[1024]; - DBUG_ENTER("debug_wait_for_kill"); - - thd= current_thd; - prev_info= thd->proc_info; - thd->proc_info= info; - sql_print_information("%s", info); - while(!thd->killed) - my_sleep(1000); - thd->killed= THD::NOT_KILLED; - /* - Remove the set debug variable, to ensure we don't get stuck on it again - This is needed as for MyISAM, invalidate_table() may be called twice - (Once from mysql_delete() and once from mi_update_status()) - */ - sprintf(buff, "-d,%s", info); - DBUG_SET(buff); - sql_print_information("Exit debug_wait_for_kill"); - thd->proc_info= prev_info; - - DBUG_VOID_RETURN; -} - #else #define RW_WLOCK(M) mysql_rwlock_wrlock(M) #define RW_RLOCK(M) mysql_rwlock_rdlock(M) @@ -418,6 +384,52 @@ static void debug_wait_for_kill(const char *info) #define DUMP(C) #endif + +/** + Macro that executes the requested action at a synchronization point + only if the thread has a associated THD session. +*/ +#if defined(ENABLED_DEBUG_SYNC) +#define QC_DEBUG_SYNC(name) \ + do { \ + THD *thd= current_thd; \ + if (thd) \ + DEBUG_SYNC(thd, name); \ + } while (0) +#else +#define QC_DEBUG_SYNC(name) +#endif + + +/** + Thread state to be used when the query cache lock needs to be acquired. + Sets the thread state name in the constructor, resets on destructor. +*/ + +struct Query_cache_wait_state +{ + THD *m_thd; + const char *m_proc_info; + + Query_cache_wait_state(THD *thd, const char *func, + const char *file, unsigned int line) + : m_thd(thd), + m_proc_info(NULL) + { + if (m_thd) + m_proc_info= set_thd_proc_info(m_thd, + "Waiting for query cache lock", + func, file, line); + } + + ~Query_cache_wait_state() + { + if (m_thd) + set_thd_proc_info(m_thd, m_proc_info, NULL, NULL, 0); + } +}; + + /** Serialize access to the query cache. If the lock cannot be granted the thread hangs in a conditional wait which @@ -439,6 +451,8 @@ static void debug_wait_for_kill(const char *info) bool Query_cache::try_lock(bool use_timeout) { bool interrupt= FALSE; + THD *thd= current_thd; + Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__); DBUG_ENTER("Query_cache::try_lock"); mysql_mutex_lock(&structure_guard_mutex); @@ -448,7 +462,6 @@ bool Query_cache::try_lock(bool use_timeout) { m_cache_lock_status= Query_cache::LOCKED; #ifndef DBUG_OFF - THD *thd= current_thd; if (thd) m_cache_lock_thread_id= thd->thread_id; #endif @@ -507,6 +520,8 @@ bool Query_cache::try_lock(bool use_timeout) void Query_cache::lock_and_suspend(void) { + THD *thd= current_thd; + Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__); DBUG_ENTER("Query_cache::lock_and_suspend"); mysql_mutex_lock(&structure_guard_mutex); @@ -514,7 +529,6 @@ void Query_cache::lock_and_suspend(void) mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); m_cache_lock_status= Query_cache::LOCKED_NO_WAIT; #ifndef DBUG_OFF - THD *thd= current_thd; if (thd) m_cache_lock_thread_id= thd->thread_id; #endif @@ -535,6 +549,8 @@ void Query_cache::lock_and_suspend(void) void Query_cache::lock(void) { + THD *thd= current_thd; + Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__); DBUG_ENTER("Query_cache::lock"); mysql_mutex_lock(&structure_guard_mutex); @@ -542,7 +558,6 @@ void Query_cache::lock(void) mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex); m_cache_lock_status= Query_cache::LOCKED; #ifndef DBUG_OFF - THD *thd= current_thd; if (thd) m_cache_lock_thread_id= thd->thread_id; #endif @@ -882,9 +897,7 @@ Query_cache::insert(Query_cache_tls *query_cache_tls, if (is_disabled() || query_cache_tls->first_query_block == NULL) DBUG_VOID_RETURN; - DBUG_EXECUTE_IF("wait_in_query_cache_insert", - debug_wait_for_kill("wait_in_query_cache_insert"); ); - + QC_DEBUG_SYNC("wait_in_query_cache_insert"); if (try_lock()) DBUG_VOID_RETURN; @@ -1695,6 +1708,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", } else thd->lex->safe_to_cache_query= 0; // Don't try to cache this + /* End the statement transaction potentially started by engine. */ + trans_rollback_stmt(thd); goto err_unlock; // Parse query } else @@ -1737,6 +1752,14 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", thd->limit_found_rows = query->found_rows(); thd->status_var.last_query_cost= 0.0; thd->query_plan_flags= (thd->query_plan_flags & ~QPLAN_QC_NO) | QPLAN_QC; + + /* + End the statement transaction potentially started by an + engine callback. We ignore the return value for now, + since as long as EOF packet is part of the query cache + response, we can't handle it anyway. + */ + (void) trans_commit_stmt(thd); if (!thd->stmt_da->is_set()) thd->stmt_da->disable_status(); @@ -1786,8 +1809,7 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used, invalidate_table(thd, tables_used); } - DBUG_EXECUTE_IF("wait_after_query_cache_invalidate", - debug_wait_for_kill("wait_after_query_cache_invalidate");); + DEBUG_SYNC(thd, "wait_after_query_cache_invalidate"); DBUG_VOID_RETURN; } @@ -1978,8 +2000,7 @@ void Query_cache::flush() if (is_disabled()) DBUG_VOID_RETURN; - DBUG_EXECUTE_IF("wait_in_query_cache_flush1", - debug_wait_for_kill("wait_in_query_cache_flush1");); + QC_DEBUG_SYNC("wait_in_query_cache_flush1"); lock_and_suspend(); if (query_cache_size > 0) @@ -2319,9 +2340,7 @@ void Query_cache::free_cache() void Query_cache::flush_cache() { - - DBUG_EXECUTE_IF("wait_in_query_cache_flush2", - debug_wait_for_kill("wait_in_query_cache_flush2");); + QC_DEBUG_SYNC("wait_in_query_cache_flush2"); my_hash_reset(&queries); while (queries_blocks != 0) @@ -2767,8 +2786,7 @@ void Query_cache::invalidate_table(THD *thd, TABLE *table) void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length) { - DBUG_EXECUTE_IF("wait_in_query_cache_invalidate1", - debug_wait_for_kill("wait_in_query_cache_invalidate1"); ); + DEBUG_SYNC(thd, "wait_in_query_cache_invalidate1"); /* Lock the query cache and queue all invalidation attempts to avoid @@ -2776,9 +2794,7 @@ void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length) */ lock(); - DBUG_EXECUTE_IF("wait_in_query_cache_invalidate2", - debug_wait_for_kill("wait_in_query_cache_invalidate2"); ); - + DEBUG_SYNC(thd, "wait_in_query_cache_invalidate2"); if (query_cache_size > 0) invalidate_table_internal(thd, key, key_length); @@ -2828,7 +2844,6 @@ Query_cache::invalidate_query_block_list(THD *thd, Query_cache_block *query_block= list_root->next->block(); BLOCK_LOCK_WR(query_block); free_query(query_block); - DBUG_EXECUTE_IF("debug_cache_locks", sleep(10);); } } |