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