summaryrefslogtreecommitdiff
path: root/sql/sql_cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_cache.cc')
-rw-r--r--sql/sql_cache.cc125
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););
}
}