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-1301 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
22class MY_LOCALE;
23struct TABLE_LIST;
24class Time_zone;
25struct LEX;
26struct TABLE;
27typedef struct st_changed_table_list CHANGED_TABLE_LIST;
28
29/* Query cache */
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
71struct Query_cache_block;
72struct Query_cache_block_table;
73struct Query_cache_table;
74struct Query_cache_query;
75struct Query_cache_result;
76class Query_cache;
77struct Query_cache_tls;
78struct LEX;
79class THD;
80
81typedef 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*/
92struct 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).
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();
121};
122
123struct 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);
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
152struct 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 */
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; }
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); }
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 */
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
198struct 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
241struct 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
257extern "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}
264extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
265
266
267struct 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
286struct 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
300class Query_cache
301{
302public:
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
310private:
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
324protected:
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
548struct 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 ha_rows limit;
562 Time_zone *time_zone;
563 sql_mode_t sql_mode;
564 ulonglong max_sort_length;
565 ulonglong group_concat_max_len;
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
611extern Query_cache query_cache;
612#endif
613