diff options
author | Kristofer Pettersson <kristofer.pettersson@sun.com> | 2009-10-19 15:00:38 +0200 |
---|---|---|
committer | Kristofer Pettersson <kristofer.pettersson@sun.com> | 2009-10-19 15:00:38 +0200 |
commit | d1b03b432fff88d5a0a1c3cb5eabb9bdc434c8ae (patch) | |
tree | bdacd3d55076a3cdb1fd8dcc23dc264a2f7073fc /sql/sql_cache.cc | |
parent | 0659b857e7fe232ebfe7f48c5e0affd59dbf5862 (diff) | |
parent | b7c3a76cfe1b24283bea37d82d33444ed95aa6e5 (diff) | |
download | mariadb-git-d1b03b432fff88d5a0a1c3cb5eabb9bdc434c8ae.tar.gz |
Automerge
Diffstat (limited to 'sql/sql_cache.cc')
-rw-r--r-- | sql/sql_cache.cc | 214 |
1 files changed, 117 insertions, 97 deletions
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index e4eb1e012b5..aed32497009 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -789,19 +789,20 @@ uchar *query_cache_query_get_key(const uchar *record, size_t *length, Note on double-check locking (DCL) usage. Below, in query_cache_insert(), query_cache_abort() and - query_cache_end_of_result() we use what is called double-check - locking (DCL) for NET::query_cache_query. I.e. we test it first - without a lock, and, if positive, test again under the lock. + Query_cache::end_of_result() we use what is called double-check + locking (DCL) for Query_cache_tls::first_query_block. + I.e. we test it first without a lock, and, if positive, test again + under the lock. - This means that if we see 'NET::query_cache_query == 0' without a + This means that if we see 'first_query_block == 0' without a lock we will skip the operation. But this is safe here: when we started to cache a query, we called Query_cache::store_query(), and - NET::query_cache_query was set to non-zero in this thread (and the + 'first_query_block' was set to non-zero in this thread (and the thread always sees results of its memory operations, mutex or not). - If later we see 'NET::query_cache_query == 0' without locking a + If later we see 'first_query_block == 0' without locking a mutex, that may only mean that some other thread have reset it by invalidating the query. Skipping the operation in this case is the - right thing to do, as NET::query_cache_query won't get non-zero for + right thing to do, as first_query_block won't get non-zero for this query again. See also comments in Query_cache::store_query() and @@ -810,56 +811,71 @@ uchar *query_cache_query_get_key(const uchar *record, size_t *length, NOTE, however, that double-check locking is not applicable in 'invalidate' functions, as we may erroneously skip invalidation, because the thread doing invalidation may never see non-zero - NET::query_cache_query. + 'first_query_block'. */ -void query_cache_init_query(NET *net) +/** + libmysql convenience wrapper to insert data into query cache. +*/ +void query_cache_insert(const char *packet, ulong length, + unsigned pkt_nr) { + THD *thd= current_thd; + /* - It is safe to initialize 'NET::query_cache_query' without a lock - here, because before it will be accessed from different threads it - will be set in this thread under a lock, and access from the same - thread is always safe. + Current_thd can be NULL when a new connection is immediately ended + due to "Too many connections". thd->store_globals() has not been + called at this time and hence my_pthread_setspecific_ptr(THR_THD, + this) has not been called for this thread. */ - net->query_cache_query= 0; + + if (!thd) + return; + + query_cache.insert(&thd->query_cache_tls, + packet, length, + pkt_nr); } -/* +/** Insert the packet into the query cache. */ -void query_cache_insert(NET *net, const char *packet, ulong length) +void +Query_cache::insert(Query_cache_tls *query_cache_tls, + const char *packet, ulong length, + unsigned pkt_nr) { - DBUG_ENTER("query_cache_insert"); + DBUG_ENTER("Query_cache::insert"); /* See the comment on double-check locking usage above. */ - if (net->query_cache_query == 0) + if (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"); ); - if (query_cache.try_lock()) + + if (try_lock()) DBUG_VOID_RETURN; - Query_cache_block *query_block= (Query_cache_block*)net->query_cache_query; - if (!query_block) + Query_cache_block *query_block = query_cache_tls->first_query_block; + if (query_block == NULL) { /* We lost the writer and the currently processed query has been invalidated; there is nothing left to do. */ - query_cache.unlock(); + unlock(); DBUG_VOID_RETURN; } - BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); Query_cache_block *result= header->result(); - DUMP(&query_cache); + DUMP(this); DBUG_PRINT("qcache", ("insert packet %lu bytes long",length)); /* @@ -867,8 +883,8 @@ void query_cache_insert(NET *net, const char *packet, ulong length) still need structure_guard_mutex to free the query, and therefore unlock it later in this function. */ - if (!query_cache.append_result_data(&result, length, (uchar*) packet, - query_block)) + if (!append_result_data(&result, length, (uchar*) packet, + query_block)) { DBUG_PRINT("warning", ("Can't append data")); header->result(result); @@ -877,60 +893,63 @@ 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 - query_cache.unlock(); + unlock(); DBUG_VOID_RETURN; } header->result(result); - header->last_pkt_nr= net->pkt_nr; + header->last_pkt_nr= pkt_nr; BLOCK_UNLOCK_WR(query_block); - DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0);); + DBUG_EXECUTE("check_querycache",check_integrity(0);); DBUG_VOID_RETURN; } -void query_cache_abort(NET *net) +void +Query_cache::abort(Query_cache_tls *query_cache_tls) { DBUG_ENTER("query_cache_abort"); THD *thd= current_thd; /* See the comment on double-check locking usage above. */ - if (net->query_cache_query == 0) + if (query_cache_tls->first_query_block == NULL) DBUG_VOID_RETURN; - if (query_cache.try_lock()) + if (try_lock()) DBUG_VOID_RETURN; /* While we were waiting another thread might have changed the status of the writer. Make sure the writer still exists before continue. */ - Query_cache_block *query_block= ((Query_cache_block*) - net->query_cache_query); + Query_cache_block *query_block= query_cache_tls->first_query_block; if (query_block) { thd_proc_info(thd, "storing result in query cache"); - DUMP(&query_cache); + DUMP(this); BLOCK_LOCK_WR(query_block); // The following call will remove the lock on query_block - query_cache.free_query(query_block); - net->query_cache_query= 0; - DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); + free_query(query_block); + query_cache_tls->first_query_block= NULL; + DBUG_EXECUTE("check_querycache", check_integrity(1);); } - query_cache.unlock(); + unlock(); + DBUG_VOID_RETURN; } -void query_cache_end_of_result(THD *thd) +void Query_cache::end_of_result(THD *thd) { Query_cache_block *query_block; - DBUG_ENTER("query_cache_end_of_result"); + Query_cache_tls *query_cache_tls= &thd->query_cache_tls; + ulonglong limit_found_rows= thd->limit_found_rows; + DBUG_ENTER("Query_cache::end_of_result"); /* See the comment on double-check locking usage above. */ - if (thd->net.query_cache_query == 0) + if (query_cache_tls->first_query_block == NULL) DBUG_VOID_RETURN; /* Ensure that only complete results are cached. */ @@ -938,19 +957,19 @@ void query_cache_end_of_result(THD *thd) if (thd->killed) { - query_cache_abort(&thd->net); + query_cache_abort(&thd->query_cache_tls); DBUG_VOID_RETURN; } #ifdef EMBEDDED_LIBRARY - query_cache_insert(&thd->net, (char*)thd, - emb_count_querycache_size(thd)); + insert(query_cache_tls, (char*)thd, + emb_count_querycache_size(thd), 0); #endif - if (query_cache.try_lock()) + if (try_lock()) DBUG_VOID_RETURN; - query_block= ((Query_cache_block*) thd->net.query_cache_query); + query_block= query_cache_tls->first_query_block; if (query_block) { /* @@ -959,7 +978,7 @@ void query_cache_end_of_result(THD *thd) block, the writer should be dropped. */ thd_proc_info(thd, "storing result in query cache"); - DUMP(&query_cache); + DUMP(this); BLOCK_LOCK_WR(query_block); Query_cache_query *header= query_block->query(); Query_cache_block *last_result_block; @@ -976,8 +995,8 @@ void query_cache_end_of_result(THD *thd) and removed from QC. */ DBUG_ASSERT(0); - query_cache.free_query(query_block); - query_cache.unlock(); + free_query(query_block); + unlock(); DBUG_VOID_RETURN; } last_result_block= header->result()->prev; @@ -986,17 +1005,17 @@ void query_cache_end_of_result(THD *thd) if (last_result_block->length >= query_cache.min_allocation_unit + len) query_cache.split_block(last_result_block,len); - header->found_rows(current_thd->limit_found_rows); + header->found_rows(limit_found_rows); header->result()->type= Query_cache_block::RESULT; /* Drop the writer. */ header->writer(0); - thd->net.query_cache_query= 0; + query_cache_tls->first_query_block= NULL; BLOCK_UNLOCK_WR(query_block); - DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); - + DBUG_EXECUTE("check_querycache", check_integrity(1);); } - query_cache.unlock(); + + unlock(); DBUG_VOID_RETURN; } @@ -1074,7 +1093,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg) Drop the writer; this will cancel any attempts to store the processed statement associated with this writer. */ - query->writer()->query_cache_query= 0; + query->writer()->first_query_block= NULL; query->writer(0); refused++; } @@ -1230,7 +1249,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", /* Check if another thread is processing the same query? */ Query_cache_block *competitor = (Query_cache_block *) - hash_search(&queries, (uchar*) thd->query, tot_length); + my_hash_search(&queries, (uchar*) thd->query, tot_length); DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor)); if (competitor == 0) { @@ -1259,7 +1278,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", { refused++; DBUG_PRINT("warning", ("tables list including failed")); - hash_delete(&queries, (uchar *) query_block); + my_hash_delete(&queries, (uchar *) query_block); header->unlock_n_destroy(); free_memory_block(query_block); unlock(); @@ -1268,8 +1287,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", double_linked_list_simple_include(query_block, &queries_blocks); inserts++; queries_in_cache++; - net->query_cache_query= (uchar*) query_block; - header->writer(net); + thd->query_cache_tls.first_query_block= query_block; + header->writer(&thd->query_cache_tls); header->tables_type(tables_type); unlock(); @@ -1325,7 +1344,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) { ulonglong engine_data; Query_cache_query *query; - Query_cache_block *first_result_block, *result_block; +#ifndef EMBEDDED_LIBRARY + Query_cache_block *first_result_block; +#endif + Query_cache_block *result_block; Query_cache_block_table *block_table, *block_table_end; ulong tot_length; Query_cache_query_flags flags; @@ -1396,12 +1418,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) if (query_cache_size == 0) 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. - */ - DBUG_ASSERT(thd->net.query_cache_query == 0); - Query_cache_block *query_block; tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE; @@ -1467,8 +1483,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", (int)flags.autocommit)); memcpy((uchar *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)), (uchar*) &flags, QUERY_CACHE_FLAGS_SIZE); - query_block = (Query_cache_block *) hash_search(&queries, (uchar*) sql, - tot_length); + query_block = (Query_cache_block *) my_hash_search(&queries, (uchar*) sql, + tot_length); /* Quick abort on unlocked data */ if (query_block == 0 || query_block->query()->result() == 0 || @@ -1483,7 +1499,10 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", BLOCK_LOCK_RD(query_block); query = query_block->query(); - result_block= first_result_block= query->result(); + result_block= query->result(); +#ifndef EMBEDDED_LIBRARY + first_result_block= result_block; +#endif if (result_block == 0 || result_block->type != Query_cache_block::RESULT) { @@ -2073,8 +2092,8 @@ ulong Query_cache::init_cache() DUMP(this); - VOID(hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0, - query_cache_query_get_key, 0, 0)); + VOID(my_hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0, + query_cache_query_get_key, 0, 0)); #ifndef FN_NO_CASE_SENCE /* If lower_case_table_names!=0 then db and table names are already @@ -2084,8 +2103,8 @@ ulong Query_cache::init_cache() lower_case_table_names == 0 then we should distinguish my_table and MY_TABLE cases and so again can use binary collation. */ - VOID(hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0, - query_cache_table_get_key, 0, 0)); + VOID(my_hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0, + query_cache_table_get_key, 0, 0)); #else /* On windows, OS/2, MacOS X with HFS+ or any other case insensitive @@ -2095,10 +2114,10 @@ ulong Query_cache::init_cache() file system) and so should use case insensitive collation for comparison. */ - VOID(hash_init(&tables, - lower_case_table_names ? &my_charset_bin : - files_charset_info, - def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0)); + VOID(my_hash_init(&tables, + lower_case_table_names ? &my_charset_bin : + files_charset_info, + def_table_hash_size, 0, 0,query_cache_table_get_key, 0, 0)); #endif queries_in_cache = 0; @@ -2148,8 +2167,8 @@ void Query_cache::free_cache() my_free((uchar*) cache, MYF(MY_ALLOW_ZERO_PTR)); make_disabled(); - hash_free(&queries); - hash_free(&tables); + my_hash_free(&queries); + my_hash_free(&tables); DBUG_VOID_RETURN; } @@ -2261,7 +2280,7 @@ void Query_cache::free_query_internal(Query_cache_block *query_block) if (query->writer() != 0) { /* Tell MySQL that this query should not be cached anymore */ - query->writer()->query_cache_query= 0; + query->writer()->first_query_block= NULL; query->writer(0); } double_linked_list_exclude(query_block, &queries_blocks); @@ -2324,7 +2343,7 @@ void Query_cache::free_query(Query_cache_block *query_block) (ulong) query_block, query_block->query()->length() )); - hash_delete(&queries,(uchar *) query_block); + my_hash_delete(&queries,(uchar *) query_block); free_query_internal(query_block); DBUG_VOID_RETURN; @@ -2653,7 +2672,7 @@ void Query_cache::invalidate_table_internal(THD *thd, uchar *key, uint32 key_length) { Query_cache_block *table_block= - (Query_cache_block*)hash_search(&tables, key, key_length); + (Query_cache_block*)my_hash_search(&tables, key, key_length); if (table_block) { Query_cache_block_table *list_root= table_block->table(0); @@ -2851,7 +2870,7 @@ Query_cache::insert_table(uint key_len, char *key, THD *thd= current_thd; Query_cache_block *table_block= - (Query_cache_block *)hash_search(&tables, (uchar*) key, key_len); + (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len); if (table_block && table_block->table()->engine_data() != engine_data) @@ -2967,7 +2986,7 @@ void Query_cache::unlink_table(Query_cache_block_table *node) Query_cache_block *table_block= neighbour->block(); double_linked_list_exclude(table_block, &tables_blocks); - hash_delete(&tables,(uchar *) table_block); + my_hash_delete(&tables,(uchar *) table_block); free_memory_block(table_block); } DBUG_VOID_RETURN; @@ -3474,7 +3493,8 @@ Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used, */ TABLE_COUNTER_TYPE -Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex, +Query_cache::is_cacheable(THD *thd, size_t query_len, const char *query, + LEX *lex, TABLE_LIST *tables_used, uint8 *tables_type) { TABLE_COUNTER_TYPE table_count; @@ -3651,7 +3671,7 @@ my_bool Query_cache::move_by_type(uchar **border, uchar *key; size_t key_length; key=query_cache_table_get_key((uchar*) block, &key_length, 0); - hash_first(&tables, (uchar*) key, key_length, &record_idx); + my_hash_first(&tables, (uchar*) key, key_length, &record_idx); block->destroy(); new_block->init(len); @@ -3685,7 +3705,7 @@ my_bool Query_cache::move_by_type(uchar **border, /* Fix pointer to table name */ new_block->table()->table(new_block->table()->db() + tablename_offset); /* Fix hash to point at moved block */ - hash_replace(&tables, &record_idx, (uchar*) new_block); + my_hash_replace(&tables, &record_idx, (uchar*) new_block); DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx", len, (ulong) new_block, (ulong) *border)); @@ -3711,7 +3731,7 @@ my_bool Query_cache::move_by_type(uchar **border, uchar *key; size_t key_length; key=query_cache_query_get_key((uchar*) block, &key_length, 0); - hash_first(&queries, (uchar*) key, key_length, &record_idx); + my_hash_first(&queries, (uchar*) key, key_length, &record_idx); // Move table of used tables memmove((char*) new_block->table(0), (char*) block->table(0), ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table))); @@ -3773,13 +3793,13 @@ my_bool Query_cache::move_by_type(uchar **border, If someone is writing to this block, inform the writer that the block has been moved. */ - NET *net = new_block->query()->writer(); - if (net != 0) + Query_cache_tls *query_cache_tls= new_block->query()->writer(); + if (query_cache_tls != NULL) { - net->query_cache_query= (uchar*) new_block; + query_cache_tls->first_query_block= new_block; } /* Fix hash to point at moved block */ - hash_replace(&queries, &record_idx, (uchar*) new_block); + my_hash_replace(&queries, &record_idx, (uchar*) new_block); DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx", len, (ulong) new_block, (ulong) *border)); break; @@ -4190,13 +4210,13 @@ my_bool Query_cache::check_integrity(bool locked) if (!locked) lock_and_suspend(); - if (hash_check(&queries)) + if (my_hash_check(&queries)) { DBUG_PRINT("error", ("queries hash is damaged")); result = 1; } - if (hash_check(&tables)) + if (my_hash_check(&tables)) { DBUG_PRINT("error", ("tables hash is damaged")); result = 1; @@ -4363,7 +4383,7 @@ my_bool Query_cache::check_integrity(bool locked) (ulong) block, (uint) block->type)); size_t length; uchar *key = query_cache_query_get_key((uchar*) block, &length, 0); - uchar* val = hash_search(&queries, key, length); + uchar* val = my_hash_search(&queries, key, length); if (((uchar*)block) != val) { DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx", @@ -4398,7 +4418,7 @@ my_bool Query_cache::check_integrity(bool locked) (ulong) block, (uint) block->type)); size_t length; uchar *key = query_cache_table_get_key((uchar*) block, &length, 0); - uchar* val = hash_search(&tables, key, length); + uchar* val = my_hash_search(&tables, key, length); if (((uchar*)block) != val) { DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx", |