mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Creation of mysql-trunk = {summit + "Innodb plugin replacing the builtin"}:
bzr branch mysql-5.1-performance-version mysql-trunk # Summit cd mysql-trunk bzr merge mysql-5.1-innodb_plugin # which is 5.1 + Innodb plugin bzr rm innobase # remove the builtin Next step: build, test fixes.
This commit is contained in:
428
sql/sql_cache.cc
428
sql/sql_cache.cc
@ -353,11 +353,6 @@ TODO list:
|
||||
#define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \
|
||||
if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \
|
||||
else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); }
|
||||
#define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \
|
||||
pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));}
|
||||
#define STRUCT_UNLOCK(M) { \
|
||||
DBUG_PRINT("lock", ("%d struct unlock...",__LINE__)); \
|
||||
pthread_mutex_unlock(M);DBUG_PRINT("lock", ("struct unlock OK"));}
|
||||
#define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
|
||||
__LINE__,(ulong)(B))); \
|
||||
B->query()->lock_writing();}
|
||||
@ -404,8 +399,6 @@ static void debug_wait_for_kill(const char *info)
|
||||
#define RW_WLOCK(M) rw_wrlock(M)
|
||||
#define RW_RLOCK(M) rw_rdlock(M)
|
||||
#define RW_UNLOCK(M) rw_unlock(M)
|
||||
#define STRUCT_LOCK(M) pthread_mutex_lock(M)
|
||||
#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
|
||||
#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
|
||||
#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
|
||||
#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
|
||||
@ -420,6 +413,140 @@ TYPELIB query_cache_type_typelib=
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Serialize access to the query cache.
|
||||
If the lock cannot be granted the thread hangs in a conditional wait which
|
||||
is signalled on each unlock.
|
||||
|
||||
The lock attempt will also fail without wait if lock_and_suspend() is in
|
||||
effect by another thread. This enables a quick path in execution to skip waits
|
||||
when the outcome is known.
|
||||
|
||||
@return
|
||||
@retval FALSE An exclusive lock was taken
|
||||
@retval TRUE The locking attempt failed
|
||||
*/
|
||||
|
||||
bool Query_cache::try_lock(void)
|
||||
{
|
||||
bool interrupt= FALSE;
|
||||
DBUG_ENTER("Query_cache::try_lock");
|
||||
|
||||
pthread_mutex_lock(&structure_guard_mutex);
|
||||
while (1)
|
||||
{
|
||||
if (m_cache_lock_status == Query_cache::UNLOCKED)
|
||||
{
|
||||
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
|
||||
break;
|
||||
}
|
||||
else if (m_cache_lock_status == Query_cache::LOCKED_NO_WAIT)
|
||||
{
|
||||
/*
|
||||
If query cache is protected by a LOCKED_NO_WAIT lock this thread
|
||||
should avoid using the query cache as it is being evicted.
|
||||
*/
|
||||
interrupt= TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED);
|
||||
pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&structure_guard_mutex);
|
||||
|
||||
DBUG_RETURN(interrupt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Serialize access to the query cache.
|
||||
If the lock cannot be granted the thread hangs in a conditional wait which
|
||||
is signalled on each unlock.
|
||||
|
||||
This method also suspends the query cache so that other threads attempting to
|
||||
lock the cache with try_lock() will fail directly without waiting.
|
||||
|
||||
It is used by all methods which flushes or destroys the whole cache.
|
||||
*/
|
||||
|
||||
void Query_cache::lock_and_suspend(void)
|
||||
{
|
||||
DBUG_ENTER("Query_cache::lock_and_suspend");
|
||||
|
||||
pthread_mutex_lock(&structure_guard_mutex);
|
||||
while (m_cache_lock_status != Query_cache::UNLOCKED)
|
||||
pthread_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
|
||||
/* Wake up everybody, a whole cache flush is starting! */
|
||||
pthread_cond_broadcast(&COND_cache_status_changed);
|
||||
pthread_mutex_unlock(&structure_guard_mutex);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/**
|
||||
Serialize access to the query cache.
|
||||
If the lock cannot be granted the thread hangs in a conditional wait which
|
||||
is signalled on each unlock.
|
||||
|
||||
It is used by all methods which invalidates one or more tables.
|
||||
*/
|
||||
|
||||
void Query_cache::lock(void)
|
||||
{
|
||||
DBUG_ENTER("Query_cache::lock");
|
||||
|
||||
pthread_mutex_lock(&structure_guard_mutex);
|
||||
while (m_cache_lock_status != Query_cache::UNLOCKED)
|
||||
pthread_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
|
||||
pthread_mutex_unlock(&structure_guard_mutex);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the query cache to UNLOCKED and signal waiting threads.
|
||||
*/
|
||||
|
||||
void Query_cache::unlock(void)
|
||||
{
|
||||
DBUG_ENTER("Query_cache::unlock");
|
||||
pthread_mutex_lock(&structure_guard_mutex);
|
||||
#ifndef DBUG_OFF
|
||||
THD *thd= current_thd;
|
||||
if (thd)
|
||||
DBUG_ASSERT(m_cache_lock_thread_id == thd->thread_id);
|
||||
#endif
|
||||
DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED ||
|
||||
m_cache_lock_status == Query_cache::LOCKED_NO_WAIT);
|
||||
m_cache_lock_status= Query_cache::UNLOCKED;
|
||||
DBUG_PRINT("Query_cache",("Sending signal"));
|
||||
pthread_cond_signal(&COND_cache_status_changed);
|
||||
pthread_mutex_unlock(&structure_guard_mutex);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Helper function for determine if a SELECT statement has a SQL_NO_CACHE
|
||||
directive.
|
||||
@ -714,14 +841,8 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
|
||||
DBUG_EXECUTE_IF("wait_in_query_cache_insert",
|
||||
debug_wait_for_kill("wait_in_query_cache_insert"); );
|
||||
|
||||
STRUCT_LOCK(&query_cache.structure_guard_mutex);
|
||||
bool interrupt;
|
||||
query_cache.wait_while_table_flush_is_in_progress(&interrupt);
|
||||
if (interrupt)
|
||||
{
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
if (query_cache.try_lock())
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
Query_cache_block *query_block= (Query_cache_block*)net->query_cache_query;
|
||||
if (!query_block)
|
||||
@ -730,7 +851,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
|
||||
We lost the writer and the currently processed query has been
|
||||
invalidated; there is nothing left to do.
|
||||
*/
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
query_cache.unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -756,7 +877,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
|
||||
query_cache.free_query(query_block);
|
||||
query_cache.refused++;
|
||||
// append_result_data no success => we need unlock
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
query_cache.unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -778,14 +899,8 @@ void query_cache_abort(NET *net)
|
||||
if (net->query_cache_query == 0)
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
STRUCT_LOCK(&query_cache.structure_guard_mutex);
|
||||
bool interrupt;
|
||||
query_cache.wait_while_table_flush_is_in_progress(&interrupt);
|
||||
if (interrupt)
|
||||
{
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
if (query_cache.try_lock())
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
While we were waiting another thread might have changed the status
|
||||
@ -804,8 +919,7 @@ void query_cache_abort(NET *net)
|
||||
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
||||
}
|
||||
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
|
||||
query_cache.unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -833,15 +947,8 @@ void query_cache_end_of_result(THD *thd)
|
||||
emb_count_querycache_size(thd));
|
||||
#endif
|
||||
|
||||
STRUCT_LOCK(&query_cache.structure_guard_mutex);
|
||||
|
||||
bool interrupt;
|
||||
query_cache.wait_while_table_flush_is_in_progress(&interrupt);
|
||||
if (interrupt)
|
||||
{
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
if (query_cache.try_lock())
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
query_block= ((Query_cache_block*) thd->net.query_cache_query);
|
||||
if (query_block)
|
||||
@ -870,10 +977,9 @@ void query_cache_end_of_result(THD *thd)
|
||||
*/
|
||||
DBUG_ASSERT(0);
|
||||
query_cache.free_query(query_block);
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
query_cache.unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
last_result_block= header->result()->prev;
|
||||
allign_size= ALIGN_SIZE(last_result_block->used);
|
||||
len= max(query_cache.min_allocation_unit, allign_size);
|
||||
@ -886,13 +992,11 @@ void query_cache_end_of_result(THD *thd)
|
||||
/* Drop the writer. */
|
||||
header->writer(0);
|
||||
thd->net.query_cache_query= 0;
|
||||
|
||||
BLOCK_UNLOCK_WR(query_block);
|
||||
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
||||
|
||||
}
|
||||
|
||||
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
|
||||
query_cache.unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -952,11 +1056,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
|
||||
query_cache_size_arg));
|
||||
DBUG_ASSERT(initialized);
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
while (is_flushing())
|
||||
pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
|
||||
m_cache_status= Query_cache::FLUSH_IN_PROGRESS;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
lock_and_suspend();
|
||||
|
||||
/*
|
||||
Wait for all readers and writers to exit. When the list of all queries
|
||||
@ -988,13 +1088,10 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
|
||||
query_cache_size= query_cache_size_arg;
|
||||
new_query_cache_size= init_cache();
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
|
||||
pthread_cond_signal(&COND_cache_status_changed);
|
||||
if (new_query_cache_size)
|
||||
DBUG_EXECUTE("check_querycache",check_integrity(1););
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
|
||||
unlock();
|
||||
DBUG_RETURN(new_query_cache_size);
|
||||
}
|
||||
|
||||
@ -1091,15 +1188,16 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
*/
|
||||
ha_release_temporary_latches(thd);
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
if (query_cache_size == 0 || is_flushing())
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
if (try_lock())
|
||||
DBUG_VOID_RETURN;
|
||||
if (query_cache_size == 0)
|
||||
{
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
DUMP(this);
|
||||
@ -1107,7 +1205,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
if (ask_handler_allowance(thd, tables_used))
|
||||
{
|
||||
refused++;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -1155,7 +1253,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
DBUG_PRINT("qcache", ("insertion in query hash"));
|
||||
header->unlock_n_destroy();
|
||||
free_memory_block(query_block);
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
goto end;
|
||||
}
|
||||
if (!register_all_tables(query_block, tables_used, local_tables))
|
||||
@ -1165,7 +1263,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
hash_delete(&queries, (uchar *) query_block);
|
||||
header->unlock_n_destroy();
|
||||
free_memory_block(query_block);
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
goto end;
|
||||
}
|
||||
double_linked_list_simple_include(query_block, &queries_blocks);
|
||||
@ -1175,7 +1273,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
header->writer(net);
|
||||
header->tables_type(tables_type);
|
||||
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
|
||||
// init_n_lock make query block locked
|
||||
BLOCK_UNLOCK_WR(query_block);
|
||||
@ -1184,7 +1282,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
{
|
||||
// We have not enough memory to store query => do nothing
|
||||
refused++;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_PRINT("warning", ("Can't allocate query"));
|
||||
}
|
||||
}
|
||||
@ -1192,7 +1290,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
{
|
||||
// Another thread is processing the same query => do nothing
|
||||
refused++;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_PRINT("qcache", ("Another thread process same query"));
|
||||
}
|
||||
}
|
||||
@ -1291,18 +1389,17 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
|
||||
}
|
||||
}
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
if (try_lock())
|
||||
goto err;
|
||||
|
||||
if (query_cache_size == 0)
|
||||
goto err_unlock;
|
||||
|
||||
if (is_flushing())
|
||||
{
|
||||
/* Return; Query cache is temporarily disabled while we flush. */
|
||||
DBUG_PRINT("qcache",("query cache disabled"));
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
Check that we haven't forgot to reset the query cache variables;
|
||||
make sure there are no attached query cache writer to this thread.
|
||||
@ -1436,7 +1533,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
DBUG_PRINT("qcache",
|
||||
("Temporary table detected: '%s.%s'",
|
||||
table_list.db, table_list.alias));
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
/*
|
||||
We should not store result of this query because it contain
|
||||
temporary tables => assign following variable to make check
|
||||
@ -1457,7 +1554,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
DBUG_PRINT("qcache",
|
||||
("probably no SELECT access to %s.%s => return to normal processing",
|
||||
table_list.db, table_list.alias));
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
thd->lex->safe_to_cache_query=0; // Don't try to cache this
|
||||
BLOCK_UNLOCK_RD(query_block);
|
||||
DBUG_RETURN(-1); // Privilege error
|
||||
@ -1500,7 +1597,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
}
|
||||
move_to_query_list_end(query_block);
|
||||
hits++;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
|
||||
/*
|
||||
Send cached result to client
|
||||
@ -1540,7 +1637,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
|
||||
DBUG_RETURN(1); // Result sent to client
|
||||
|
||||
err_unlock:
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
err:
|
||||
MYSQL_QUERY_CACHE_MISS(thd->query);
|
||||
DBUG_RETURN(0); // Query was not cached
|
||||
@ -1661,47 +1758,6 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Synchronize the thread with any flushing operations.
|
||||
|
||||
This helper function is called whenever a thread needs to operate on the
|
||||
query cache structure (example: during invalidation). If a table flush is in
|
||||
progress this function will wait for it to stop. If a full flush is in
|
||||
progress, the function will set the interrupt parameter to indicate that the
|
||||
current operation is redundant and should be interrupted.
|
||||
|
||||
@param[out] interrupt This out-parameter will be set to TRUE if the calling
|
||||
function is redundant and should be interrupted.
|
||||
|
||||
@return If the interrupt-parameter is TRUE then m_cache_status is set to
|
||||
NO_FLUSH_IN_PROGRESS. If the interrupt-parameter is FALSE then
|
||||
m_cache_status is set to FLUSH_IN_PROGRESS.
|
||||
The structure_guard_mutex will in any case be locked.
|
||||
*/
|
||||
|
||||
void Query_cache::wait_while_table_flush_is_in_progress(bool *interrupt)
|
||||
{
|
||||
while (is_flushing())
|
||||
{
|
||||
/*
|
||||
If there already is a full flush in progress query cache isn't enabled
|
||||
and additional flushes are redundant; just return instead.
|
||||
*/
|
||||
if (m_cache_status == Query_cache::FLUSH_IN_PROGRESS)
|
||||
{
|
||||
*interrupt= TRUE;
|
||||
return;
|
||||
}
|
||||
/*
|
||||
If a table flush is in progress; wait on cache status to change.
|
||||
*/
|
||||
if (m_cache_status == Query_cache::TABLE_FLUSH_IN_PROGRESS)
|
||||
pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
|
||||
}
|
||||
*interrupt= FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove all cached queries that uses the given database.
|
||||
*/
|
||||
@ -1711,14 +1767,11 @@ void Query_cache::invalidate(char *db)
|
||||
bool restart= FALSE;
|
||||
DBUG_ENTER("Query_cache::invalidate (db)");
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
bool interrupt;
|
||||
wait_while_table_flush_is_in_progress(&interrupt);
|
||||
if (interrupt)
|
||||
{
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
Lock the query cache and queue all invalidation attempts to avoid
|
||||
the risk of a race between invalidation, cache inserts and flushes.
|
||||
*/
|
||||
lock();
|
||||
|
||||
THD *thd= current_thd;
|
||||
|
||||
@ -1774,7 +1827,7 @@ void Query_cache::invalidate(char *db)
|
||||
} while (restart);
|
||||
} // end if( tables_blocks )
|
||||
}
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -1798,7 +1851,10 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
|
||||
void Query_cache::flush()
|
||||
{
|
||||
DBUG_ENTER("Query_cache::flush");
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
DBUG_EXECUTE_IF("wait_in_query_cache_flush1",
|
||||
debug_wait_for_kill("wait_in_query_cache_flush1"););
|
||||
|
||||
lock_and_suspend();
|
||||
if (query_cache_size > 0)
|
||||
{
|
||||
DUMP(this);
|
||||
@ -1807,7 +1863,7 @@ void Query_cache::flush()
|
||||
}
|
||||
|
||||
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -1826,18 +1882,16 @@ void Query_cache::pack(ulong join_limit, uint iteration_limit)
|
||||
{
|
||||
DBUG_ENTER("Query_cache::pack");
|
||||
|
||||
bool interrupt;
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
wait_while_table_flush_is_in_progress(&interrupt);
|
||||
if (interrupt)
|
||||
{
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
/*
|
||||
If the entire qc is being invalidated we can bail out early
|
||||
instead of waiting for the lock.
|
||||
*/
|
||||
if (try_lock())
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
if (query_cache_size == 0)
|
||||
{
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -1847,7 +1901,7 @@ void Query_cache::pack(ulong join_limit, uint iteration_limit)
|
||||
pack_cache();
|
||||
} while ((++i < iteration_limit) && join_results(join_limit));
|
||||
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -1862,9 +1916,9 @@ void Query_cache::destroy()
|
||||
else
|
||||
{
|
||||
/* Underlying code expects the lock. */
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
lock_and_suspend();
|
||||
free_cache();
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
|
||||
pthread_cond_destroy(&COND_cache_status_changed);
|
||||
pthread_mutex_destroy(&structure_guard_mutex);
|
||||
@ -1883,7 +1937,7 @@ void Query_cache::init()
|
||||
DBUG_ENTER("Query_cache::init");
|
||||
pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&COND_cache_status_changed, NULL);
|
||||
m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
|
||||
m_cache_lock_status= Query_cache::UNLOCKED;
|
||||
initialized = 1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -2123,23 +2177,9 @@ void Query_cache::free_cache()
|
||||
|
||||
void Query_cache::flush_cache()
|
||||
{
|
||||
/*
|
||||
If there is flush in progress, wait for it to finish, and then do
|
||||
our flush. This is necessary because something could be added to
|
||||
the cache before we acquire the lock again, and some code (like
|
||||
Query_cache::free_cache()) depends on the fact that after the
|
||||
flush the cache is empty.
|
||||
*/
|
||||
while (is_flushing())
|
||||
pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
|
||||
|
||||
/*
|
||||
Setting 'FLUSH_IN_PROGRESS' will prevent other threads from using
|
||||
the cache while we are in the middle of the flush, and we release
|
||||
the lock so that other threads won't block.
|
||||
*/
|
||||
m_cache_status= Query_cache::FLUSH_IN_PROGRESS;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
|
||||
DBUG_EXECUTE_IF("wait_in_query_cache_flush2",
|
||||
debug_wait_for_kill("wait_in_query_cache_flush2"););
|
||||
|
||||
my_hash_reset(&queries);
|
||||
while (queries_blocks != 0)
|
||||
@ -2147,10 +2187,6 @@ void Query_cache::flush_cache()
|
||||
BLOCK_LOCK_WR(queries_blocks);
|
||||
free_query_internal(queries_blocks);
|
||||
}
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
|
||||
pthread_cond_signal(&COND_cache_status_changed);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2330,10 +2366,6 @@ Query_cache::write_block_data(ulong data_len, uchar* data,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be done.
|
||||
*/
|
||||
|
||||
my_bool
|
||||
Query_cache::append_result_data(Query_cache_block **current_block,
|
||||
ulong data_len, uchar* data,
|
||||
@ -2353,10 +2385,6 @@ Query_cache::append_result_data(Query_cache_block **current_block,
|
||||
if (*current_block == 0)
|
||||
{
|
||||
DBUG_PRINT("qcache", ("allocated first result data block %lu", data_len));
|
||||
/*
|
||||
STRUCT_UNLOCK(&structure_guard_mutex) Will be done by
|
||||
write_result_data if success;
|
||||
*/
|
||||
DBUG_RETURN(write_result_data(current_block, data_len, data, query_block,
|
||||
Query_cache_block::RES_BEG));
|
||||
}
|
||||
@ -2387,10 +2415,6 @@ Query_cache::append_result_data(Query_cache_block **current_block,
|
||||
DBUG_PRINT("qcache", ("allocate new block for %lu bytes",
|
||||
data_len-last_block_free_space));
|
||||
Query_cache_block *new_block = 0;
|
||||
/*
|
||||
On success STRUCT_UNLOCK(&structure_guard_mutex) will be done
|
||||
by the next call
|
||||
*/
|
||||
success = write_result_data(&new_block, data_len-last_block_free_space,
|
||||
(uchar*)(((uchar*)data)+last_block_free_space),
|
||||
query_block,
|
||||
@ -2405,7 +2429,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
|
||||
else
|
||||
{
|
||||
// It is success (nobody can prevent us write data)
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
}
|
||||
|
||||
// Now finally write data to the last block
|
||||
@ -2443,7 +2467,7 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block,
|
||||
if (success)
|
||||
{
|
||||
// It is success (nobody can prevent us write data)
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
uint headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
|
||||
ALIGN_SIZE(sizeof(Query_cache_result)));
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
@ -2601,6 +2625,18 @@ void Query_cache::invalidate_table(THD *thd, TABLE *table)
|
||||
|
||||
void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
|
||||
{
|
||||
#ifdef TO_BE_REMOVED
|
||||
/*
|
||||
This ifdef'd piece comes from Summit, it's a manual backport (2008-10-15) of
|
||||
http://lists.mysql.com/commits/56418.
|
||||
But that was an early, non-final patch: after that backport was made, the
|
||||
author of the patch decided to abandon it, and his final patch (put into 6.0)
|
||||
was different.
|
||||
Then 5.1's code was changed for some other reasons, so now we have a
|
||||
conflict between the old patch backported to Summit and the latest 5.1.
|
||||
The backport cannot stay, it has to be removed and then rewritten if
|
||||
desired.
|
||||
*/
|
||||
bool interrupt;
|
||||
|
||||
if (m_query_cache_is_disabled)
|
||||
@ -2619,28 +2655,35 @@ void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
return;
|
||||
}
|
||||
||||||| BASE-REVISION
|
||||
bool interrupt;
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
wait_while_table_flush_is_in_progress(&interrupt);
|
||||
if (interrupt)
|
||||
{
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
return;
|
||||
}
|
||||
=======
|
||||
/* current 5.1 code: */
|
||||
#endif
|
||||
DBUG_EXECUTE_IF("wait_in_query_cache_invalidate1",
|
||||
debug_wait_for_kill("wait_in_query_cache_invalidate1"); );
|
||||
|
||||
/*
|
||||
Setting 'TABLE_FLUSH_IN_PROGRESS' will temporarily disable the cache
|
||||
so that structural changes to cache won't block the entire server.
|
||||
However, threads requesting to change the query cache will still have
|
||||
to wait for the flush to finish.
|
||||
Lock the query cache and queue all invalidation attempts to avoid
|
||||
the risk of a race between invalidation, cache inserts and flushes.
|
||||
*/
|
||||
m_cache_status= Query_cache::TABLE_FLUSH_IN_PROGRESS;
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
lock();
|
||||
|
||||
DBUG_EXECUTE_IF("wait_in_query_cache_invalidate2",
|
||||
debug_wait_for_kill("wait_in_query_cache_invalidate2"); );
|
||||
|
||||
|
||||
if (query_cache_size > 0)
|
||||
invalidate_table_internal(thd, key, key_length);
|
||||
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
|
||||
|
||||
/*
|
||||
net_real_write might be waiting on a change on the m_cache_status
|
||||
variable.
|
||||
*/
|
||||
pthread_cond_signal(&COND_cache_status_changed);
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
@ -2649,7 +2692,7 @@ void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
|
||||
The caller must ensure that no other thread is trying to work with
|
||||
the query cache when this function is executed.
|
||||
|
||||
@pre structure_guard_mutex is acquired or TABLE_FLUSH_IN_PROGRESS is set.
|
||||
@pre structure_guard_mutex is acquired or LOCKED is set.
|
||||
*/
|
||||
|
||||
void
|
||||
@ -2667,7 +2710,7 @@ Query_cache::invalidate_table_internal(THD *thd, uchar *key, uint32 key_length)
|
||||
/**
|
||||
Invalidate a linked list of query cache blocks.
|
||||
|
||||
Each block tries to aquire a block level lock before
|
||||
Each block tries to acquire a block level lock before
|
||||
free_query is a called. This function will in turn affect
|
||||
related table- and result-blocks.
|
||||
|
||||
@ -4191,10 +4234,7 @@ my_bool Query_cache::check_integrity(bool locked)
|
||||
DBUG_ENTER("check_integrity");
|
||||
|
||||
if (!locked)
|
||||
STRUCT_LOCK(&structure_guard_mutex);
|
||||
|
||||
while (is_flushing())
|
||||
pthread_cond_wait(&COND_cache_status_changed,&structure_guard_mutex);
|
||||
lock_and_suspend();
|
||||
|
||||
if (hash_check(&queries))
|
||||
{
|
||||
@ -4443,7 +4483,7 @@ my_bool Query_cache::check_integrity(bool locked)
|
||||
}
|
||||
DBUG_ASSERT(result == 0);
|
||||
if (!locked)
|
||||
STRUCT_UNLOCK(&structure_guard_mutex);
|
||||
unlock();
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user