diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 18 | ||||
-rw-r--r-- | sql/sql_cache.cc | 168 | ||||
-rw-r--r-- | sql/sql_cache.h | 9 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 9 | ||||
-rw-r--r-- | sql/sql_table.cc | 27 |
7 files changed, 168 insertions, 68 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4e3757d3f23..72953cad8e8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -277,7 +277,7 @@ bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); bool check_stack_overrun(THD *thd,char *dummy); -bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables); +bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables); void table_cache_init(void); void table_cache_free(void); uint cached_tables(void); @@ -697,7 +697,6 @@ void hostname_cache_refresh(void); bool get_interval_info(const char *str,uint length,uint count, long *values); /* sql_cache */ - extern bool sql_cache_init(); extern void sql_cache_free(); extern int sql_cache_hit(THD *thd, char *inBuf, uint length); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b913233806f..7f6ffd04d98 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2195,16 +2195,18 @@ int setup_ftfuncs(THD *thd) int init_ftfuncs(THD *thd, bool no_order) { - List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list); - Item_func_match *ifm; - DBUG_PRINT("info",("Performing FULLTEXT search")); - thd->proc_info="FULLTEXT initialization"; - - while ((ifm=li++)) + if (thd->lex.select_lex.ftfunc_list.elements) { - ifm->init_search(no_order); - } + List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list); + Item_func_match *ifm; + DBUG_PRINT("info",("Performing FULLTEXT search")); + thd->proc_info="FULLTEXT initialization"; + while ((ifm=li++)) + { + ifm->init_search(no_order); + } + } return 0; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index bc9b95fe773..9b83a14c6d6 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -200,6 +200,74 @@ stored in Query_cache_memory_bin_step structure. Free memory blocks are sorted in bins in lists with size-ascending order (more small blocks needed frequently then bigger one). + +6. Packing cache. + +Query cache packing is divided into two operation: + - pack_cache + - join_results + +pack_cache moved all blocks to "top" of cache and create one block of free +space at the "bottom": + + before pack_cache after pack_cache + +-------------+ +-------------+ + | query 1 | | query 1 | + +-------------+ +-------------+ + | table 1 | | table 1 | + +-------------+ +-------------+ + | results 1.1 | | results 1.1 | + +-------------+ +-------------+ + | free | | query 2 | + +-------------+ +-------------+ + | query 2 | | table 2 | + +-------------+ ---> +-------------+ + | table 2 | | results 1.2 | + +-------------+ +-------------+ + | results 1.2 | | results 2 | + +-------------+ +-------------+ + | free | | free | + +-------------+ | | + | results 2 | | | + +-------------+ | | + | free | | | + +-------------+ +-------------+ + +pack_cache scan blocks in physical address order and move every non-free +block "higher". + +pack_cach remove every free block it finds. The length of the deleted block +is accumulated to the "gap". All non free blocks should be shifted with the +"gap" step. + +join_results scans all complete queries. If the results of query are not +stored in the same block, join_results tries to move results so, that they +are stored in one block. + + before join_results after join_results + +-------------+ +-------------+ + | query 1 | | query 1 | + +-------------+ +-------------+ + | table 1 | | table 1 | + +-------------+ +-------------+ + | results 1.1 | | free | + +-------------+ +-------------+ + | query 2 | | query 2 | + +-------------+ +-------------+ + | table 2 | | table 2 | + +-------------+ ---> +-------------+ + | results 1.2 | | free | + +-------------+ +-------------+ + | results 2 | | results 2 | + +-------------+ +-------------+ + | free | | results 1 | + | | | | + | | +-------------+ + | | | free | + | | | | + +-------------+ +-------------+ + +If join_results allocated new block(s) then we need call pack_cache again. */ #include "mysql_priv.h" @@ -377,6 +445,10 @@ void Query_cache_query::init_n_lock() void Query_cache_query::unlock_n_destroy() { DBUG_ENTER("Query_cache_query::unlock_n_destroy"); + /* + The following call is not needed on system where one can destroy an + active semaphore + */ this->unlock_writing(); DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx", ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block)))); @@ -465,7 +537,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length) DBUG_ENTER("query_cache_insert"); #ifndef DBUG_OFF - // Debugging method wreck may cause this + // Check if we have called query_cache.wreck() (which disables the cache) if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN; #endif @@ -493,6 +565,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length) if (!query_cache.append_result_data(&result, length, (gptr) packet, query_block)) { + query_cache.refused++; DBUG_PRINT("warning", ("Can't append data")); header->result(result); DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block)); @@ -517,7 +590,7 @@ void query_cache_abort(NET *net) DBUG_ENTER("query_cache_abort"); #ifndef DBUG_OFF - // Debugging method wreck may cause this + // Check if we have called query_cache.wreck() (which disables the cache) if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN; #endif @@ -545,7 +618,7 @@ void query_cache_end_of_result(NET *net) DBUG_ENTER("query_cache_end_of_result"); #ifndef DBUG_OFF - // Debugging method wreck may cause this + // Check if we have called query_cache.wreck() (which disables the cache) if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN; #endif @@ -603,11 +676,11 @@ Query_cache::Query_cache(ulong query_cache_limit, uint def_table_hash_size) :query_cache_size(0), query_cache_limit(query_cache_limit), + queries_in_cache(0), hits(0), inserts(0), refused(0), min_allocation_unit(min_allocation_unit), min_result_data_size(min_result_data_size), def_query_hash_size(def_query_hash_size), def_table_hash_size(def_table_hash_size), - queries_in_cache(0), hits(0), inserts(0), refused(0), initialized(0) { ulong min_needed=(ALIGN_SIZE(sizeof(Query_cache_block)) + @@ -622,11 +695,11 @@ Query_cache::Query_cache(ulong query_cache_limit, ulong Query_cache::resize(ulong query_cache_size) { /* - TODO: when will be realized pack() optimize case when + TODO: + When will be realized pack() optimize case when query_cache_size < this->query_cache_size - */ - /* - TODO: try to copy old cache in new memory + + Try to copy old cache in new memory */ DBUG_ENTER("Query_cache::resize"); DBUG_PRINT("qcache", ("from %lu to %lu",this->query_cache_size, @@ -739,7 +812,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) } } else - refused++; + statistic_increment(refused, &structure_guard_mutex); end: thd->query[thd->query_length]= 0; // Restore end null @@ -834,7 +907,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) /* Now lock and test that nothing changed while blocks was unlocked */ BLOCK_LOCK_RD(query_block); - STRUCT_UNLOCK(&structure_guard_mutex); query = query_block->query(); result_block= first_result_block= query->result(); @@ -843,6 +915,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) { /* The query is probably yet processed */ DBUG_PRINT("qcache", ("query found, but no data or data incomplete")); + BLOCK_UNLOCK_RD(query_block); goto err; } DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query)); @@ -863,12 +936,15 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("probably no SELECT access to %s.%s => return to normal processing", table_list.db, table_list.name)); + BLOCK_UNLOCK_RD(query_block); + STRUCT_UNLOCK(&structure_guard_mutex); goto err; } } move_to_query_list_end(query_block); - hits++; + STRUCT_UNLOCK(&structure_guard_mutex); + /* Send cached result to client */ @@ -957,12 +1033,11 @@ void Query_cache::invalidate(Query_cache_table::query_cache_table_type type) { /* Store next block address defore deleting the current block */ Query_cache_block *next = table_block->next; - invalidate_table(table_block); - +#ifdef TO_BE_DELETED if (next == table_block) // End of list break; - +#endif table_block = next; } while (table_block != tables_blocks[type]); } @@ -999,10 +1074,10 @@ void Query_cache::invalidate(char *db) Query_cache_block *next = table_block->next; invalidate_table_in_db(table_block, db); - +#ifdef TO_BE_DELETED if (table_block == next) break; - +#endif table_block = next; } while (table_block != tables_blocks[i]); } @@ -1035,21 +1110,24 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename) DBUG_VOID_RETURN; } + /* Remove all queries from cache */ void Query_cache::flush() { DBUG_ENTER("Query_cache::flush"); + STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size > 0) { DUMP(this); - STRUCT_LOCK(&structure_guard_mutex); flush_cache(); DUMP(this); - STRUCT_UNLOCK(&structure_guard_mutex); } + STRUCT_UNLOCK(&structure_guard_mutex); DBUG_VOID_RETURN; } + /* Join result in cache in 1 block (if result length > join_limit) */ + void Query_cache::pack(ulong join_limit, uint iteration_limit) { DBUG_ENTER("Query_cache::pack"); @@ -1307,7 +1385,7 @@ void Query_cache::flush_cache() my_bool Query_cache::free_old_query() { DBUG_ENTER("Query_cache::free_old_query"); - if (!queries_blocks) + if (queries_blocks) { /* try_lock_writing used to prevent client because here lock @@ -1371,6 +1449,11 @@ void Query_cache::free_query(Query_cache_block *query_block) for (TABLE_COUNTER_TYPE i=0; i < query_block->n_tables; i++) unlink_table(table++); Query_cache_block *result_block = query->result(); + + /* + The following is true when query destruction was called and no results + in query . (query just registered and then abort/pack/flush called) + */ if (result_block != 0) { Query_cache_block *block = result_block; @@ -1522,7 +1605,15 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block, DBUG_ENTER("Query_cache::write_result_data"); DBUG_PRINT("qcache", ("data_len %lu",data_len)); - // Reserve block(s) for filling + /* + Reserve block(s) for filling + During data allocation we must have structure_guard_mutex locked. + As data copy is not a fast operation, it's better if we don't have + structure_guard_mutex locked during data coping. + Thus we first allocate space and lock query, then unlock + structure_guard_mutex and copy data. + */ + my_bool success = allocate_data_chain(result_block, data_len, query_block); if (success) { @@ -1975,7 +2066,6 @@ Query_cache::join_free_blocks(Query_cache_block *first_block, exclude_from_free_memory_list(block_in_list); second_block = first_block->pnext; // May be was not free block - second_block->type = Query_cache_block::FREE; second_block->used=0; second_block->destroy(); @@ -2254,27 +2344,30 @@ void Query_cache::pack_cache() Query_cache_block *before = 0; ulong gap = 0; my_bool ok = 1; - Query_cache_block *i = first_block; + Query_cache_block *block = first_block; DBUG_ENTER("Query_cache::pack_cache"); DUMP(this); - do + if (first_block) { - ok = move_by_type(&border, &before, &gap, i); - i = i->pnext; - } while (ok && i != first_block); + do + { + ok = move_by_type(&border, &before, &gap, block); + block = block->pnext; + } while (ok && block != first_block); - if (border != 0) - { - Query_cache_block *new_block = (Query_cache_block *) border; - new_block->init(gap); - new_block->pnext = before->pnext; - before->pnext = new_block; - new_block->pprev = before; - new_block->pnext->pprev = new_block; - insert_into_free_memory_list(new_block); + if (border != 0) + { + Query_cache_block *new_block = (Query_cache_block *) border; + new_block->init(gap); + new_block->pnext = before->pnext; + before->pnext = new_block; + new_block->pprev = before; + new_block->pnext->pprev = new_block; + insert_into_free_memory_list(new_block); + } + DUMP(this); } - DUMP(this); STRUCT_UNLOCK(&structure_guard_mutex); DBUG_VOID_RETURN; } @@ -2487,7 +2580,6 @@ void Query_cache::relink(Query_cache_block *oblock, my_bool Query_cache::join_results(ulong join_limit) { - //TODO my_bool has_moving = 0; DBUG_ENTER("Query_cache::join_results"); @@ -2577,7 +2669,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path) db_length= (filename - dbname) - 1; DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename)); - DBUG_RETURN((uint) (strmov(strnmov(key, dbname, db_length) + 1, + DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1, filename) -key) + 1); } diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 09eb745e405..f5f0580d051 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -241,12 +241,12 @@ protected: Query_cache_memory_bin *bins; // free block lists Query_cache_memory_bin_step *steps; // bins spacing info HASH queries, tables; - uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin - my_bool initialized; - /* options */ ulong min_allocation_unit, min_result_data_size; uint def_query_hash_size, def_table_hash_size; + uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin + + my_bool initialized; /* Exclude/include from cyclic double linked list */ static void double_linked_list_exclude(Query_cache_block *point, @@ -368,10 +368,7 @@ protected: /* Remove all queries that uses any of the listed following table */ void invalidate_by_MyISAM_filename(const char *filename); - /* Remove all queries from cache */ void flush(); - - /* Join result in cache in 1 block (if result length > join_limit) */ void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT, uint iteration_limit = QUERY_CACHE_PACK_ITERATION); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0b596c01f9d..d293a62903d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -122,7 +122,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), server_status=SERVER_STATUS_AUTOCOMMIT; update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE; options=thd_startup_options; - query_cache_type = (byte)query_cache_startup_type; + query_cache_type = (byte) query_cache_startup_type; sql_mode=(uint) opt_sql_mode; inactive_timeout=net_wait_timeout; open_options=ha_open_options; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 769527c92fe..8eef80bc985 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -951,7 +951,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_REFRESH: { - uint options=(uchar) packet[0]; + ulong options= (ulong) (uchar) packet[0]; if (check_access(thd,RELOAD_ACL,any_db)) break; mysql_log.write(thd,command,NullS); @@ -1432,7 +1432,6 @@ mysql_execute_command(void) (ORDER *) select_lex->order_list.first, lex->drop_primary, lex->duplicates, lex->alter_keys_onoff, lex->simple_alter); - query_cache.invalidate(tables); } break; } @@ -2984,7 +2983,7 @@ static bool check_dup(const char *db, const char *name, TABLE_LIST *tables) return 0; } -bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables) +bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) { bool result=0; @@ -3006,12 +3005,12 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables) } if (options & REFRESH_QUERY_CACHE_FREE) { - query_cache.pack(); + query_cache.pack(); // FLUSH QUERY CACHE options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory } if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE)) { - query_cache.flush(); + query_cache.flush(); // RESET QUERY CACHE } if (options & (REFRESH_TABLES | REFRESH_READ_LOCK)) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 737c8fccd9d..2f9fa17faf1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -951,6 +951,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name); net_store_data(packet, buff); close_thread_tables(thd); + table->table=0; // For query cache if (my_net_write(&thd->net, (char*) thd->packet.ptr(), packet->length())) goto err; @@ -1028,6 +1029,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, remove_table_from_cache(thd, table->table->table_cache_key, table->table->real_name); close_thread_tables(thd); + table->table=0; // For query cache if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length())) goto err; @@ -1037,9 +1039,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, DBUG_RETURN(0); err: close_thread_tables(thd); // Shouldn't be needed + if (table) + table->table=0; DBUG_RETURN(-1); } + int mysql_backup_table(THD* thd, TABLE_LIST* table_list) { DBUG_ENTER("mysql_backup_table"); @@ -1658,24 +1663,30 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } if (error) { - // This shouldn't happen. We solve this the safe way by - // closing the locked table. + /* + This shouldn't happen. We solve this the safe way by + closing the locked table. + */ close_cached_table(thd,table); VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } if (thd->lock || new_name != table_name) // True if WIN32 { - // Not table locking or alter table with rename - // free locks and remove old table + /* + Not table locking or alter table with rename + free locks and remove old table + */ close_cached_table(thd,table); VOID(quick_rm_table(old_db_type,db,old_name)); } else { - // Using LOCK TABLES without rename. - // This code is never executed on WIN32! - // Remove old renamed table, reopen table and get new locks + /* + Using LOCK TABLES without rename. + This code is never executed on WIN32! + Remove old renamed table, reopen table and get new locks + */ if (table) { VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file @@ -1712,7 +1723,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_mutex_unlock(&LOCK_open)); - table_list->table=0; // Table is closed + table_list->table=0; // For query cache query_cache.invalidate(table_list); end_temporary: |