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