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.cc68
1 files changed, 59 insertions, 9 deletions
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index f995b51ae68..302d5e95a28 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -377,9 +377,11 @@ TODO list:
static void debug_wait_for_kill(const char *info)
{
- DBUG_ENTER("debug_wait_for_kill");
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;
@@ -387,8 +389,16 @@ static void debug_wait_for_kill(const char *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;
}
@@ -421,12 +431,16 @@ TYPELIB query_cache_type_typelib=
effect by another thread. This enables a quick path in execution to skip waits
when the outcome is known.
+ @param use_timeout TRUE if the lock can abort because of a timeout.
+
+ @note use_timeout is optional and default value is FALSE.
+
@return
@retval FALSE An exclusive lock was taken
@retval TRUE The locking attempt failed
*/
-bool Query_cache::try_lock(void)
+bool Query_cache::try_lock(bool use_timeout)
{
bool interrupt= FALSE;
DBUG_ENTER("Query_cache::try_lock");
@@ -456,7 +470,26 @@ bool Query_cache::try_lock(void)
else
{
DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED);
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ /*
+ To prevent send_result_to_client() and query_cache_insert() from
+ blocking execution for too long a timeout is put on the lock.
+ */
+ if (use_timeout)
+ {
+ struct timespec waittime;
+ set_timespec_nsec(waittime,(ulong)(50000000L)); /* Wait for 50 msec */
+ int res= pthread_cond_timedwait(&COND_cache_status_changed,
+ &structure_guard_mutex,&waittime);
+ if (res == ETIMEDOUT)
+ {
+ interrupt= TRUE;
+ break;
+ }
+ }
+ else
+ {
+ pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ }
}
}
pthread_mutex_unlock(&structure_guard_mutex);
@@ -891,15 +924,18 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
void query_cache_abort(NET *net)
{
+ THD *thd;
DBUG_ENTER("query_cache_abort");
- THD *thd= current_thd;
/* See the comment on double-check locking usage above. */
if (net->query_cache_query == 0)
DBUG_VOID_RETURN;
if (query_cache.try_lock())
+ {
+ net->query_cache_query = 0;
DBUG_VOID_RETURN;
+ }
/*
While we were waiting another thread might have changed the status
@@ -909,6 +945,7 @@ void query_cache_abort(NET *net)
net->query_cache_query);
if (query_block)
{
+ thd= current_thd;
thd_proc_info(thd, "storing result in query cache");
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
@@ -918,6 +955,7 @@ void query_cache_abort(NET *net)
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
}
+ DBUG_ASSERT(!net->query_cache_query);
query_cache.unlock();
DBUG_VOID_RETURN;
}
@@ -947,8 +985,12 @@ void query_cache_end_of_result(THD *thd)
#endif
if (query_cache.try_lock())
+ {
+ thd->net.query_cache_query= 0;
DBUG_VOID_RETURN;
+ }
+ /* thd->net.query_cache_query may have changed during resize */
query_block= ((Query_cache_block*) thd->net.query_cache_query);
if (query_block)
{
@@ -974,8 +1016,8 @@ void query_cache_end_of_result(THD *thd)
to this function. In the release version that query should be ignored
and removed from QC.
*/
- DBUG_ASSERT(0);
query_cache.free_query(query_block);
+ thd->net.query_cache_query= 0;
query_cache.unlock();
DBUG_VOID_RETURN;
}
@@ -1190,8 +1232,14 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
A table- or a full flush operation can potentially take a long time to
finish. We choose not to wait for them and skip caching statements
instead.
+
+ 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 'TRUE' parameter indicate that the lock is allowed to timeout
+
*/
- if (try_lock())
+ if (try_lock(TRUE))
DBUG_VOID_RETURN;
if (query_cache_size == 0)
{
@@ -1306,8 +1354,8 @@ end:
to the user.
RESULTS
- 1 Query was not cached.
- 0 The query was cached and user was sent the result.
+ 0 Query was not cached.
+ 1 The query was cached and user was sent the result.
-1 The query was cached but we didn't have rights to use it.
No error is sent to the client yet.
@@ -1388,8 +1436,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Try to obtain an exclusive lock on the query cache. If the cache is
disabled or if a full cache flush is in progress, the attempt to
get the lock is aborted.
+
+ The 'TRUE' parameter indicate that the lock is allowed to timeout
*/
- if (try_lock())
+ if (try_lock(TRUE))
goto err;
if (query_cache_size == 0)