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