1 /* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License, version 2.0, 5 as published by the Free Software Foundation. 6 7 This program is also distributed with certain software (including 8 but not limited to OpenSSL) that is licensed under separate terms, 9 as designated in a particular file or component or in included license 10 documentation. The authors of MySQL hereby grant you an additional 11 permission to link the program and your derivative works with the 12 separately licensed software that they have included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software Foundation, 21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 22 23 #ifndef _SQL_CACHE_H 24 #define _SQL_CACHE_H 25 26 #include "hash.h" 27 #include "my_base.h" /* ha_rows */ 28 29 class MY_LOCALE; 30 struct TABLE_LIST; 31 class Time_zone; 32 struct LEX; 33 struct TABLE; 34 typedef struct st_changed_table_list CHANGED_TABLE_LIST; 35 typedef ulonglong sql_mode_t; 36 37 /* Query cache */ 38 39 /* 40 Can't create new free memory block if unused memory in block less 41 then QUERY_CACHE_MIN_ALLOCATION_UNIT. 42 if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then 43 QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly 44 */ 45 #define QUERY_CACHE_MIN_ALLOCATION_UNIT 512 46 47 /* inittial size of hashes */ 48 #define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024 49 #define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024 50 51 /* minimal result data size when data allocated */ 52 #define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024*4 53 54 /* 55 start estimation of first result block size only when number of queries 56 bigger then: 57 */ 58 #define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3 59 60 61 62 /* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */ 63 #define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4 64 #define QUERY_CACHE_MEM_BIN_STEP_PWR2 2 65 #define QUERY_CACHE_MEM_BIN_PARTS_INC 1 66 #define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2 67 #define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3 68 69 /* how many free blocks check when finding most suitable before other 'end' 70 of list of free blocks */ 71 #define QUERY_CACHE_MEM_BIN_TRY 5 72 73 /* packing parameters */ 74 #define QUERY_CACHE_PACK_ITERATION 2 75 #define QUERY_CACHE_PACK_LIMIT (512*1024L) 76 77 #define TABLE_COUNTER_TYPE uint 78 79 struct Query_cache_block; 80 struct Query_cache_block_table; 81 struct Query_cache_table; 82 struct Query_cache_query; 83 struct Query_cache_result; 84 class Query_cache; 85 struct Query_cache_tls; 86 struct LEX; 87 class THD; 88 89 typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, 90 uint key_length, 91 ulonglong *engine_data); 92 93 /** 94 This class represents a node in the linked chain of queries 95 belonging to one table. 96 97 @note The root of this linked list is not a query-type block, but the table- 98 type block which all queries has in common. 99 */ 100 struct Query_cache_block_table 101 { Query_cache_block_tableQuery_cache_block_table102 Query_cache_block_table() {} /* Remove gcc warning */ 103 104 /** 105 This node holds a position in a static table list belonging 106 to the associated query (base 0). 107 */ 108 TABLE_COUNTER_TYPE n; 109 110 /** 111 Pointers to the next and previous node, linking all queries with 112 a common table. 113 */ 114 Query_cache_block_table *next, *prev; 115 116 /** 117 A pointer to the table-type block which all 118 linked queries has in common. 119 */ 120 Query_cache_table *parent; 121 122 /** 123 A method to calculate the address of the query cache block 124 owning this node. The purpose of this calculation is to 125 make it easier to move the query cache block without having 126 to modify all the pointer addresses. 127 */ 128 inline Query_cache_block *block(); 129 }; 130 131 struct Query_cache_block 132 { Query_cache_blockQuery_cache_block133 Query_cache_block() {} /* Remove gcc warning */ 134 enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG, 135 RES_INCOMPLETE, TABLE, INCOMPLETE}; 136 137 ulong length; // length of all block 138 ulong used; // length of data 139 /* 140 Not used **pprev, **prev because really needed access to pervious block: 141 *pprev to join free blocks 142 *prev to access to opposite side of list in cyclic sorted list 143 */ 144 Query_cache_block *pnext,*pprev, // physical next/previous block 145 *next,*prev; // logical next/previous block 146 block_type type; 147 TABLE_COUNTER_TYPE n_tables; // number of tables in query 148 is_freeQuery_cache_block149 inline my_bool is_free(void) { return type == FREE; } 150 void init(ulong length); 151 void destroy(); 152 inline uint headers_len(); 153 inline uchar* data(void); 154 inline Query_cache_query *query(); 155 inline Query_cache_table *table(); 156 inline Query_cache_result *result(); 157 inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n); 158 }; 159 160 struct Query_cache_query 161 { 162 ulonglong limit_found_rows; 163 mysql_rwlock_t lock; 164 Query_cache_block *res; 165 Query_cache_tls *wri; 166 ulong len; 167 uint8 tbls_type; 168 unsigned int last_pkt_nr; 169 Query_cache_queryQuery_cache_query170 Query_cache_query() {} /* Remove gcc warning */ 171 inline void init_n_lock(); 172 void unlock_n_destroy(); found_rowsQuery_cache_query173 inline ulonglong found_rows() { return limit_found_rows; } found_rowsQuery_cache_query174 inline void found_rows(ulonglong rows) { limit_found_rows= rows; } resultQuery_cache_query175 inline Query_cache_block *result() { return res; } resultQuery_cache_query176 inline void result(Query_cache_block *p) { res= p; } writerQuery_cache_query177 inline Query_cache_tls *writer() { return wri; } writerQuery_cache_query178 inline void writer(Query_cache_tls *p) { wri= p; } tables_typeQuery_cache_query179 inline uint8 tables_type() { return tbls_type; } tables_typeQuery_cache_query180 inline void tables_type(uint8 type) { tbls_type= type; } lengthQuery_cache_query181 inline ulong length() { return len; } addQuery_cache_query182 inline ulong add(ulong packet_len) { return(len+= packet_len); } lengthQuery_cache_query183 inline void length(ulong length_arg) { len= length_arg; } queryQuery_cache_query184 inline uchar* query() 185 { 186 return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query))); 187 } 188 void lock_writing(); 189 void lock_reading(); 190 my_bool try_lock_writing(); 191 void unlock_writing(); 192 void unlock_reading(); 193 }; 194 195 196 struct Query_cache_table 197 { Query_cache_tableQuery_cache_table198 Query_cache_table() {} /* Remove gcc warning */ 199 char *tbl; 200 uint32 key_len; 201 uint8 table_type; 202 /* unique for every engine reference */ 203 qc_engine_callback callback_func; 204 /* data need by some engines */ 205 ulonglong engine_data_buff; 206 207 /** 208 The number of queries depending of this table. 209 */ 210 int32 m_cached_query_count; 211 dbQuery_cache_table212 inline char *db() { return (char *) data(); } tableQuery_cache_table213 inline char *table() { return tbl; } tableQuery_cache_table214 inline void table(char *table_arg) { tbl= table_arg; } key_lengthQuery_cache_table215 inline uint32 key_length() { return key_len; } key_lengthQuery_cache_table216 inline void key_length(uint32 len) { key_len= len; } typeQuery_cache_table217 inline uint8 type() { return table_type; } typeQuery_cache_table218 inline void type(uint8 t) { table_type= t; } callbackQuery_cache_table219 inline qc_engine_callback callback() { return callback_func; } callbackQuery_cache_table220 inline void callback(qc_engine_callback fn){ callback_func= fn; } engine_dataQuery_cache_table221 inline ulonglong engine_data() { return engine_data_buff; } engine_dataQuery_cache_table222 inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } dataQuery_cache_table223 inline uchar* data() 224 { 225 return (uchar*)(((uchar*)this)+ 226 ALIGN_SIZE(sizeof(Query_cache_table))); 227 } 228 }; 229 230 struct Query_cache_result 231 { Query_cache_resultQuery_cache_result232 Query_cache_result() {} /* Remove gcc warning */ 233 Query_cache_block *query; 234 dataQuery_cache_result235 inline uchar* data() 236 { 237 return (uchar*)(((uchar*) this)+ 238 ALIGN_SIZE(sizeof(Query_cache_result))); 239 } 240 /* data_continue (if not whole packet contained by this block) */ parentQuery_cache_result241 inline Query_cache_block *parent() { return query; } parentQuery_cache_result242 inline void parent (Query_cache_block *p) { query=p; } 243 }; 244 245 246 extern "C" 247 { 248 uchar *query_cache_query_get_key(const uchar *record, size_t *length, 249 my_bool not_used); 250 uchar *query_cache_table_get_key(const uchar *record, size_t *length, 251 my_bool not_used); 252 } 253 extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename); 254 255 256 struct Query_cache_memory_bin 257 { Query_cache_memory_binQuery_cache_memory_bin258 Query_cache_memory_bin() {} /* Remove gcc warning */ 259 #ifndef DBUG_OFF 260 ulong size; 261 #endif 262 uint number; 263 Query_cache_block *free_blocks; 264 initQuery_cache_memory_bin265 inline void init(ulong size_arg) 266 { 267 #ifndef DBUG_OFF 268 size = size_arg; 269 #endif 270 number = 0; 271 free_blocks = 0; 272 } 273 }; 274 275 struct Query_cache_memory_bin_step 276 { Query_cache_memory_bin_stepQuery_cache_memory_bin_step277 Query_cache_memory_bin_step() {} /* Remove gcc warning */ 278 ulong size; 279 ulong increment; 280 uint idx; initQuery_cache_memory_bin_step281 inline void init(ulong size_arg, uint idx_arg, ulong increment_arg) 282 { 283 size = size_arg; 284 idx = idx_arg; 285 increment = increment_arg; 286 } 287 }; 288 289 class Query_cache 290 { 291 public: 292 /* Info */ 293 ulong query_cache_size, query_cache_limit; 294 /* statistics */ 295 ulong free_memory, queries_in_cache, hits, inserts, refused, 296 free_memory_blocks, total_blocks, lowmem_prunes; 297 298 299 private: 300 #ifndef DBUG_OFF 301 my_thread_id m_cache_lock_thread_id; 302 #endif 303 mysql_cond_t COND_cache_status_changed; 304 enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED }; 305 Cache_lock_status m_cache_lock_status; 306 307 bool m_query_cache_is_disabled; 308 309 void free_query_internal(Query_cache_block *point); 310 void invalidate_table_internal(THD *thd, uchar *key, uint32 key_length); disable_query_cache(void)311 void disable_query_cache(void) { m_query_cache_is_disabled= TRUE; } 312 313 protected: 314 /* 315 The following mutex is locked when searching or changing global 316 query, tables lists or hashes. When we are operating inside the 317 query structure we locked an internal query block mutex. 318 LOCK SEQUENCE (to prevent deadlocks): 319 1. structure_guard_mutex 320 2. query block (for operation inside query (query block/results)) 321 322 Thread doing cache flush releases the mutex once it sets 323 m_cache_status flag, so other threads may bypass the cache as 324 if it is disabled, not waiting for reset to finish. The exception 325 is other threads that were going to do cache flush---they'll wait 326 till the end of a flush operation. 327 */ 328 mysql_mutex_t structure_guard_mutex; 329 uchar *cache; // cache memory 330 Query_cache_block *first_block; // physical location block list 331 Query_cache_block *queries_blocks; // query list (LIFO) 332 Query_cache_block *tables_blocks; 333 334 Query_cache_memory_bin *bins; // free block lists 335 Query_cache_memory_bin_step *steps; // bins spacing info 336 HASH queries, tables; 337 /* options */ 338 ulong min_allocation_unit, min_result_data_size; 339 uint def_query_hash_size, def_table_hash_size; 340 341 uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin 342 343 my_bool initialized; 344 345 /* Exclude/include from cyclic double linked list */ 346 static void double_linked_list_exclude(Query_cache_block *point, 347 Query_cache_block **list_pointer); 348 static void double_linked_list_simple_include(Query_cache_block *point, 349 Query_cache_block ** 350 list_pointer); 351 static void double_linked_list_join(Query_cache_block *head_tail, 352 Query_cache_block *tail_head); 353 354 /* Table key generation */ 355 static uint filename_2_table_key (char *key, const char *filename, 356 uint32 *db_langth); 357 358 /* The following functions require that structure_guard_mutex is locked */ 359 void flush_cache(); 360 my_bool free_old_query(); 361 void free_query(Query_cache_block *point); 362 my_bool allocate_data_chain(Query_cache_block **result_block, 363 ulong data_len, 364 Query_cache_block *query_block, 365 my_bool first_block); 366 void invalidate_table(THD *thd, TABLE_LIST *table); 367 void invalidate_table(THD *thd, TABLE *table); 368 void invalidate_table(THD *thd, uchar *key, uint32 key_length); 369 void invalidate_table(THD *thd, Query_cache_block *table_block); 370 void invalidate_query_block_list(THD *thd, 371 Query_cache_block_table *list_root); 372 373 TABLE_COUNTER_TYPE 374 register_tables_from_list(TABLE_LIST *tables_used, 375 TABLE_COUNTER_TYPE counter, 376 Query_cache_block_table *block_table); 377 my_bool register_all_tables(Query_cache_block *block, 378 TABLE_LIST *tables_used, 379 TABLE_COUNTER_TYPE tables); 380 my_bool insert_table(uint key_len, const char *key, 381 Query_cache_block_table *node, 382 uint32 db_length, uint8 cache_type, 383 qc_engine_callback callback, 384 ulonglong engine_data); 385 void unlink_table(Query_cache_block_table *node); 386 Query_cache_block *get_free_block (ulong len, my_bool not_less, 387 ulong min); 388 void free_memory_block(Query_cache_block *point); 389 void split_block(Query_cache_block *block, ulong len); 390 Query_cache_block *join_free_blocks(Query_cache_block *first_block, 391 Query_cache_block *block_in_list); 392 my_bool append_next_free_block(Query_cache_block *block, 393 ulong add_size); 394 void exclude_from_free_memory_list(Query_cache_block *free_block); 395 void insert_into_free_memory_list(Query_cache_block *new_block); 396 my_bool move_by_type(uchar **border, Query_cache_block **before, 397 ulong *gap, Query_cache_block *i); 398 uint find_bin(ulong size); 399 void move_to_query_list_end(Query_cache_block *block); 400 void insert_into_free_memory_sorted_list(Query_cache_block *new_block, 401 Query_cache_block **list); 402 void pack_cache(); 403 void relink(Query_cache_block *oblock, 404 Query_cache_block *nblock, 405 Query_cache_block *next, 406 Query_cache_block *prev, 407 Query_cache_block *pnext, 408 Query_cache_block *pprev); 409 my_bool join_results(ulong join_limit); 410 411 /* 412 Following function control structure_guard_mutex 413 by themself or don't need structure_guard_mutex 414 */ 415 ulong init_cache(); 416 void make_disabled(); 417 void free_cache(); 418 Query_cache_block *write_block_data(ulong data_len, uchar* data, 419 ulong header_len, 420 Query_cache_block::block_type type, 421 TABLE_COUNTER_TYPE ntab = 0); 422 my_bool append_result_data(Query_cache_block **result, 423 ulong data_len, uchar* data, 424 Query_cache_block *parent); 425 my_bool write_result_data(Query_cache_block **result, 426 ulong data_len, uchar* data, 427 Query_cache_block *parent, 428 Query_cache_block::block_type 429 type=Query_cache_block::RESULT); 430 inline ulong get_min_first_result_data_size(); 431 inline ulong get_min_append_result_data_size(); 432 Query_cache_block *allocate_block(ulong len, my_bool not_less, 433 ulong min); 434 /* 435 If query is cacheable return number tables in query 436 (query without tables not cached) 437 */ 438 TABLE_COUNTER_TYPE is_cacheable(THD *thd, size_t query_len, 439 const char *query, 440 LEX *lex, TABLE_LIST *tables_used, 441 uint8 *tables_type); 442 TABLE_COUNTER_TYPE process_and_count_tables(THD *thd, 443 TABLE_LIST *tables_used, 444 uint8 *tables_type); 445 446 static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used); 447 public: 448 449 Query_cache(ulong query_cache_limit = ULONG_MAX, 450 ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT, 451 ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE, 452 uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, 453 uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); 454 is_disabled(void)455 bool is_disabled(void) { return m_query_cache_is_disabled; } 456 457 /* initialize cache (mutex) */ 458 void init(); 459 /* resize query cache (return real query size, 0 if disabled) */ 460 ulong resize(ulong query_cache_size); 461 /* set limit on result size */ result_size_limit(ulong limit)462 inline void result_size_limit(ulong limit){query_cache_limit=limit;} 463 /* set minimal result data allocation unit size */ 464 ulong set_min_res_unit(ulong size); 465 466 /* register query in cache */ 467 void store_query(THD *thd, TABLE_LIST *used_tables); 468 469 /* 470 Check if the query is in the cache and if this is true send the 471 data to client. 472 */ 473 int send_result_to_client(THD *thd, char *query, uint query_length); 474 475 /* Remove all queries that uses any of the listed following tables */ 476 void invalidate(THD* thd, TABLE_LIST *tables_used, 477 my_bool using_transactions); 478 void invalidate(CHANGED_TABLE_LIST *tables_used); 479 void invalidate_locked_for_write(TABLE_LIST *tables_used); 480 void invalidate(THD* thd, TABLE *table, my_bool using_transactions); 481 void invalidate(THD *thd, const char *key, uint32 key_length, 482 my_bool using_transactions); 483 484 /* Remove all queries that uses any of the tables in following database */ 485 void invalidate(char *db); 486 487 /* Remove all queries that uses any of the listed following table */ 488 void invalidate_by_MyISAM_filename(const char *filename); 489 490 void flush(); 491 void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT, 492 uint iteration_limit = QUERY_CACHE_PACK_ITERATION); 493 494 void destroy(); 495 496 void insert(Query_cache_tls *query_cache_tls, 497 const char *packet, 498 ulong length, 499 unsigned pkt_nr); 500 501 void end_of_result(THD *thd); 502 void abort(Query_cache_tls *query_cache_tls); 503 504 /* 505 The following functions are only used when debugging 506 We don't protect these with ifndef DBUG_OFF to not have to recompile 507 everything if we want to add checks of the cache at some places. 508 */ 509 void wreck(uint line, const char *message); 510 void bins_dump(); 511 void cache_dump(); 512 void queries_dump(); 513 void tables_dump(); 514 my_bool check_integrity(bool not_locked); 515 my_bool in_list(Query_cache_block * root, Query_cache_block * point, 516 const char *name); 517 my_bool in_table_list(Query_cache_block_table * root, 518 Query_cache_block_table * point, 519 const char *name); 520 my_bool in_blocks(Query_cache_block * point); 521 522 bool try_lock(bool use_timeout= FALSE); 523 void lock(void); 524 void lock_and_suspend(void); 525 void unlock(void); 526 }; 527 528 #ifdef HAVE_QUERY_CACHE 529 struct Query_cache_query_flags 530 { 531 unsigned int client_long_flag:1; 532 unsigned int client_protocol_41:1; 533 unsigned int protocol_type:2; 534 unsigned int more_results_exists:1; 535 unsigned int in_trans:1; 536 unsigned int autocommit:1; 537 unsigned int pkt_nr; 538 uint character_set_client_num; 539 uint character_set_results_num; 540 uint collation_connection_num; 541 ha_rows limit; 542 Time_zone *time_zone; 543 sql_mode_t sql_mode; 544 ulong max_sort_length; 545 ulong group_concat_max_len; 546 ulong default_week_format; 547 ulong div_precision_increment; 548 MY_LOCALE *lc_time_names; 549 }; 550 #define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags) 551 #include "sql_cache.h" 552 #define query_cache_abort(A) query_cache.abort(A) 553 #define query_cache_end_of_result(A) query_cache.end_of_result(A) 554 #define query_cache_store_query(A, B) query_cache.store_query(A, B) 555 #define query_cache_destroy() query_cache.destroy() 556 #define query_cache_result_size_limit(A) query_cache.result_size_limit(A) 557 #define query_cache_init() query_cache.init() 558 #define query_cache_resize(A) query_cache.resize(A) 559 #define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A) 560 #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C) 561 #define query_cache_invalidate1(A) query_cache.invalidate(A) 562 #define query_cache_send_result_to_client(A, B, C) \ 563 query_cache.send_result_to_client(A, B, C) 564 #define query_cache_invalidate_by_MyISAM_filename_ref \ 565 &query_cache_invalidate_by_MyISAM_filename 566 /* note the "maybe": it's a read without mutex */ 567 #define query_cache_maybe_disabled(T) \ 568 (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0) 569 #define query_cache_is_cacheable_query(L) \ 570 (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query && \ 571 !(L)->describe) 572 #else 573 #define QUERY_CACHE_FLAGS_SIZE 0 574 #define query_cache_store_query(A, B) 575 #define query_cache_destroy() 576 #define query_cache_result_size_limit(A) 577 #define query_cache_init() 578 #define query_cache_resize(A) 579 #define query_cache_set_min_res_unit(A) 580 #define query_cache_invalidate3(A, B, C) 581 #define query_cache_invalidate1(A) 582 #define query_cache_send_result_to_client(A, B, C) 0 583 #define query_cache_invalidate_by_MyISAM_filename_ref NULL 584 585 #define query_cache_abort(A) 586 #define query_cache_end_of_result(A) 587 #define query_cache_invalidate_by_MyISAM_filename_ref NULL 588 #define query_cache_maybe_disabled(T) 1 589 #define query_cache_is_cacheable_query(L) 0 590 #endif /*HAVE_QUERY_CACHE*/ 591 592 extern Query_cache query_cache; 593 #endif 594