1 /* Copyright (c) 2001, 2021, Oracle and/or its affiliates. 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_mysql_const_lex_string LEX_CSTRING; 35 typedef struct st_changed_table_list CHANGED_TABLE_LIST; 36 typedef ulonglong sql_mode_t; 37 38 /* Query cache */ 39 40 /* 41 Can't create new free memory block if unused memory in block less 42 then QUERY_CACHE_MIN_ALLOCATION_UNIT. 43 if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then 44 QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly 45 */ 46 #define QUERY_CACHE_MIN_ALLOCATION_UNIT 512 47 48 /* inittial size of hashes */ 49 #define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024 50 #define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024 51 52 /* minimal result data size when data allocated */ 53 #define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024*4 54 55 /* 56 start estimation of first result block size only when number of queries 57 bigger then: 58 */ 59 #define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3 60 61 62 63 /* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */ 64 #define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4 65 #define QUERY_CACHE_MEM_BIN_STEP_PWR2 2 66 #define QUERY_CACHE_MEM_BIN_PARTS_INC 1 67 #define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2 68 #define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3 69 70 /* how many free blocks check when finding most suitable before other 'end' 71 of list of free blocks */ 72 #define QUERY_CACHE_MEM_BIN_TRY 5 73 74 /* packing parameters */ 75 #define QUERY_CACHE_PACK_ITERATION 2 76 #define QUERY_CACHE_PACK_LIMIT (512*1024L) 77 78 #define TABLE_COUNTER_TYPE size_t 79 80 struct Query_cache_block; 81 struct Query_cache_block_table; 82 struct Query_cache_table; 83 struct Query_cache_query; 84 struct Query_cache_result; 85 class Query_cache; 86 struct Query_cache_tls; 87 struct LEX; 88 class THD; 89 90 typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, 91 uint key_length, 92 ulonglong *engine_data); 93 94 /** 95 This class represents a node in the linked chain of queries 96 belonging to one table. 97 98 @note The root of this linked list is not a query-type block, but the table- 99 type block which all queries has in common. 100 */ 101 struct Query_cache_block_table 102 { Query_cache_block_tableQuery_cache_block_table103 Query_cache_block_table() {} /* Remove gcc warning */ 104 105 /** 106 This node holds a position in a static table list belonging 107 to the associated query (base 0). 108 */ 109 TABLE_COUNTER_TYPE n; 110 111 /** 112 Pointers to the next and previous node, linking all queries with 113 a common table. 114 */ 115 Query_cache_block_table *next, *prev; 116 117 /** 118 A pointer to the table-type block which all 119 linked queries has in common. 120 */ 121 Query_cache_table *parent; 122 123 /** 124 A method to calculate the address of the query cache block 125 owning this node. The purpose of this calculation is to 126 make it easier to move the query cache block without having 127 to modify all the pointer addresses. 128 */ 129 inline Query_cache_block *block(); 130 }; 131 132 struct Query_cache_block 133 { Query_cache_blockQuery_cache_block134 Query_cache_block() {} /* Remove gcc warning */ 135 enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG, 136 RES_INCOMPLETE, TABLE, INCOMPLETE}; 137 138 ulong length; // length of all block 139 ulong used; // length of data 140 /* 141 Not used **pprev, **prev because really needed access to pervious block: 142 *pprev to join free blocks 143 *prev to access to opposite side of list in cyclic sorted list 144 */ 145 Query_cache_block *pnext,*pprev, // physical next/previous block 146 *next,*prev; // logical next/previous block 147 block_type type; 148 TABLE_COUNTER_TYPE n_tables; // number of tables in query 149 is_freeQuery_cache_block150 inline my_bool is_free(void) { return type == FREE; } 151 void init(ulong length); 152 void destroy(); 153 inline uint headers_len(); 154 inline uchar* data(void); 155 inline Query_cache_query *query(); 156 inline Query_cache_table *table(); 157 inline Query_cache_result *result(); 158 inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n); 159 }; 160 161 struct Query_cache_query 162 { 163 ulonglong current_found_rows; 164 mysql_rwlock_t lock; 165 Query_cache_block *res; 166 Query_cache_tls *wri; 167 ulong len; 168 uint8 tbls_type; 169 unsigned int last_pkt_nr; 170 Query_cache_queryQuery_cache_query171 Query_cache_query() {} /* Remove gcc warning */ 172 inline void init_n_lock(); 173 void unlock_n_destroy(); found_rowsQuery_cache_query174 inline ulonglong found_rows() { return current_found_rows; } found_rowsQuery_cache_query175 inline void found_rows(ulonglong rows) { current_found_rows= rows; } resultQuery_cache_query176 inline Query_cache_block *result() { return res; } resultQuery_cache_query177 inline void result(Query_cache_block *p) { res= p; } writerQuery_cache_query178 inline Query_cache_tls *writer() { return wri; } writerQuery_cache_query179 inline void writer(Query_cache_tls *p) { wri= p; } tables_typeQuery_cache_query180 inline uint8 tables_type() { return tbls_type; } tables_typeQuery_cache_query181 inline void tables_type(uint8 type) { tbls_type= type; } lengthQuery_cache_query182 inline ulong length() { return len; } addQuery_cache_query183 inline ulong add(ulong packet_len) { return(len+= packet_len); } lengthQuery_cache_query184 inline void length(ulong length_arg) { len= length_arg; } queryQuery_cache_query185 inline uchar* query() 186 { 187 return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query))); 188 } 189 void lock_writing(); 190 void lock_reading(); 191 my_bool try_lock_writing(); 192 void unlock_writing(); 193 void unlock_reading(); 194 }; 195 196 197 struct Query_cache_table 198 { Query_cache_tableQuery_cache_table199 Query_cache_table() {} /* Remove gcc warning */ 200 char *tbl; 201 uint32 key_len; 202 uint8 table_type; 203 /* unique for every engine reference */ 204 qc_engine_callback callback_func; 205 /* data need by some engines */ 206 ulonglong engine_data_buff; 207 208 /** 209 The number of queries depending of this table. 210 */ 211 int32 m_cached_query_count; 212 dbQuery_cache_table213 inline char *db() { return (char *) data(); } tableQuery_cache_table214 inline char *table() { return tbl; } tableQuery_cache_table215 inline void table(char *table_arg) { tbl= table_arg; } key_lengthQuery_cache_table216 inline size_t key_length() { return key_len; } key_lengthQuery_cache_table217 inline void key_length(size_t len) { key_len= static_cast<uint32>(len); } typeQuery_cache_table218 inline uint8 type() { return table_type; } typeQuery_cache_table219 inline void type(uint8 t) { table_type= t; } callbackQuery_cache_table220 inline qc_engine_callback callback() { return callback_func; } callbackQuery_cache_table221 inline void callback(qc_engine_callback fn){ callback_func= fn; } engine_dataQuery_cache_table222 inline ulonglong engine_data() { return engine_data_buff; } engine_dataQuery_cache_table223 inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; } dataQuery_cache_table224 inline uchar* data() 225 { 226 return (uchar*)(((uchar*)this)+ 227 ALIGN_SIZE(sizeof(Query_cache_table))); 228 } 229 }; 230 231 struct Query_cache_result 232 { Query_cache_resultQuery_cache_result233 Query_cache_result() {} /* Remove gcc warning */ 234 Query_cache_block *query; 235 dataQuery_cache_result236 inline uchar* data() 237 { 238 return (uchar*)(((uchar*) this)+ 239 ALIGN_SIZE(sizeof(Query_cache_result))); 240 } 241 /* data_continue (if not whole packet contained by this block) */ parentQuery_cache_result242 inline Query_cache_block *parent() { return query; } parentQuery_cache_result243 inline void parent (Query_cache_block *p) { query=p; } 244 }; 245 246 247 extern "C" 248 { 249 uchar *query_cache_query_get_key(const uchar *record, size_t *length, 250 my_bool not_used); 251 uchar *query_cache_table_get_key(const uchar *record, size_t *length, 252 my_bool not_used); 253 } 254 extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename); 255 256 257 struct Query_cache_memory_bin 258 { Query_cache_memory_binQuery_cache_memory_bin259 Query_cache_memory_bin() {} /* Remove gcc warning */ 260 #ifndef NDEBUG 261 ulong size; 262 #endif 263 uint number; 264 Query_cache_block *free_blocks; 265 initQuery_cache_memory_bin266 inline void init(ulong size_arg) 267 { 268 #ifndef NDEBUG 269 size = size_arg; 270 #endif 271 number = 0; 272 free_blocks = 0; 273 } 274 }; 275 276 struct Query_cache_memory_bin_step 277 { Query_cache_memory_bin_stepQuery_cache_memory_bin_step278 Query_cache_memory_bin_step() {} /* Remove gcc warning */ 279 ulong size; 280 ulong increment; 281 uint idx; initQuery_cache_memory_bin_step282 inline void init(ulong size_arg, uint idx_arg, ulong increment_arg) 283 { 284 size = size_arg; 285 idx = idx_arg; 286 increment = increment_arg; 287 } 288 }; 289 290 class Query_cache 291 { 292 public: 293 /* Info */ 294 ulong query_cache_size, query_cache_limit; 295 /* statistics */ 296 ulong free_memory, queries_in_cache, hits, inserts, refused, 297 free_memory_blocks, total_blocks, lowmem_prunes; 298 299 300 private: 301 #ifndef NDEBUG 302 my_thread_id m_cache_lock_thread_id; 303 #endif 304 mysql_cond_t COND_cache_status_changed; 305 enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED }; 306 Cache_lock_status m_cache_lock_status; 307 308 bool m_query_cache_is_disabled; 309 310 void free_query_internal(Query_cache_block *point); 311 void invalidate_table_internal(THD *thd, uchar *key, size_t key_length); disable_query_cache(void)312 void disable_query_cache(void) { m_query_cache_is_disabled= TRUE; } 313 314 protected: 315 /* 316 The following mutex is locked when searching or changing global 317 query, tables lists or hashes. When we are operating inside the 318 query structure we locked an internal query block mutex. 319 LOCK SEQUENCE (to prevent deadlocks): 320 1. structure_guard_mutex 321 2. query block (for operation inside query (query block/results)) 322 323 Thread doing cache flush releases the mutex once it sets 324 m_cache_status flag, so other threads may bypass the cache as 325 if it is disabled, not waiting for reset to finish. The exception 326 is other threads that were going to do cache flush---they'll wait 327 till the end of a flush operation. 328 */ 329 mysql_mutex_t structure_guard_mutex; 330 uchar *cache; // cache memory 331 Query_cache_block *first_block; // physical location block list 332 Query_cache_block *queries_blocks; // query list (LIFO) 333 Query_cache_block *tables_blocks; 334 335 Query_cache_memory_bin *bins; // free block lists 336 Query_cache_memory_bin_step *steps; // bins spacing info 337 HASH queries, tables; 338 /* options */ 339 ulong min_allocation_unit, min_result_data_size; 340 uint def_query_hash_size, def_table_hash_size; 341 342 uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin 343 344 my_bool initialized; 345 346 /* Exclude/include from cyclic double linked list */ 347 static void double_linked_list_exclude(Query_cache_block *point, 348 Query_cache_block **list_pointer); 349 static void double_linked_list_simple_include(Query_cache_block *point, 350 Query_cache_block ** 351 list_pointer); 352 static void double_linked_list_join(Query_cache_block *head_tail, 353 Query_cache_block *tail_head); 354 355 /* Table key generation */ 356 static size_t filename_2_table_key (char *key, const char *filename, 357 size_t *db_length); 358 359 /* The following functions require that structure_guard_mutex is locked */ 360 void flush_cache(); 361 my_bool free_old_query(); 362 void free_query(Query_cache_block *point); 363 my_bool allocate_data_chain(Query_cache_block **result_block, 364 ulong data_len, 365 Query_cache_block *query_block, 366 my_bool first_block); 367 void invalidate_table(THD *thd, TABLE_LIST *table); 368 void invalidate_table(THD *thd, TABLE *table); 369 void invalidate_table(THD *thd, uchar *key, size_t key_length); 370 void invalidate_table(THD *thd, Query_cache_block *table_block); 371 void invalidate_query_block_list(THD *thd, 372 Query_cache_block_table *list_root); 373 374 TABLE_COUNTER_TYPE 375 register_tables_from_list(TABLE_LIST *tables_used, 376 TABLE_COUNTER_TYPE counter, 377 Query_cache_block_table *block_table); 378 my_bool register_all_tables(Query_cache_block *block, 379 TABLE_LIST *tables_used, 380 TABLE_COUNTER_TYPE tables); 381 my_bool insert_table(size_t key_len, const char *key, 382 Query_cache_block_table *node, 383 size_t db_length, uint8 cache_type, 384 qc_engine_callback callback, 385 ulonglong engine_data); 386 void unlink_table(Query_cache_block_table *node); 387 Query_cache_block *get_free_block (size_t len, my_bool not_less, 388 size_t min); 389 void free_memory_block(Query_cache_block *point); 390 void split_block(Query_cache_block *block, ulong len); 391 Query_cache_block *join_free_blocks(Query_cache_block *first_block, 392 Query_cache_block *block_in_list); 393 my_bool append_next_free_block(Query_cache_block *block, 394 ulong add_size); 395 void exclude_from_free_memory_list(Query_cache_block *free_block); 396 void insert_into_free_memory_list(Query_cache_block *new_block); 397 my_bool move_by_type(uchar **border, Query_cache_block **before, 398 ulong *gap, Query_cache_block *i); 399 uint find_bin(size_t size); 400 void move_to_query_list_end(Query_cache_block *block); 401 void insert_into_free_memory_sorted_list(Query_cache_block *new_block, 402 Query_cache_block **list); 403 void pack_cache(); 404 void relink(Query_cache_block *oblock, 405 Query_cache_block *nblock, 406 Query_cache_block *next, 407 Query_cache_block *prev, 408 Query_cache_block *pnext, 409 Query_cache_block *pprev); 410 my_bool join_results(ulong join_limit); 411 412 /* 413 Following function control structure_guard_mutex 414 by themself or don't need structure_guard_mutex 415 */ 416 ulong init_cache(); 417 void make_disabled(); 418 void free_cache(); 419 Query_cache_block *write_block_data(size_t data_len, uchar* data, 420 size_t header_len, 421 Query_cache_block::block_type type, 422 TABLE_COUNTER_TYPE ntab = 0); 423 my_bool append_result_data(Query_cache_block **result, 424 ulong data_len, uchar* data, 425 Query_cache_block *parent); 426 my_bool write_result_data(Query_cache_block **result, 427 ulong data_len, uchar* data, 428 Query_cache_block *parent, 429 Query_cache_block::block_type 430 type=Query_cache_block::RESULT); 431 inline ulong get_min_first_result_data_size(); 432 inline ulong get_min_append_result_data_size(); 433 Query_cache_block *allocate_block(size_t len, my_bool not_less, 434 size_t min); 435 /* 436 If query is cacheable return number tables in query 437 (query without tables not cached) 438 */ 439 TABLE_COUNTER_TYPE is_cacheable(THD *thd, LEX *lex, TABLE_LIST *tables_used, 440 uint8 *tables_type); 441 TABLE_COUNTER_TYPE process_and_count_tables(THD *thd, 442 TABLE_LIST *tables_used, 443 uint8 *tables_type); 444 445 static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used); 446 public: 447 448 Query_cache(ulong query_cache_limit = ULONG_MAX, 449 ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT, 450 ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE, 451 uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, 452 uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); 453 is_disabled(void)454 bool is_disabled(void) { return m_query_cache_is_disabled; } 455 456 /* initialize cache (mutex) */ 457 void init(); 458 /* resize query cache (return real query size, 0 if disabled) */ 459 ulong resize(ulong query_cache_size); 460 /* set limit on result size */ result_size_limit(ulong limit)461 inline void result_size_limit(ulong limit){query_cache_limit=limit;} 462 /* set minimal result data allocation unit size */ 463 ulong set_min_res_unit(ulong size); 464 465 /* register query in cache */ 466 void store_query(THD *thd, TABLE_LIST *used_tables); 467 468 /* 469 Check if the query is in the cache and if this is true send the 470 data to client. 471 */ 472 int send_result_to_client(THD *thd, const LEX_CSTRING &sql); 473 474 /* Remove all queries that use the given table */ 475 void invalidate_single(THD* thd, TABLE_LIST *table_used, 476 my_bool using_transactions); 477 /* Remove all queries that uses any of the listed following tables */ 478 void invalidate(THD* thd, TABLE_LIST *tables_used, 479 my_bool using_transactions); 480 void invalidate(CHANGED_TABLE_LIST *tables_used); 481 void invalidate_locked_for_write(TABLE_LIST *tables_used); 482 void invalidate(THD* thd, TABLE *table, my_bool using_transactions); 483 void invalidate(THD *thd, const char *key, uint32 key_length, 484 my_bool using_transactions); 485 486 /* Remove all queries that uses any of the tables in following database */ 487 void invalidate(const char *db); 488 489 /* Remove all queries that uses any of the listed following table */ 490 void invalidate_by_MyISAM_filename(const char *filename); 491 492 void flush(); 493 void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT, 494 uint iteration_limit = QUERY_CACHE_PACK_ITERATION); 495 496 void destroy(); 497 498 void insert(Query_cache_tls *query_cache_tls, 499 const char *packet, 500 ulong length, 501 unsigned pkt_nr); 502 503 void end_of_result(THD *thd); 504 void abort(Query_cache_tls *query_cache_tls); 505 506 /* 507 The following functions are only used when debugging 508 We don't protect these with ifndef NDEBUG to not have to recompile 509 everything if we want to add checks of the cache at some places. 510 */ 511 void wreck(uint line, const char *message); 512 void bins_dump(); 513 void cache_dump(); 514 void queries_dump(); 515 void tables_dump(); 516 enum enum_qcci_lock_mode { CALLER_HOLDS_LOCK, LOCK_WHILE_CHECKING }; 517 bool check_integrity(enum_qcci_lock_mode locking); 518 my_bool in_list(Query_cache_block * root, Query_cache_block * point, 519 const char *name); 520 my_bool in_table_list(Query_cache_block_table * root, 521 Query_cache_block_table * point, 522 const char *name); 523 my_bool in_blocks(Query_cache_block * point); 524 525 bool try_lock(bool use_timeout= FALSE); 526 void lock(void); 527 void lock_and_suspend(void); 528 void unlock(void); 529 }; 530 531 struct Query_cache_query_flags 532 { 533 unsigned int client_long_flag:1; 534 unsigned int client_protocol_41:1; 535 unsigned int protocol_type:2; 536 unsigned int more_results_exists:1; 537 unsigned int in_trans:1; 538 unsigned int autocommit:1; 539 unsigned int pkt_nr; 540 uint character_set_client_num; 541 uint character_set_results_num; 542 uint collation_connection_num; 543 ha_rows limit; 544 Time_zone *time_zone; 545 sql_mode_t sql_mode; 546 ulong max_sort_length; 547 ulong group_concat_max_len; 548 ulong default_week_format; 549 ulong div_precision_increment; 550 MY_LOCALE *lc_time_names; 551 }; 552 #define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags) 553 554 extern Query_cache query_cache; 555 #endif 556