My Project
|
00001 /* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; version 2 of the License. 00006 00007 This program is distributed in the hope that it will be useful, 00008 but WITHOUT ANY WARRANTY; without even the implied warranty of 00009 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00010 GNU General Public License for more details. 00011 00012 You should have received a copy of the GNU General Public License 00013 along with this program; if not, write to the Free Software Foundation, 00014 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 00015 00016 #ifndef _SQL_CACHE_H 00017 #define _SQL_CACHE_H 00018 00019 #include "hash.h" 00020 #include "my_base.h" /* ha_rows */ 00021 00022 class MY_LOCALE; 00023 struct TABLE_LIST; 00024 class Time_zone; 00025 struct LEX; 00026 struct TABLE; 00027 typedef struct st_changed_table_list CHANGED_TABLE_LIST; 00028 typedef ulonglong sql_mode_t; 00029 00030 /* Query cache */ 00031 00032 /* 00033 Can't create new free memory block if unused memory in block less 00034 then QUERY_CACHE_MIN_ALLOCATION_UNIT. 00035 if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then 00036 QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly 00037 */ 00038 #define QUERY_CACHE_MIN_ALLOCATION_UNIT 512 00039 00040 /* inittial size of hashes */ 00041 #define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024 00042 #define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024 00043 00044 /* minimal result data size when data allocated */ 00045 #define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024*4 00046 00047 /* 00048 start estimation of first result block size only when number of queries 00049 bigger then: 00050 */ 00051 #define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3 00052 00053 00054 00055 /* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */ 00056 #define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4 00057 #define QUERY_CACHE_MEM_BIN_STEP_PWR2 2 00058 #define QUERY_CACHE_MEM_BIN_PARTS_INC 1 00059 #define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2 00060 #define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3 00061 00062 /* how many free blocks check when finding most suitable before other 'end' 00063 of list of free blocks */ 00064 #define QUERY_CACHE_MEM_BIN_TRY 5 00065 00066 /* packing parameters */ 00067 #define QUERY_CACHE_PACK_ITERATION 2 00068 #define QUERY_CACHE_PACK_LIMIT (512*1024L) 00069 00070 #define TABLE_COUNTER_TYPE uint 00071 00072 struct Query_cache_block; 00073 struct Query_cache_block_table; 00074 struct Query_cache_table; 00075 struct Query_cache_query; 00076 struct Query_cache_result; 00077 class Query_cache; 00078 struct Query_cache_tls; 00079 struct LEX; 00080 class THD; 00081 00082 typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, 00083 uint key_length, 00084 ulonglong *engine_data); 00085 00093 struct Query_cache_block_table 00094 { 00095 Query_cache_block_table() {} /* Remove gcc warning */ 00096 00101 TABLE_COUNTER_TYPE n; 00102 00107 Query_cache_block_table *next, *prev; 00108 00113 Query_cache_table *parent; 00114 00121 inline Query_cache_block *block(); 00122 }; 00123 00124 struct Query_cache_block 00125 { 00126 Query_cache_block() {} /* Remove gcc warning */ 00127 enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG, 00128 RES_INCOMPLETE, TABLE, INCOMPLETE}; 00129 00130 ulong length; // length of all block 00131 ulong used; // length of data 00132 /* 00133 Not used **pprev, **prev because really needed access to pervious block: 00134 *pprev to join free blocks 00135 *prev to access to opposite side of list in cyclic sorted list 00136 */ 00137 Query_cache_block *pnext,*pprev, // physical next/previous block 00138 *next,*prev; // logical next/previous block 00139 block_type type; 00140 TABLE_COUNTER_TYPE n_tables; // number of tables in query 00141 00142 inline my_bool is_free(void) { return type == FREE; } 00143 void init(ulong length); 00144 void destroy(); 00145 inline uint headers_len(); 00146 inline uchar* data(void); 00147 inline Query_cache_query *query(); 00148 inline Query_cache_table *table(); 00149 inline Query_cache_result *result(); 00150 inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n); 00151 }; 00152 00153 struct Query_cache_query 00154 { 00155 ulonglong limit_found_rows; 00156 mysql_rwlock_t lock; 00157 Query_cache_block *res; 00158 Query_cache_tls *wri; 00159 ulong len; 00160 uint8 tbls_type; 00161 unsigned int last_pkt_nr; 00162 00163 Query_cache_query() {} /* Remove gcc warning */ 00164 inline void init_n_lock(); 00165 void unlock_n_destroy(); 00166 inline ulonglong found_rows() { return limit_found_rows; } 00167 inline void found_rows(ulonglong rows) { limit_found_rows= rows; } 00168 inline Query_cache_block *result() { return res; } 00169 inline void result(Query_cache_block *p) { res= p; } 00170 inline Query_cache_tls *writer() { return wri; } 00171 inline void writer(Query_cache_tls *p) { wri= p; } 00172 inline uint8 tables_type() { return tbls_type; } 00173 inline void tables_type(uint8 type) { tbls_type= type; } 00174 inline ulong length() { return len; } 00175 inline ulong add(ulong packet_len) { return(len+= packet_len); } 00176 inline void length(ulong length_arg) { len= length_arg; } 00177 inline uchar* query() 00178 { 00179 return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query))); 00180 } 00181 void lock_writing(); 00182 void lock_reading(); 00183 my_bool try_lock_writing(); 00184 void unlock_writing(); 00185 void unlock_reading(); 00186 }; 00187 00188 00189 struct Query_cache_table 00190 { 00191 Query_cache_table() {} /* Remove gcc warning */ 00192 char *tbl; 00193 uint32 key_len; 00194 uint8 table_type; 00195 /* unique for every engine reference */ 00196 qc_engine_callback callback_func; 00197 /* data need by some engines */ 00198 ulonglong engine_data_buff; 00199 00203 int32 m_cached_query_count; 00204 00205 inline char *db() { return (char *) data(); } 00206 inline char *table() { return tbl; } 00207 inline void table(char *table_arg) { tbl= table_arg; } 00208 inline uint32 key_length() { return key_len; } 00209 inline void key_length(uint32 len) { key_len= len; } 00210 inline uint8 type() { return table_type; } 00211 inline void type(uint8 t) { table_type= t; } 00212 inline qc_engine_callback callback() { return callback_func; } 00213 inline void callback(qc_engine_callback fn){ callback_func= fn; } 00214 inline ulonglong engine_data() { return engine_data_buff; } 00215 inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } 00216 inline uchar* data() 00217 { 00218 return (uchar*)(((uchar*)this)+ 00219 ALIGN_SIZE(sizeof(Query_cache_table))); 00220 } 00221 }; 00222 00223 struct Query_cache_result 00224 { 00225 Query_cache_result() {} /* Remove gcc warning */ 00226 Query_cache_block *query; 00227 00228 inline uchar* data() 00229 { 00230 return (uchar*)(((uchar*) this)+ 00231 ALIGN_SIZE(sizeof(Query_cache_result))); 00232 } 00233 /* data_continue (if not whole packet contained by this block) */ 00234 inline Query_cache_block *parent() { return query; } 00235 inline void parent (Query_cache_block *p) { query=p; } 00236 }; 00237 00238 00239 extern "C" 00240 { 00241 uchar *query_cache_query_get_key(const uchar *record, size_t *length, 00242 my_bool not_used); 00243 uchar *query_cache_table_get_key(const uchar *record, size_t *length, 00244 my_bool not_used); 00245 } 00246 extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename); 00247 00248 00249 struct Query_cache_memory_bin 00250 { 00251 Query_cache_memory_bin() {} /* Remove gcc warning */ 00252 #ifndef DBUG_OFF 00253 ulong size; 00254 #endif 00255 uint number; 00256 Query_cache_block *free_blocks; 00257 00258 inline void init(ulong size_arg) 00259 { 00260 #ifndef DBUG_OFF 00261 size = size_arg; 00262 #endif 00263 number = 0; 00264 free_blocks = 0; 00265 } 00266 }; 00267 00268 struct Query_cache_memory_bin_step 00269 { 00270 Query_cache_memory_bin_step() {} /* Remove gcc warning */ 00271 ulong size; 00272 ulong increment; 00273 uint idx; 00274 inline void init(ulong size_arg, uint idx_arg, ulong increment_arg) 00275 { 00276 size = size_arg; 00277 idx = idx_arg; 00278 increment = increment_arg; 00279 } 00280 }; 00281 00282 class Query_cache 00283 { 00284 public: 00285 /* Info */ 00286 ulong query_cache_size, query_cache_limit; 00287 /* statistics */ 00288 ulong free_memory, queries_in_cache, hits, inserts, refused, 00289 free_memory_blocks, total_blocks, lowmem_prunes; 00290 00291 00292 private: 00293 #ifndef DBUG_OFF 00294 my_thread_id m_cache_lock_thread_id; 00295 #endif 00296 mysql_cond_t COND_cache_status_changed; 00297 enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED }; 00298 Cache_lock_status m_cache_lock_status; 00299 00300 bool m_query_cache_is_disabled; 00301 00302 void free_query_internal(Query_cache_block *point); 00303 void invalidate_table_internal(THD *thd, uchar *key, uint32 key_length); 00304 void disable_query_cache(void) { m_query_cache_is_disabled= TRUE; } 00305 00306 protected: 00307 /* 00308 The following mutex is locked when searching or changing global 00309 query, tables lists or hashes. When we are operating inside the 00310 query structure we locked an internal query block mutex. 00311 LOCK SEQUENCE (to prevent deadlocks): 00312 1. structure_guard_mutex 00313 2. query block (for operation inside query (query block/results)) 00314 00315 Thread doing cache flush releases the mutex once it sets 00316 m_cache_status flag, so other threads may bypass the cache as 00317 if it is disabled, not waiting for reset to finish. The exception 00318 is other threads that were going to do cache flush---they'll wait 00319 till the end of a flush operation. 00320 */ 00321 mysql_mutex_t structure_guard_mutex; 00322 uchar *cache; // cache memory 00323 Query_cache_block *first_block; // physical location block list 00324 Query_cache_block *queries_blocks; // query list (LIFO) 00325 Query_cache_block *tables_blocks; 00326 00327 Query_cache_memory_bin *bins; // free block lists 00328 Query_cache_memory_bin_step *steps; // bins spacing info 00329 HASH queries, tables; 00330 /* options */ 00331 ulong min_allocation_unit, min_result_data_size; 00332 uint def_query_hash_size, def_table_hash_size; 00333 00334 uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin 00335 00336 my_bool initialized; 00337 00338 /* Exclude/include from cyclic double linked list */ 00339 static void double_linked_list_exclude(Query_cache_block *point, 00340 Query_cache_block **list_pointer); 00341 static void double_linked_list_simple_include(Query_cache_block *point, 00342 Query_cache_block ** 00343 list_pointer); 00344 static void double_linked_list_join(Query_cache_block *head_tail, 00345 Query_cache_block *tail_head); 00346 00347 /* Table key generation */ 00348 static uint filename_2_table_key (char *key, const char *filename, 00349 uint32 *db_langth); 00350 00351 /* The following functions require that structure_guard_mutex is locked */ 00352 void flush_cache(); 00353 my_bool free_old_query(); 00354 void free_query(Query_cache_block *point); 00355 my_bool allocate_data_chain(Query_cache_block **result_block, 00356 ulong data_len, 00357 Query_cache_block *query_block, 00358 my_bool first_block); 00359 void invalidate_table(THD *thd, TABLE_LIST *table); 00360 void invalidate_table(THD *thd, TABLE *table); 00361 void invalidate_table(THD *thd, uchar *key, uint32 key_length); 00362 void invalidate_table(THD *thd, Query_cache_block *table_block); 00363 void invalidate_query_block_list(THD *thd, 00364 Query_cache_block_table *list_root); 00365 00366 TABLE_COUNTER_TYPE 00367 register_tables_from_list(TABLE_LIST *tables_used, 00368 TABLE_COUNTER_TYPE counter, 00369 Query_cache_block_table *block_table); 00370 my_bool register_all_tables(Query_cache_block *block, 00371 TABLE_LIST *tables_used, 00372 TABLE_COUNTER_TYPE tables); 00373 my_bool insert_table(uint key_len, const char *key, 00374 Query_cache_block_table *node, 00375 uint32 db_length, uint8 cache_type, 00376 qc_engine_callback callback, 00377 ulonglong engine_data); 00378 void unlink_table(Query_cache_block_table *node); 00379 Query_cache_block *get_free_block (ulong len, my_bool not_less, 00380 ulong min); 00381 void free_memory_block(Query_cache_block *point); 00382 void split_block(Query_cache_block *block, ulong len); 00383 Query_cache_block *join_free_blocks(Query_cache_block *first_block, 00384 Query_cache_block *block_in_list); 00385 my_bool append_next_free_block(Query_cache_block *block, 00386 ulong add_size); 00387 void exclude_from_free_memory_list(Query_cache_block *free_block); 00388 void insert_into_free_memory_list(Query_cache_block *new_block); 00389 my_bool move_by_type(uchar **border, Query_cache_block **before, 00390 ulong *gap, Query_cache_block *i); 00391 uint find_bin(ulong size); 00392 void move_to_query_list_end(Query_cache_block *block); 00393 void insert_into_free_memory_sorted_list(Query_cache_block *new_block, 00394 Query_cache_block **list); 00395 void pack_cache(); 00396 void relink(Query_cache_block *oblock, 00397 Query_cache_block *nblock, 00398 Query_cache_block *next, 00399 Query_cache_block *prev, 00400 Query_cache_block *pnext, 00401 Query_cache_block *pprev); 00402 my_bool join_results(ulong join_limit); 00403 00404 /* 00405 Following function control structure_guard_mutex 00406 by themself or don't need structure_guard_mutex 00407 */ 00408 ulong init_cache(); 00409 void make_disabled(); 00410 void free_cache(); 00411 Query_cache_block *write_block_data(ulong data_len, uchar* data, 00412 ulong header_len, 00413 Query_cache_block::block_type type, 00414 TABLE_COUNTER_TYPE ntab = 0); 00415 my_bool append_result_data(Query_cache_block **result, 00416 ulong data_len, uchar* data, 00417 Query_cache_block *parent); 00418 my_bool write_result_data(Query_cache_block **result, 00419 ulong data_len, uchar* data, 00420 Query_cache_block *parent, 00421 Query_cache_block::block_type 00422 type=Query_cache_block::RESULT); 00423 inline ulong get_min_first_result_data_size(); 00424 inline ulong get_min_append_result_data_size(); 00425 Query_cache_block *allocate_block(ulong len, my_bool not_less, 00426 ulong min); 00427 /* 00428 If query is cacheable return number tables in query 00429 (query without tables not cached) 00430 */ 00431 TABLE_COUNTER_TYPE is_cacheable(THD *thd, size_t query_len, 00432 const char *query, 00433 LEX *lex, TABLE_LIST *tables_used, 00434 uint8 *tables_type); 00435 TABLE_COUNTER_TYPE process_and_count_tables(THD *thd, 00436 TABLE_LIST *tables_used, 00437 uint8 *tables_type); 00438 00439 static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used); 00440 public: 00441 00442 Query_cache(ulong query_cache_limit = ULONG_MAX, 00443 ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT, 00444 ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE, 00445 uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, 00446 uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); 00447 00448 bool is_disabled(void) { return m_query_cache_is_disabled; } 00449 00450 /* initialize cache (mutex) */ 00451 void init(); 00452 /* resize query cache (return real query size, 0 if disabled) */ 00453 ulong resize(ulong query_cache_size); 00454 /* set limit on result size */ 00455 inline void result_size_limit(ulong limit){query_cache_limit=limit;} 00456 /* set minimal result data allocation unit size */ 00457 ulong set_min_res_unit(ulong size); 00458 00459 /* register query in cache */ 00460 void store_query(THD *thd, TABLE_LIST *used_tables); 00461 00462 /* 00463 Check if the query is in the cache and if this is true send the 00464 data to client. 00465 */ 00466 int send_result_to_client(THD *thd, char *query, uint query_length); 00467 00468 /* Remove all queries that uses any of the listed following tables */ 00469 void invalidate(THD* thd, TABLE_LIST *tables_used, 00470 my_bool using_transactions); 00471 void invalidate(CHANGED_TABLE_LIST *tables_used); 00472 void invalidate_locked_for_write(TABLE_LIST *tables_used); 00473 void invalidate(THD* thd, TABLE *table, my_bool using_transactions); 00474 void invalidate(THD *thd, const char *key, uint32 key_length, 00475 my_bool using_transactions); 00476 00477 /* Remove all queries that uses any of the tables in following database */ 00478 void invalidate(char *db); 00479 00480 /* Remove all queries that uses any of the listed following table */ 00481 void invalidate_by_MyISAM_filename(const char *filename); 00482 00483 void flush(); 00484 void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT, 00485 uint iteration_limit = QUERY_CACHE_PACK_ITERATION); 00486 00487 void destroy(); 00488 00489 void insert(Query_cache_tls *query_cache_tls, 00490 const char *packet, 00491 ulong length, 00492 unsigned pkt_nr); 00493 00494 void end_of_result(THD *thd); 00495 void abort(Query_cache_tls *query_cache_tls); 00496 00497 /* 00498 The following functions are only used when debugging 00499 We don't protect these with ifndef DBUG_OFF to not have to recompile 00500 everything if we want to add checks of the cache at some places. 00501 */ 00502 void wreck(uint line, const char *message); 00503 void bins_dump(); 00504 void cache_dump(); 00505 void queries_dump(); 00506 void tables_dump(); 00507 my_bool check_integrity(bool not_locked); 00508 my_bool in_list(Query_cache_block * root, Query_cache_block * point, 00509 const char *name); 00510 my_bool in_table_list(Query_cache_block_table * root, 00511 Query_cache_block_table * point, 00512 const char *name); 00513 my_bool in_blocks(Query_cache_block * point); 00514 00515 bool try_lock(bool use_timeout= FALSE); 00516 void lock(void); 00517 void lock_and_suspend(void); 00518 void unlock(void); 00519 }; 00520 00521 #ifdef HAVE_QUERY_CACHE 00522 struct Query_cache_query_flags 00523 { 00524 unsigned int client_long_flag:1; 00525 unsigned int client_protocol_41:1; 00526 unsigned int protocol_type:2; 00527 unsigned int more_results_exists:1; 00528 unsigned int in_trans:1; 00529 unsigned int autocommit:1; 00530 unsigned int pkt_nr; 00531 uint character_set_client_num; 00532 uint character_set_results_num; 00533 uint collation_connection_num; 00534 ha_rows limit; 00535 Time_zone *time_zone; 00536 sql_mode_t sql_mode; 00537 ulong max_sort_length; 00538 ulong group_concat_max_len; 00539 ulong default_week_format; 00540 ulong div_precision_increment; 00541 MY_LOCALE *lc_time_names; 00542 }; 00543 #define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags) 00544 #include "sql_cache.h" 00545 #define query_cache_abort(A) query_cache.abort(A) 00546 #define query_cache_end_of_result(A) query_cache.end_of_result(A) 00547 #define query_cache_store_query(A, B) query_cache.store_query(A, B) 00548 #define query_cache_destroy() query_cache.destroy() 00549 #define query_cache_result_size_limit(A) query_cache.result_size_limit(A) 00550 #define query_cache_init() query_cache.init() 00551 #define query_cache_resize(A) query_cache.resize(A) 00552 #define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A) 00553 #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C) 00554 #define query_cache_invalidate1(A) query_cache.invalidate(A) 00555 #define query_cache_send_result_to_client(A, B, C) \ 00556 query_cache.send_result_to_client(A, B, C) 00557 #define query_cache_invalidate_by_MyISAM_filename_ref \ 00558 &query_cache_invalidate_by_MyISAM_filename 00559 /* note the "maybe": it's a read without mutex */ 00560 #define query_cache_maybe_disabled(T) \ 00561 (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0) 00562 #define query_cache_is_cacheable_query(L) \ 00563 (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query && \ 00564 !(L)->describe) 00565 #else 00566 #define QUERY_CACHE_FLAGS_SIZE 0 00567 #define query_cache_store_query(A, B) 00568 #define query_cache_destroy() 00569 #define query_cache_result_size_limit(A) 00570 #define query_cache_init() 00571 #define query_cache_resize(A) 00572 #define query_cache_set_min_res_unit(A) 00573 #define query_cache_invalidate3(A, B, C) 00574 #define query_cache_invalidate1(A) 00575 #define query_cache_send_result_to_client(A, B, C) 0 00576 #define query_cache_invalidate_by_MyISAM_filename_ref NULL 00577 00578 #define query_cache_abort(A) 00579 #define query_cache_end_of_result(A) 00580 #define query_cache_invalidate_by_MyISAM_filename_ref NULL 00581 #define query_cache_maybe_disabled(T) 1 00582 #define query_cache_is_cacheable_query(L) 0 00583 #endif /*HAVE_QUERY_CACHE*/ 00584 00585 extern Query_cache query_cache; 00586 #endif