1 /* Copyright (c) 2000, 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 /*
24 Description of the query cache:
25
26 1. Query_cache object consists of
27 - query cache memory pool (cache)
28 - queries hash (queries)
29 - tables hash (tables)
30 - list of blocks ordered as they allocated in memory
31 (first_block)
32 - list of queries block (queries_blocks)
33 - list of used tables (tables_blocks)
34
35 2. Query cache memory pool (cache) consists of
36 - table of steps of memory bins allocation
37 - table of free memory bins
38 - blocks of memory
39
40 3. Memory blocks
41
42 Every memory block has the following structure:
43
44 +----------------------------------------------------------+
45 | Block header (Query_cache_block structure) |
46 +----------------------------------------------------------+
47 |Table of database table lists (used for queries & tables) |
48 +----------------------------------------------------------+
49 | Type depended header |
50 |(Query_cache_query, Query_cache_table, Query_cache_result)|
51 +----------------------------------------------------------+
52 | Data ... |
53 +----------------------------------------------------------+
54
55 Block header consists of:
56 - type:
57 FREE Free memory block
58 QUERY Query block
59 RESULT Ready to send result
60 RES_CONT Result's continuation
61 RES_BEG First block of results, that is not yet complete,
62 written to cache
63 RES_INCOMPLETE Allocated for results data block
64 TABLE Block with database table description
65 INCOMPLETE The destroyed block
66 - length of block (length)
67 - length of data & headers (used)
68 - physical list links (pnext/pprev) - used for the list of
69 blocks ordered as they are allocated in physical memory
70 - logical list links (next/prev) - used for queries block list, tables block
71 list, free memory block lists and list of results block in query
72 - number of elements in table of database table list (n_tables)
73
74 4. Query & results blocks
75
76 Query stored in cache consists of following blocks:
77
78 more more
79 recent+-------------+ old
80 <-----|Query block 1|------> double linked list of queries block
81 prev | | next
82 +-------------+
83 <-| table 0 |-> (see "Table of database table lists" description)
84 <-| table 1 |->
85 | ... | +--------------------------+
86 +-------------+ +-------------------------+ |
87 NET | | | V V |
88 struct| | +-+------------+ +------------+ |
89 <-----|query header |----->|Result block|-->|Result block|-+ doublelinked
90 writer| |result| |<--| | list of results
91 +-------------+ +------------+ +------------+
92 |charset | +------------+ +------------+ no table of dbtables
93 |encoding + | | result | | result |
94 |query text |<-----| header | | header |------+
95 +-------------+parent| | | |parent|
96 ^ +------------+ +------------+ |
97 | |result data | |result data | |
98 | +------------+ +------------+ |
99 +---------------------------------------------------+
100
101 First query is registered. During the registration query block is
102 allocated. This query block is included in query hash and is linked
103 with appropriate database tables lists (if there is no appropriate
104 list exists it will be created).
105
106 Later when query has performed results is written into the result blocks.
107 A result block cannot be smaller then QUERY_CACHE_MIN_RESULT_DATA_SIZE.
108
109 When new result is written to cache it is appended to the last result
110 block, if no more free space left in the last block, new block is
111 allocated.
112
113 5. Table of database table lists.
114
115 For quick invalidation of queries all query are linked in lists on used
116 database tables basis (when table will be changed (insert/delete/...)
117 this queries will be removed from cache).
118
119 Root of such list is table block:
120
121 +------------+ list of used tables (used while invalidation of
122 <----| Table |-----> whole database)
123 prev| block |next +-----------+
124 | | +-----------+ |Query block|
125 | | |Query block| +-----------+
126 +------------+ +-----------+ | ... |
127 +->| table 0 |------>|table 0 |----->| table N |---+
128 |+-| |<------| |<-----| |<-+|
129 || +------------+ | ... | | ... | ||
130 || |table header| +-----------+ +-----------+ ||
131 || +------------+ | ... | | ... | ||
132 || |db name + | +-----------+ +-----------+ ||
133 || |table name | ||
134 || +------------+ ||
135 |+--------------------------------------------------------+|
136 +----------------------------------------------------------+
137
138 Table block is included into the tables hash (tables).
139
140 6. Free blocks, free blocks bins & steps of freeblock bins.
141
142 When we just started only one free memory block existed. All query
143 cache memory (that will be used for block allocation) were
144 containing in this block.
145 When a new block is allocated we find most suitable memory block
146 (minimal of >= required size). If such a block can not be found, we try
147 to find max block < required size (if we allocate block for results).
148 If there is no free memory, oldest query is removed from cache, and then
149 we try to allocate memory. Last step should be repeated until we find
150 suitable block or until there is no unlocked query found.
151
152 If the block is found and its length more then we need, it should be
153 split into 2 blocks.
154 New blocks cannot be smaller then min_allocation_unit_bytes.
155
156 When a block becomes free, its neighbor-blocks should be tested and if
157 there are free blocks among them, they should be joined into one block.
158
159 Free memory blocks are stored in bins according to their sizes.
160 The bins are stored in size-descending order.
161 These bins are distributed (by size) approximately logarithmically.
162
163 First bin (number 0) stores free blocks with
164 size <= query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2.
165 It is first (number 0) step.
166 On the next step distributed (1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
167 QUERY_CACHE_MEM_BIN_PARTS_MUL bins. This bins allocated in interval from
168 query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 to
169 query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 >>
170 QUERY_CACHE_MEM_BIN_STEP_PWR2
171 ...
172 On each step interval decreases in 2 power of
173 QUERY_CACHE_MEM_BIN_STEP_PWR2
174 times, number of bins (that distributed on this step) increases. If on
175 the previous step there were N bins distributed , on the current there
176 would be distributed
177 (N + QUERY_CACHE_MEM_BIN_PARTS_INC) * QUERY_CACHE_MEM_BIN_PARTS_MUL
178 bins.
179 Last distributed bin stores blocks with size near min_allocation_unit
180 bytes.
181
182 For example:
183 query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 = 100,
184 min_allocation_unit = 17,
185 QUERY_CACHE_MEM_BIN_STEP_PWR2 = 1,
186 QUERY_CACHE_MEM_BIN_PARTS_INC = 1,
187 QUERY_CACHE_MEM_BIN_PARTS_MUL = 1
188 (in followed picture showed right (low) bound of bin):
189
190 | 100>>1 50>>1 |25>>1|
191 | | | | | |
192 | 100 75 50 41 33 25 21 18 15| 12 | - bins right (low) bounds
193
194 |\---/\-----/\--------/\--------|---/ |
195 | 0 1 2 3 | | - steps
196 \-----------------------------/ \---/
197 bins that we store in cache this bin showed for example only
198
199
200 Calculation of steps/bins distribution is performed only when query cache
201 is resized.
202
203 When we need to find appropriate bin, first we should find appropriate
204 step, then we should calculate number of bins that are using data
205 stored in Query_cache_memory_bin_step structure.
206
207 Free memory blocks are sorted in bins in lists with size-ascending order
208 (more small blocks needed frequently then bigger one).
209
210 7. Packing cache.
211
212 Query cache packing is divided into two operation:
213 - pack_cache
214 - join_results
215
216 pack_cache moved all blocks to "top" of cache and create one block of free
217 space at the "bottom":
218
219 before pack_cache after pack_cache
220 +-------------+ +-------------+
221 | query 1 | | query 1 |
222 +-------------+ +-------------+
223 | table 1 | | table 1 |
224 +-------------+ +-------------+
225 | results 1.1 | | results 1.1 |
226 +-------------+ +-------------+
227 | free | | query 2 |
228 +-------------+ +-------------+
229 | query 2 | | table 2 |
230 +-------------+ ---> +-------------+
231 | table 2 | | results 1.2 |
232 +-------------+ +-------------+
233 | results 1.2 | | results 2 |
234 +-------------+ +-------------+
235 | free | | free |
236 +-------------+ | |
237 | results 2 | | |
238 +-------------+ | |
239 | free | | |
240 +-------------+ +-------------+
241
242 pack_cache scan blocks in physical address order and move every non-free
243 block "higher".
244
245 pack_cach remove every free block it finds. The length of the deleted block
246 is accumulated to the "gap". All non free blocks should be shifted with the
247 "gap" step.
248
249 join_results scans all complete queries. If the results of query are not
250 stored in the same block, join_results tries to move results so, that they
251 are stored in one block.
252
253 before join_results after join_results
254 +-------------+ +-------------+
255 | query 1 | | query 1 |
256 +-------------+ +-------------+
257 | table 1 | | table 1 |
258 +-------------+ +-------------+
259 | results 1.1 | | free |
260 +-------------+ +-------------+
261 | query 2 | | query 2 |
262 +-------------+ +-------------+
263 | table 2 | | table 2 |
264 +-------------+ ---> +-------------+
265 | results 1.2 | | free |
266 +-------------+ +-------------+
267 | results 2 | | results 2 |
268 +-------------+ +-------------+
269 | free | | results 1 |
270 | | | |
271 | | +-------------+
272 | | | free |
273 | | | |
274 +-------------+ +-------------+
275
276 If join_results allocated new block(s) then we need call pack_cache again.
277
278 7. Interface
279 The query cache interfaces with the rest of the server code through 7
280 functions:
281 1. Query_cache::send_result_to_client
282 - Called before parsing and used to match a statement with the stored
283 queries hash.
284 If a match is found the cached result set is sent through repeated
285 calls to net_write_packet. (note: calling thread doesn't have a regis-
286 tered result set writer: thd->net.query_cache_query=0)
287 2. Query_cache::store_query
288 - Called just before handle_select() and is used to register a result
289 set writer to the statement currently being processed
290 (thd->net.query_cache_query).
291 3. query_cache_insert
292 - Called from net_write_packet to append a result set to a cached query
293 if (and only if) this query has a registered result set writer
294 (thd->net.query_cache_query).
295 4. Query_cache::invalidate
296 Query_cache::invalidate_locked_for_write
297 - Called from various places to invalidate query cache based on data-
298 base, table and myisam file name. During an on going invalidation
299 the query cache is temporarily disabled.
300 5. Query_cache::flush
301 - Used when a RESET QUERY CACHE is issued. This clears the entire
302 cache block by block.
303 6. Query_cache::resize
304 - Used to change the available memory used by the query cache. This
305 will also invalidate the entrie query cache in one free operation.
306 7. Query_cache::pack
307 - Used when a FLUSH QUERY CACHE is issued. This changes the order of
308 the used memory blocks in physical memory order and move all avail-
309 able memory to the 'bottom' of the memory.
310
311
312 TODO list:
313
314 - Delayed till after-parsing qache answer (for column rights processing)
315 - Optimize cache resizing
316 - if new_size < old_size then pack & shrink
317 - if new_size > old_size copy cached query to new cache
318 - Move MRG_MYISAM table type processing to handlers, something like:
319 tables_used->table->file->register_used_filenames(callback,
320 first_argument);
321 - QC improvement suggested by Monty:
322 - Add a counter in open_table() for how many MERGE (ISAM or MyISAM)
323 tables are cached in the table cache.
324 (This will be trivial when we have the new table cache in place I
325 have been working on)
326 - After this we can add the following test around the for loop in
327 is_cacheable::
328
329 if (thd->temp_tables || global_merge_table_count)
330
331 - Another option would be to set thd->lex->safe_to_cache_query to 0
332 in 'get_lock_data' if any of the tables was a tmp table or a
333 MRG_ISAM table.
334 (This could be done with almost no speed penalty)
335 */
336
337 #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
338 #include "sql_cache.h"
339 #include "sql_parse.h" // check_table_access
340 #include "tztime.h" // struct Time_zone
341 #include "auth_common.h" // SELECT_ACL
342 #include "sql_base.h" // TMP_TABLE_KEY_EXTRA
343 #include "debug_sync.h" // DEBUG_SYNC
344 #include "opt_trace.h"
345 #include "sql_table.h"
346 #include <m_ctype.h>
347 #include <my_dir.h>
348 #include <hash.h>
349 #include "../storage/myisammrg/ha_myisammrg.h"
350 #include "../storage/myisammrg/myrg_def.h"
351 #include "probes_mysql.h"
352 #include "transaction.h"
353
354 #include "query_strip_comments.h"
355
356 /*
357 Number of bytes to be allocated in a query cache buffer in addition to the
358 query string length.
359
360 The query buffer layout is:
361
362 buffer :==
363 <statement> The input statement(s)
364 '\0' Terminating null char
365 <db_length> Length of following current database name (size_t)
366 <db_name> Name of current database
367 <flags> Flags struct
368 */
369 #define QUERY_BUFFER_ADDITIONAL_LENGTH(db_length) \
370 (1 + sizeof(size_t) + db_length + QUERY_CACHE_FLAGS_SIZE)
371
QueryStripComments()372 QueryStripComments::QueryStripComments()
373 {
374 buffer = 0;
375 length = 0;
376 buffer_length = 0;
377 }
~QueryStripComments()378 QueryStripComments::~QueryStripComments()
379 {
380 cleanup();
381 }
382
query_strip_comments_is_white_space(char c)383 inline bool query_strip_comments_is_white_space(char c)
384 {
385 return ((' ' == c) || ('\t' == c) || ('\r' == c) || ('\n' ==c ));
386 }
set(LEX_CSTRING query,uint additional_length)387 void QueryStripComments::set(LEX_CSTRING query, uint additional_length)
388 {
389 uint new_buffer_length = query.length + additional_length;
390 if(new_buffer_length > buffer_length)
391 {
392 cleanup();
393 buffer= (char*)my_malloc(key_memory_Query_cache, new_buffer_length,
394 MYF(0));
395 }
396 uint query_position = 0;
397 uint position = 0;
398 // Skip whitespaces from begin
399 while ((query_position < query.length)
400 && query_strip_comments_is_white_space(query.str[query_position]))
401 {
402 ++query_position;
403 }
404 long int last_space = -1;
405 while (query_position < query.length)
406 {
407 char current = query.str[query_position];
408 bool insert_space = false; // insert space to buffer, (IMPORTANT) don't update query_position
409 switch(current)
410 {
411 case '\'':
412 case '"':
413 {
414 buffer[position++] = query.str[query_position++]; // copy current symbol
415 while(query_position < query.length)
416 {
417 if(current == query.str[query_position]) // found pair quote
418 {
419 break;
420 }
421 buffer[position++] = query.str[query_position++]; // copy current symbol
422 }
423 break;
424 }
425 case '/':
426 {
427 if(((query_position + 2) < query.length)
428 && ('*' == query.str[query_position+1])
429 && ('!' != query.str[query_position+2]))
430 {
431 query_position += 2; // skip "/*"
432 do
433 {
434 if('*' == query.str[query_position]
435 && '/' == query.str[query_position+1]) // check for "*/"
436 {
437 query_position += 2; // skip "*/"
438 insert_space = true;
439 break;
440 }
441 else
442 {
443 ++query_position;
444 }
445 }
446 while(query_position < query.length);
447 if(!insert_space)
448 {
449 continue;
450 }
451 }
452 break;
453 }
454 case '-':
455 {
456 if(query.str[query_position+1] == '-')
457 {
458 ++query_position; // skip "-", and go to search of "\n"
459 }
460 else
461 {
462 break;
463 }
464 }
465 // fallthrough
466 case '#':
467 {
468 do
469 {
470 ++query_position; // skip current symbol (# or -)
471 if('\n' == query.str[query_position]) // check for '\n'
472 {
473 ++query_position; // skip '\n'
474 insert_space = true;
475 break;
476 }
477 }
478 while(query_position < query.length);
479 if(insert_space)
480 {
481 break;
482 }
483 else
484 {
485 continue;
486 }
487 }
488 default:
489 if(query_strip_comments_is_white_space(current))
490 {
491 insert_space = true;
492 ++query_position;
493 }
494 break; // make gcc happy
495 }
496 if(insert_space)
497 {
498 if((uint) (last_space + 1) != position)
499 {
500 last_space = position;
501 buffer[position++] = ' ';
502 }
503 }
504 else if (query_position < query.length)
505 {
506 buffer[position++] = query.str[query_position++];
507 }
508 }
509 while((0 < position) && query_strip_comments_is_white_space(buffer[position - 1]))
510 {
511 --position;
512 }
513 buffer[position] = 0;
514 length = position;
515 }
cleanup()516 void QueryStripComments::cleanup()
517 {
518 if(buffer)
519 {
520 my_free(buffer);
521 }
522 buffer = 0;
523 length = 0;
524 buffer_length = 0;
525 }
526
527 class QueryStripComments_Backup
528 {
529 public:
530 QueryStripComments_Backup(THD* a_thd, QueryStripComments* qsc);
531 ~QueryStripComments_Backup();
532 private:
533 THD* thd;
534 LEX_CSTRING query;
535 };
536
QueryStripComments_Backup(THD * a_thd,QueryStripComments * qsc)537 QueryStripComments_Backup::QueryStripComments_Backup(THD* a_thd,
538 QueryStripComments* qsc)
539 {
540 if(opt_query_cache_strip_comments)
541 {
542 thd = a_thd;
543 query = thd->query();
544 qsc->set(query, QUERY_BUFFER_ADDITIONAL_LENGTH(thd->db().length));
545 *(size_t *) (qsc->query() + qsc->query_length() + 1)= thd->db().length;
546 thd->set_query(qsc->query(),qsc->query_length());
547 }
548 else
549 {
550 thd = 0;
551 query.str = NULL;
552 query.length = 0;
553 }
554 }
~QueryStripComments_Backup()555 QueryStripComments_Backup::~QueryStripComments_Backup()
556 {
557 if(thd)
558 {
559 thd->set_query(query);
560 }
561 }
562
563 #ifdef EMBEDDED_LIBRARY
564 #include "emb_qcache.h"
565 #endif
566
567 using std::min;
568 using std::max;
569
570 #if defined(EXTRA_DEBUG) && !defined(NDEBUG)
571 #define RW_WLOCK(M) {DBUG_PRINT("lock", ("rwlock wlock 0x%lx",(ulong)(M))); \
572 if (!mysql_rwlock_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \
573 else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); }
574 #define RW_RLOCK(M) {DBUG_PRINT("lock", ("rwlock rlock 0x%lx", (ulong)(M))); \
575 if (!mysql_rwlock_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \
576 else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); }
577 #define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \
578 if (!mysql_rwlock_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \
579 else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); }
580 #define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
581 __LINE__,(ulong)(B))); \
582 B->query()->lock_writing();}
583 #define BLOCK_LOCK_RD(B) {DBUG_PRINT("lock", ("%d LOCK_RD 0x%lx",\
584 __LINE__,(ulong)(B))); \
585 B->query()->lock_reading();}
586 #define BLOCK_UNLOCK_WR(B) { \
587 DBUG_PRINT("lock", ("%d UNLOCK_WR 0x%lx",\
588 __LINE__,(ulong)(B)));B->query()->unlock_writing();}
589 #define BLOCK_UNLOCK_RD(B) { \
590 DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\
591 __LINE__,(ulong)(B)));B->query()->unlock_reading();}
592 #define DUMP(C) DBUG_EXECUTE("qcache", {\
593 (C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
594 #else
595 #define RW_WLOCK(M) mysql_rwlock_wrlock(M)
596 #define RW_RLOCK(M) mysql_rwlock_rdlock(M)
597 #define RW_UNLOCK(M) mysql_rwlock_unlock(M)
598 #define BLOCK_LOCK_WR(B) B->query()->lock_writing()
599 #define BLOCK_LOCK_RD(B) B->query()->lock_reading()
600 #define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
601 #define BLOCK_UNLOCK_RD(B) B->query()->unlock_reading()
602 #define DUMP(C)
603 #endif
604
605
606 /**
607 Macro that executes the requested action at a synchronization point
608 only if the thread has a associated THD session.
609 */
610 #if defined(ENABLED_DEBUG_SYNC)
611 #define QC_DEBUG_SYNC(name) \
612 do { \
613 THD *thd= current_thd; \
614 if (thd) \
615 DEBUG_SYNC(thd, name); \
616 } while (0)
617 #else
618 #define QC_DEBUG_SYNC(name)
619 #endif
620
621 // Max aligned size for ulong type query_cache_min_res_unit.
622 static const ulong max_aligned_min_res_unit_size= ((ULONG_MAX) &
623 (~(sizeof(double) - 1)));
624
625 /**
626 Thread state to be used when the query cache lock needs to be acquired.
627 Sets the thread state name in the constructor, resets on destructor.
628 */
629
630 struct Query_cache_wait_state
631 {
632 THD *m_thd;
633 PSI_stage_info m_old_stage;
634 const char *m_func;
635 const char *m_file;
636 int m_line;
637
Query_cache_wait_stateQuery_cache_wait_state638 Query_cache_wait_state(THD *thd, const char *func,
639 const char *file, unsigned int line)
640 : m_thd(thd),
641 m_old_stage(),
642 m_func(func), m_file(file), m_line(line)
643 {
644 if (m_thd)
645 m_thd->enter_stage(&stage_waiting_for_query_cache_lock,
646 &m_old_stage,
647 m_func, m_file, m_line);
648 }
649
~Query_cache_wait_stateQuery_cache_wait_state650 ~Query_cache_wait_state()
651 {
652 if (m_thd)
653 m_thd->enter_stage(&m_old_stage, NULL, m_func, m_file, m_line);
654 }
655 };
656
657
658 /**
659 Construct the key used for cache lookup.
660 The key is query + NULL + current DB (if any) + cache flags
661 The key is allocated on THD's mem_root.
662
663 @param thd Thread context
664 @param query Query string
665 @param flags Cache query flags
666 @param tot_length[out] Length of the key
667
668 @return The constructed cache key or NULL if OOM
669 */
670
make_cache_key(THD * thd,const LEX_CSTRING & query,Query_cache_query_flags * flags,size_t * tot_length)671 static char *make_cache_key(THD *thd,
672 const LEX_CSTRING &query,
673 Query_cache_query_flags *flags,
674 size_t *tot_length)
675 {
676 *tot_length= query.length + 1 + thd->db().length + QUERY_CACHE_FLAGS_SIZE;
677 char *cache_key= static_cast<char*>(thd->alloc(*tot_length));
678 if (cache_key == NULL)
679 return NULL;
680
681 memcpy(cache_key, query.str, query.length);
682 cache_key[query.length]= '\0';
683 if (thd->db().length)
684 memcpy(cache_key + query.length + 1, thd->db().str, thd->db().length);
685
686 /*
687 We should only copy structure (don't use it location directly)
688 because of alignment issue
689 */
690 memcpy((void*) (cache_key + (*tot_length - QUERY_CACHE_FLAGS_SIZE)),
691 flags, QUERY_CACHE_FLAGS_SIZE);
692 return cache_key;
693 }
694
695
696 /**
697 Serialize access to the query cache.
698 If the lock cannot be granted the thread hangs in a conditional wait which
699 is signalled on each unlock.
700
701 The lock attempt will also fail without wait if lock_and_suspend() is in
702 effect by another thread. This enables a quick path in execution to skip waits
703 when the outcome is known.
704
705 @param use_timeout TRUE if the lock can abort because of a timeout.
706
707 @note use_timeout is optional and default value is FALSE.
708
709 @return
710 @retval FALSE An exclusive lock was taken
711 @retval TRUE The locking attempt failed
712 */
713
try_lock(bool use_timeout)714 bool Query_cache::try_lock(bool use_timeout)
715 {
716 bool interrupt= FALSE;
717 THD *thd= current_thd;
718 Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
719 DBUG_ENTER("Query_cache::try_lock");
720
721 const char* old_proc_info= thd->proc_info;
722 thd_proc_info(thd,"Waiting on query cache mutex");
723 DEBUG_SYNC(thd, "before_query_cache_mutex");
724 mysql_mutex_lock(&structure_guard_mutex);
725 DEBUG_SYNC(thd, "after_query_cache_mutex");
726 thd->proc_info = old_proc_info;
727 while (1)
728 {
729 if (m_cache_lock_status == Query_cache::UNLOCKED)
730 {
731 m_cache_lock_status= Query_cache::LOCKED;
732 #ifndef NDEBUG
733 if (thd)
734 m_cache_lock_thread_id= thd->thread_id();
735 #endif
736 break;
737 }
738 else if (m_cache_lock_status == Query_cache::LOCKED_NO_WAIT)
739 {
740 /*
741 If query cache is protected by a LOCKED_NO_WAIT lock this thread
742 should avoid using the query cache as it is being evicted.
743 */
744 interrupt= TRUE;
745 break;
746 }
747 else
748 {
749 assert(m_cache_lock_status == Query_cache::LOCKED);
750 /*
751 To prevent send_result_to_client() and query_cache_insert() from
752 blocking execution for too long a timeout is put on the lock.
753 */
754 if (use_timeout)
755 {
756 struct timespec waittime;
757 set_timespec_nsec(&waittime, 50000000UL); /* Wait for 50 msec */
758 int res= mysql_cond_timedwait(&COND_cache_status_changed,
759 &structure_guard_mutex, &waittime);
760 if (res == ETIMEDOUT)
761 {
762 interrupt= TRUE;
763 break;
764 }
765 }
766 else
767 {
768 mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
769 }
770 }
771 }
772 mysql_mutex_unlock(&structure_guard_mutex);
773
774 DBUG_RETURN(interrupt);
775 }
776
777
778 /**
779 Serialize access to the query cache.
780 If the lock cannot be granted the thread hangs in a conditional wait which
781 is signalled on each unlock.
782
783 This method also suspends the query cache so that other threads attempting to
784 lock the cache with try_lock() will fail directly without waiting.
785
786 It is used by all methods which flushes or destroys the whole cache.
787 */
788
lock_and_suspend(void)789 void Query_cache::lock_and_suspend(void)
790 {
791 THD *thd= current_thd;
792 Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
793 DBUG_ENTER("Query_cache::lock_and_suspend");
794
795 mysql_mutex_lock(&structure_guard_mutex);
796 while (m_cache_lock_status != Query_cache::UNLOCKED)
797 mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
798 m_cache_lock_status= Query_cache::LOCKED_NO_WAIT;
799 #ifndef NDEBUG
800 if (thd)
801 m_cache_lock_thread_id= thd->thread_id();
802 #endif
803 /* Wake up everybody, a whole cache flush is starting! */
804 mysql_cond_broadcast(&COND_cache_status_changed);
805 mysql_mutex_unlock(&structure_guard_mutex);
806
807 DBUG_VOID_RETURN;
808 }
809
810 /**
811 Serialize access to the query cache.
812 If the lock cannot be granted the thread hangs in a conditional wait which
813 is signalled on each unlock.
814
815 It is used by all methods which invalidates one or more tables.
816 */
817
lock(void)818 void Query_cache::lock(void)
819 {
820 THD *thd= current_thd;
821 Query_cache_wait_state wait_state(thd, __func__, __FILE__, __LINE__);
822 DBUG_ENTER("Query_cache::lock");
823
824 mysql_mutex_lock(&structure_guard_mutex);
825 while (m_cache_lock_status != Query_cache::UNLOCKED)
826 mysql_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
827 m_cache_lock_status= Query_cache::LOCKED;
828 #ifndef NDEBUG
829 if (thd)
830 m_cache_lock_thread_id= thd->thread_id();
831 #endif
832 mysql_mutex_unlock(&structure_guard_mutex);
833
834 DBUG_VOID_RETURN;
835 }
836
837
838 /**
839 Set the query cache to UNLOCKED and signal waiting threads.
840 */
841
unlock(void)842 void Query_cache::unlock(void)
843 {
844 DBUG_ENTER("Query_cache::unlock");
845 mysql_mutex_lock(&structure_guard_mutex);
846 #ifndef NDEBUG
847 THD *thd= current_thd;
848 if (thd)
849 assert(m_cache_lock_thread_id == thd->thread_id());
850 #endif
851 assert(m_cache_lock_status == Query_cache::LOCKED ||
852 m_cache_lock_status == Query_cache::LOCKED_NO_WAIT);
853 m_cache_lock_status= Query_cache::UNLOCKED;
854 DBUG_PRINT("Query_cache",("Sending signal"));
855 mysql_cond_signal(&COND_cache_status_changed);
856 mysql_mutex_unlock(&structure_guard_mutex);
857 DBUG_VOID_RETURN;
858 }
859
860
861 /**
862 Helper function for determine if a SELECT statement has a SQL_NO_CACHE
863 directive.
864
865 @param sql Query string
866 @param offset Offset of the first whitespace character after SELECT
867 @param query_length The total length of the query string
868
869 @return
870 @retval TRUE The character string contains SQL_NO_CACHE
871 @retval FALSE No directive found.
872 */
873
has_no_cache_directive(const char * sql,uint offset,size_t query_length)874 static bool has_no_cache_directive(const char *sql, uint offset,
875 size_t query_length)
876 {
877 uint i= offset;
878
879 // Must have at least one whitespace char before SQL_NO_CACHE
880 if (!my_isspace(system_charset_info, sql[i]))
881 return false;
882
883 // But can have several
884 while (i < query_length &&
885 my_isspace(system_charset_info, sql[i]))
886 ++i;
887
888 // Check that we have enough chars left for SQL_NO_CACHE
889 if (i + 12 >= query_length)
890 return false;
891
892 if (my_toupper(system_charset_info, sql[i]) == 'S' &&
893 my_toupper(system_charset_info, sql[i+1]) == 'Q' &&
894 my_toupper(system_charset_info, sql[i+2]) == 'L' &&
895 my_toupper(system_charset_info, sql[i+3]) == '_' &&
896 my_toupper(system_charset_info, sql[i+4]) == 'N' &&
897 my_toupper(system_charset_info, sql[i+5]) == 'O' &&
898 my_toupper(system_charset_info, sql[i+6]) == '_' &&
899 my_toupper(system_charset_info, sql[i+7]) == 'C' &&
900 my_toupper(system_charset_info, sql[i+8]) == 'A' &&
901 my_toupper(system_charset_info, sql[i+9]) == 'C' &&
902 my_toupper(system_charset_info, sql[i+10]) == 'H' &&
903 my_toupper(system_charset_info, sql[i+11]) == 'E' &&
904 my_isspace(system_charset_info, sql[i+12]))
905 return true;
906
907 return false;
908 }
909
910
911 /*****************************************************************************
912 Query_cache_block_table method(s)
913 *****************************************************************************/
914
block()915 inline Query_cache_block * Query_cache_block_table::block()
916 {
917 return (Query_cache_block *)(((uchar*)this) -
918 ALIGN_SIZE(sizeof(Query_cache_block_table)*n) -
919 ALIGN_SIZE(sizeof(Query_cache_block)));
920 }
921
922 /*****************************************************************************
923 Query_cache_block method(s)
924 *****************************************************************************/
925
init(ulong block_length)926 void Query_cache_block::init(ulong block_length)
927 {
928 DBUG_ENTER("Query_cache_block::init");
929 DBUG_PRINT("qcache", ("init block: 0x%lx length: %lu", (ulong) this,
930 block_length));
931 length = block_length;
932 used = 0;
933 type = Query_cache_block::FREE;
934 n_tables = 0;
935 DBUG_VOID_RETURN;
936 }
937
destroy()938 void Query_cache_block::destroy()
939 {
940 DBUG_ENTER("Query_cache_block::destroy");
941 DBUG_PRINT("qcache", ("destroy block 0x%lx, type %d",
942 (ulong) this, type));
943 type = INCOMPLETE;
944 DBUG_VOID_RETURN;
945 }
946
headers_len()947 inline uint Query_cache_block::headers_len()
948 {
949 return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
950 ALIGN_SIZE(sizeof(Query_cache_block)));
951 }
952
data(void)953 inline uchar* Query_cache_block::data(void)
954 {
955 return (uchar*)( ((uchar*)this) + headers_len() );
956 }
957
query()958 inline Query_cache_query * Query_cache_block::query()
959 {
960 #ifndef NDEBUG
961 if (type != QUERY)
962 query_cache.wreck(__LINE__, "incorrect block type");
963 #endif
964 return (Query_cache_query *) data();
965 }
966
table()967 inline Query_cache_table * Query_cache_block::table()
968 {
969 #ifndef NDEBUG
970 if (type != TABLE)
971 query_cache.wreck(__LINE__, "incorrect block type");
972 #endif
973 return (Query_cache_table *) data();
974 }
975
result()976 inline Query_cache_result * Query_cache_block::result()
977 {
978 #ifndef NDEBUG
979 if (type != RESULT && type != RES_CONT && type != RES_BEG &&
980 type != RES_INCOMPLETE)
981 query_cache.wreck(__LINE__, "incorrect block type");
982 #endif
983 return (Query_cache_result *) data();
984 }
985
table(TABLE_COUNTER_TYPE n)986 inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
987 {
988 return ((Query_cache_block_table *)
989 (((uchar*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
990 n*sizeof(Query_cache_block_table)));
991 }
992
993
994 /*****************************************************************************
995 * Query_cache_table method(s)
996 *****************************************************************************/
997
998 extern "C"
999 {
query_cache_table_get_key(const uchar * record,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))1000 uchar *query_cache_table_get_key(const uchar *record, size_t *length,
1001 my_bool not_used MY_ATTRIBUTE((unused)))
1002 {
1003 Query_cache_block* table_block = (Query_cache_block*) record;
1004 *length = (table_block->used - table_block->headers_len() -
1005 ALIGN_SIZE(sizeof(Query_cache_table)));
1006 return (table_block->data() +
1007 ALIGN_SIZE(sizeof(Query_cache_table)));
1008 }
1009 }
1010
1011 /*****************************************************************************
1012 Query_cache_query methods
1013 *****************************************************************************/
1014
1015 /*
1016 Following methods work for block read/write locking only in this
1017 particular case and in interaction with structure_guard_mutex.
1018
1019 Lock for write prevents any other locking. (exclusive use)
1020 Lock for read prevents only locking for write.
1021 */
1022
lock_writing()1023 inline void Query_cache_query::lock_writing()
1024 {
1025 RW_WLOCK(&lock);
1026 }
1027
1028
1029 /*
1030 Needed for finding queries, that we may delete from cache.
1031 We don't want to wait while block become unlocked. In addition,
1032 block locking means that query is now used and we don't need to
1033 remove it.
1034 */
1035
try_lock_writing()1036 my_bool Query_cache_query::try_lock_writing()
1037 {
1038 DBUG_ENTER("Query_cache_block::try_lock_writing");
1039 if (mysql_rwlock_trywrlock(&lock) != 0)
1040 {
1041 DBUG_PRINT("info", ("can't lock rwlock"));
1042 DBUG_RETURN(0);
1043 }
1044 DBUG_PRINT("info", ("rwlock 0x%lx locked", (ulong) &lock));
1045 DBUG_RETURN(1);
1046 }
1047
1048
lock_reading()1049 inline void Query_cache_query::lock_reading()
1050 {
1051 RW_RLOCK(&lock);
1052 }
1053
1054
unlock_writing()1055 inline void Query_cache_query::unlock_writing()
1056 {
1057 RW_UNLOCK(&lock);
1058 }
1059
1060
unlock_reading()1061 inline void Query_cache_query::unlock_reading()
1062 {
1063 RW_UNLOCK(&lock);
1064 }
1065
1066
init_n_lock()1067 void Query_cache_query::init_n_lock()
1068 {
1069 DBUG_ENTER("Query_cache_query::init_n_lock");
1070 res=0; wri = 0; len = 0;
1071 mysql_rwlock_init(key_rwlock_query_cache_query_lock, &lock);
1072 lock_writing();
1073 DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
1074 (long) (((uchar*) this) -
1075 ALIGN_SIZE(sizeof(Query_cache_block)))));
1076 DBUG_VOID_RETURN;
1077 }
1078
1079
unlock_n_destroy()1080 void Query_cache_query::unlock_n_destroy()
1081 {
1082 DBUG_ENTER("Query_cache_query::unlock_n_destroy");
1083 DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
1084 (long) (((uchar*) this) -
1085 ALIGN_SIZE(sizeof(Query_cache_block)))));
1086 /*
1087 The following call is not needed on system where one can destroy an
1088 active semaphore
1089 */
1090 this->unlock_writing();
1091 mysql_rwlock_destroy(&lock);
1092 DBUG_VOID_RETURN;
1093 }
1094
1095
1096 extern "C"
1097 {
query_cache_query_get_key(const uchar * record,size_t * length,my_bool not_used)1098 uchar *query_cache_query_get_key(const uchar *record, size_t *length,
1099 my_bool not_used)
1100 {
1101 Query_cache_block *query_block = (Query_cache_block*) record;
1102 *length = (query_block->used - query_block->headers_len() -
1103 ALIGN_SIZE(sizeof(Query_cache_query)));
1104 return (query_block->data() +
1105 ALIGN_SIZE(sizeof(Query_cache_query)));
1106 }
1107 }
1108
1109 /*****************************************************************************
1110 Functions to store things into the query cache
1111 *****************************************************************************/
1112
1113 /*
1114 Note on double-check locking (DCL) usage.
1115
1116 Below, in query_cache_insert(), query_cache_abort() and
1117 Query_cache::end_of_result() we use what is called double-check
1118 locking (DCL) for Query_cache_tls::first_query_block.
1119 I.e. we test it first without a lock, and, if positive, test again
1120 under the lock.
1121
1122 This means that if we see 'first_query_block == 0' without a
1123 lock we will skip the operation. But this is safe here: when we
1124 started to cache a query, we called Query_cache::store_query(), and
1125 'first_query_block' was set to non-zero in this thread (and the
1126 thread always sees results of its memory operations, mutex or not).
1127 If later we see 'first_query_block == 0' without locking a
1128 mutex, that may only mean that some other thread have reset it by
1129 invalidating the query. Skipping the operation in this case is the
1130 right thing to do, as first_query_block won't get non-zero for
1131 this query again.
1132
1133 See also comments in Query_cache::store_query() and
1134 Query_cache::send_result_to_client().
1135
1136 NOTE, however, that double-check locking is not applicable in
1137 'invalidate' functions, as we may erroneously skip invalidation,
1138 because the thread doing invalidation may never see non-zero
1139 'first_query_block'.
1140 */
1141
1142
1143 /**
1144 libmysql convenience wrapper to insert data into query cache.
1145 */
query_cache_insert(const char * packet,ulong length,unsigned pkt_nr)1146 void query_cache_insert(const char *packet, ulong length,
1147 unsigned pkt_nr)
1148 {
1149 THD *thd= current_thd;
1150
1151 /*
1152 Current_thd can be NULL when a new connection is immediately ended
1153 due to "Too many connections". thd->store_globals() has not been
1154 called at this time and hence my_thread_setspecific_ptr(THR_THD,
1155 this) has not been called for this thread.
1156 */
1157
1158 if (!thd)
1159 return;
1160
1161 query_cache.insert(&thd->query_cache_tls,
1162 packet, length,
1163 pkt_nr);
1164 }
1165
1166
1167 /**
1168 Insert the packet into the query cache.
1169 */
1170
1171 void
insert(Query_cache_tls * query_cache_tls,const char * packet,ulong length,unsigned pkt_nr)1172 Query_cache::insert(Query_cache_tls *query_cache_tls,
1173 const char *packet, ulong length,
1174 unsigned pkt_nr)
1175 {
1176 DBUG_ENTER("Query_cache::insert");
1177
1178 /* See the comment on double-check locking usage above. */
1179 if (is_disabled() || query_cache_tls->first_query_block == NULL)
1180 DBUG_VOID_RETURN;
1181
1182 QC_DEBUG_SYNC("wait_in_query_cache_insert");
1183
1184 if (try_lock())
1185 DBUG_VOID_RETURN;
1186
1187 Query_cache_block *query_block = query_cache_tls->first_query_block;
1188 if (query_block == NULL)
1189 {
1190 /*
1191 We lost the writer and the currently processed query has been
1192 invalidated; there is nothing left to do.
1193 */
1194 unlock();
1195 DBUG_VOID_RETURN;
1196 }
1197 BLOCK_LOCK_WR(query_block);
1198 Query_cache_query *header= query_block->query();
1199 Query_cache_block *result= header->result();
1200
1201 DUMP(this);
1202 DBUG_PRINT("qcache", ("insert packet %lu bytes long",length));
1203
1204 /*
1205 On success, STRUCT_UNLOCK is done by append_result_data. Otherwise, we
1206 still need structure_guard_mutex to free the query, and therefore unlock
1207 it later in this function.
1208 */
1209 if (!append_result_data(&result, length, (uchar*) packet,
1210 query_block))
1211 {
1212 DBUG_PRINT("warning", ("Can't append data"));
1213 header->result(result);
1214 DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block));
1215 // The following call will remove the lock on query_block
1216 query_cache.free_query(query_block);
1217 query_cache.refused++;
1218 // append_result_data no success => we need unlock
1219 unlock();
1220 DBUG_VOID_RETURN;
1221 }
1222
1223 header->result(result);
1224 header->last_pkt_nr= pkt_nr;
1225 BLOCK_UNLOCK_WR(query_block);
1226
1227 DBUG_EXECUTE("check_querycache", check_integrity(LOCK_WHILE_CHECKING););
1228
1229 DBUG_VOID_RETURN;
1230 }
1231
1232
1233 void
abort(Query_cache_tls * query_cache_tls)1234 Query_cache::abort(Query_cache_tls *query_cache_tls)
1235 {
1236 DBUG_ENTER("query_cache_abort");
1237 THD *thd= current_thd;
1238
1239 /* See the comment on double-check locking usage above. */
1240 if (is_disabled() || query_cache_tls->first_query_block == NULL)
1241 DBUG_VOID_RETURN;
1242
1243 if (try_lock())
1244 DBUG_VOID_RETURN;
1245
1246 /*
1247 While we were waiting another thread might have changed the status
1248 of the writer. Make sure the writer still exists before continue.
1249 */
1250 Query_cache_block *query_block= query_cache_tls->first_query_block;
1251 if (query_block)
1252 {
1253 THD_STAGE_INFO(thd, stage_storing_result_in_query_cache);
1254 DUMP(this);
1255 BLOCK_LOCK_WR(query_block);
1256 // The following call will remove the lock on query_block
1257 free_query(query_block);
1258 query_cache_tls->first_query_block= NULL;
1259 DBUG_EXECUTE("check_querycache", check_integrity(CALLER_HOLDS_LOCK););
1260 }
1261
1262 unlock();
1263
1264 DBUG_VOID_RETURN;
1265 }
1266
1267
end_of_result(THD * thd)1268 void Query_cache::end_of_result(THD *thd)
1269 {
1270 Query_cache_block *query_block;
1271 Query_cache_tls *query_cache_tls= &thd->query_cache_tls;
1272 ulonglong current_found_rows= thd->current_found_rows;
1273 DBUG_ENTER("Query_cache::end_of_result");
1274
1275 /* See the comment on double-check locking usage above. */
1276 if (query_cache_tls->first_query_block == NULL)
1277 DBUG_VOID_RETURN;
1278
1279 if (thd->killed || thd->is_error())
1280 {
1281 abort(&thd->query_cache_tls);
1282 DBUG_VOID_RETURN;
1283 }
1284
1285 /* Ensure that only complete results are cached. */
1286 assert(thd->get_stmt_da()->is_eof());
1287
1288 #ifdef EMBEDDED_LIBRARY
1289 insert(query_cache_tls, (char*)thd,
1290 emb_count_querycache_size(thd), 0);
1291 #endif
1292
1293 if (try_lock())
1294 DBUG_VOID_RETURN;
1295
1296 query_block= query_cache_tls->first_query_block;
1297 if (query_block)
1298 {
1299 /*
1300 The writer is still present; finish last result block by chopping it to
1301 suitable size if needed and setting block type. Since this is the last
1302 block, the writer should be dropped.
1303 */
1304 THD_STAGE_INFO(thd, stage_storing_result_in_query_cache);
1305 DUMP(this);
1306 BLOCK_LOCK_WR(query_block);
1307 Query_cache_query *header= query_block->query();
1308 Query_cache_block *last_result_block;
1309 ulong allign_size;
1310 ulong len;
1311
1312 if (header->result() == 0)
1313 {
1314 DBUG_PRINT("error", ("End of data with no result blocks; "
1315 "Query '%s' removed from cache.", header->query()));
1316 /*
1317 Extra safety: empty result should not happen in the normal call
1318 to this function. In the release version that query should be ignored
1319 and removed from QC.
1320 */
1321 assert(0);
1322 free_query(query_block);
1323 unlock();
1324 DBUG_VOID_RETURN;
1325 }
1326 last_result_block= header->result()->prev;
1327 allign_size= ALIGN_SIZE(last_result_block->used);
1328 len= max(query_cache.min_allocation_unit, allign_size);
1329 if (last_result_block->length >= query_cache.min_allocation_unit + len)
1330 query_cache.split_block(last_result_block,len);
1331
1332 header->found_rows(current_found_rows);
1333 header->result()->type= Query_cache_block::RESULT;
1334
1335 /* Drop the writer. */
1336 header->writer(0);
1337 query_cache_tls->first_query_block= NULL;
1338 BLOCK_UNLOCK_WR(query_block);
1339 DBUG_EXECUTE("check_querycache", check_integrity(CALLER_HOLDS_LOCK););
1340 }
1341
1342 unlock();
1343 DBUG_VOID_RETURN;
1344 }
1345
query_cache_invalidate_by_MyISAM_filename(const char * filename)1346 void query_cache_invalidate_by_MyISAM_filename(const char *filename)
1347 {
1348 query_cache.invalidate_by_MyISAM_filename(filename);
1349 }
1350
1351
1352 /**
1353 This is a convenience function used by the innodb plugin.
1354 */
1355 extern "C"
mysql_query_cache_invalidate4(THD * thd,const char * key,unsigned key_length,int using_trx)1356 void mysql_query_cache_invalidate4(THD *thd,
1357 const char *key, unsigned key_length,
1358 int using_trx)
1359 {
1360 char qcache_key_name[2 * (NAME_LEN + 1)];
1361 char db_name[NAME_CHAR_LEN * FILENAME_CHARSET_MBMAXLEN + 1];
1362 const char *key_ptr;
1363 size_t tabname_len, dbname_len;
1364
1365 // Extract the database name.
1366 key_ptr= strchr(key, '/');
1367 memcpy(db_name, key, (key_ptr - key));
1368 db_name[(key_ptr - key)]= '\0';
1369
1370 /*
1371 Construct the key("db@002dname\0table@0024name\0") in a canonical format for
1372 the query cache using the key("db-name\0table$name\0") which is
1373 in its non-canonical form.
1374 */
1375 dbname_len= filename_to_tablename(db_name, qcache_key_name,
1376 sizeof(qcache_key_name));
1377 tabname_len= filename_to_tablename(++key_ptr,
1378 (qcache_key_name + dbname_len + 1),
1379 sizeof(qcache_key_name) - dbname_len - 1);
1380
1381 query_cache.invalidate(thd, qcache_key_name, (dbname_len + tabname_len + 2),
1382 (my_bool) using_trx);
1383 }
1384
1385
1386 /*****************************************************************************
1387 Query_cache methods
1388 *****************************************************************************/
1389
Query_cache(ulong query_cache_limit_arg,ulong min_allocation_unit_arg,ulong min_result_data_size_arg,uint def_query_hash_size_arg,uint def_table_hash_size_arg)1390 Query_cache::Query_cache(ulong query_cache_limit_arg,
1391 ulong min_allocation_unit_arg,
1392 ulong min_result_data_size_arg,
1393 uint def_query_hash_size_arg,
1394 uint def_table_hash_size_arg)
1395 :query_cache_size(0),
1396 query_cache_limit(query_cache_limit_arg),
1397 queries_in_cache(0), hits(0), inserts(0), refused(0),
1398 total_blocks(0), lowmem_prunes(0), m_query_cache_is_disabled(FALSE),
1399 min_allocation_unit(ALIGN_SIZE(min_allocation_unit_arg)),
1400 min_result_data_size(ALIGN_SIZE(min_result_data_size_arg)),
1401 def_query_hash_size(ALIGN_SIZE(def_query_hash_size_arg)),
1402 def_table_hash_size(ALIGN_SIZE(def_table_hash_size_arg)),
1403 initialized(0)
1404 {
1405 ulong min_needed= (ALIGN_SIZE(sizeof(Query_cache_block)) +
1406 ALIGN_SIZE(sizeof(Query_cache_block_table)) +
1407 ALIGN_SIZE(sizeof(Query_cache_query)) + 3);
1408 set_if_bigger(min_allocation_unit,min_needed);
1409 this->min_allocation_unit= ALIGN_SIZE(min_allocation_unit);
1410 set_if_bigger(this->min_result_data_size,min_allocation_unit);
1411 }
1412
1413
resize(ulong query_cache_size_arg)1414 ulong Query_cache::resize(ulong query_cache_size_arg)
1415 {
1416 ulong new_query_cache_size;
1417 DBUG_ENTER("Query_cache::resize");
1418 DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size,
1419 query_cache_size_arg));
1420 assert(initialized);
1421
1422 lock_and_suspend();
1423
1424 /*
1425 Wait for all readers and writers to exit. When the list of all queries
1426 is iterated over with a block level lock, we are done.
1427 */
1428 Query_cache_block *block= queries_blocks;
1429 if (block)
1430 {
1431 do
1432 {
1433 BLOCK_LOCK_WR(block);
1434 Query_cache_query *query= block->query();
1435 if (query->writer())
1436 {
1437 /*
1438 Drop the writer; this will cancel any attempts to store
1439 the processed statement associated with this writer.
1440 */
1441 query->writer()->first_query_block= NULL;
1442 query->writer(0);
1443 refused++;
1444 }
1445 query->unlock_n_destroy();
1446 block= block->next;
1447 } while (block != queries_blocks);
1448 }
1449 free_cache();
1450
1451 query_cache_size= query_cache_size_arg;
1452 new_query_cache_size= init_cache();
1453
1454 if (new_query_cache_size)
1455 DBUG_EXECUTE("check_querycache", check_integrity(CALLER_HOLDS_LOCK););
1456
1457 unlock();
1458 DBUG_RETURN(new_query_cache_size);
1459 }
1460
1461
set_min_res_unit(ulong size)1462 ulong Query_cache::set_min_res_unit(ulong size)
1463 {
1464 if (size < min_allocation_unit)
1465 size= min_allocation_unit;
1466 else if (size > max_aligned_min_res_unit_size)
1467 size= max_aligned_min_res_unit_size;
1468
1469 return (min_result_data_size= ALIGN_SIZE(size));
1470 }
1471
1472
store_query(THD * thd,TABLE_LIST * tables_used)1473 void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
1474 {
1475 TABLE_COUNTER_TYPE local_tables;
1476 DBUG_ENTER("Query_cache::store_query");
1477 /*
1478 Testing 'query_cache_size' without a lock here is safe: the thing
1479 we may loose is that the query won't be cached, but we save on
1480 mutex locking in the case when query cache is disabled or the
1481 query is uncachable.
1482
1483 See also a note on double-check locking usage above.
1484 */
1485 if (thd->locked_tables_mode || query_cache_size == 0)
1486 DBUG_VOID_RETURN;
1487
1488 /*
1489 Do not store queries while tracking transaction state.
1490 The tracker already flags queries that actually have
1491 transaction tracker items, but this will make behavior
1492 more straight forward.
1493 */
1494 if (thd->variables.session_track_transaction_info != TX_TRACK_NONE)
1495 DBUG_VOID_RETURN;
1496
1497 /*
1498 The query cache is only supported for the classic protocols.
1499 Although protocol_callback.cc is not compiled in embedded, there
1500 are other protocols. A check outside the non-embedded block is
1501 better.
1502 */
1503 if (!thd->is_classic_protocol())
1504 DBUG_VOID_RETURN;
1505 #ifndef EMBEDDED_LIBRARY
1506 /*
1507 Without active vio, net_write_packet() will not be called and
1508 therefore neither Query_cache::insert(). Since we will never get a
1509 complete query result in this case, it does not make sense to
1510 register the query in the first place.
1511 */
1512 if (!thd->get_protocol()->connection_alive())
1513 DBUG_VOID_RETURN;
1514 #endif
1515
1516 uint8 tables_type= 0;
1517
1518 if ((local_tables= is_cacheable(thd, thd->lex, tables_used, &tables_type)))
1519 {
1520 Query_cache_query_flags flags;
1521 // fill all gaps between fields with 0 to get repeatable key
1522 memset(&flags, 0, QUERY_CACHE_FLAGS_SIZE);
1523 flags.client_long_flag=
1524 thd->get_protocol()->has_client_capability(CLIENT_LONG_FLAG);
1525 flags.client_protocol_41=
1526 thd->get_protocol()->has_client_capability(CLIENT_PROTOCOL_41);
1527 /*
1528 Protocol influences result format, so statement results in the binary
1529 protocol (COM_EXECUTE) cannot be served to statements asking for results
1530 in the text protocol (COM_QUERY) and vice-versa.
1531 */
1532 flags.protocol_type= (unsigned int) thd->get_protocol()->type();
1533 /* PROTOCOL_LOCAL results are not cached. */
1534 assert(flags.protocol_type != (unsigned int) Protocol::PROTOCOL_LOCAL);
1535 flags.more_results_exists= MY_TEST(thd->server_status &
1536 SERVER_MORE_RESULTS_EXISTS);
1537 flags.in_trans= thd->in_active_multi_stmt_transaction();
1538 flags.autocommit= MY_TEST(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
1539 flags.pkt_nr= thd->get_protocol_classic()->get_pkt_nr();
1540 flags.character_set_client_num=
1541 thd->variables.character_set_client->number;
1542 flags.character_set_results_num=
1543 (thd->variables.character_set_results ?
1544 thd->variables.character_set_results->number :
1545 UINT_MAX);
1546 flags.collation_connection_num=
1547 thd->variables.collation_connection->number;
1548 flags.limit= thd->variables.select_limit;
1549 flags.time_zone= thd->variables.time_zone;
1550 flags.sql_mode= thd->variables.sql_mode;
1551 flags.max_sort_length= thd->variables.max_sort_length;
1552 flags.lc_time_names= thd->variables.lc_time_names;
1553 flags.group_concat_max_len= thd->variables.group_concat_max_len;
1554 flags.div_precision_increment= thd->variables.div_precincrement;
1555 flags.default_week_format= thd->variables.default_week_format;
1556 DBUG_PRINT("qcache", ("\
1557 long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
1558 CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
1559 sql mode: 0x%llx, sort len: %lu, conncat len: %lu, div_precision: %lu, \
1560 def_week_frmt: %lu, in_trans: %d, autocommit: %d",
1561 (int)flags.client_long_flag,
1562 (int)flags.client_protocol_41,
1563 (int)flags.protocol_type,
1564 (int)flags.more_results_exists,
1565 flags.pkt_nr,
1566 flags.character_set_client_num,
1567 flags.character_set_results_num,
1568 flags.collation_connection_num,
1569 (ulong) flags.limit,
1570 (ulong) flags.time_zone,
1571 flags.sql_mode,
1572 flags.max_sort_length,
1573 flags.group_concat_max_len,
1574 flags.div_precision_increment,
1575 flags.default_week_format,
1576 (int)flags.in_trans,
1577 (int)flags.autocommit));
1578
1579 /*
1580 Make InnoDB to release the adaptive hash index latch before
1581 acquiring the query cache mutex.
1582 */
1583 ha_release_temporary_latches(thd);
1584
1585 /*
1586 A table- or a full flush operation can potentially take a long time to
1587 finish. We choose not to wait for them and skip caching statements
1588 instead.
1589
1590 In case the wait time can't be determined there is an upper limit which
1591 causes try_lock() to abort with a time out.
1592
1593 The 'TRUE' parameter indicate that the lock is allowed to timeout
1594
1595 */
1596 if (try_lock(TRUE))
1597 DBUG_VOID_RETURN;
1598 if (query_cache_size == 0)
1599 {
1600 unlock();
1601 DBUG_VOID_RETURN;
1602 }
1603 DUMP(this);
1604
1605 if (ask_handler_allowance(thd, tables_used))
1606 {
1607 refused++;
1608 unlock();
1609 DBUG_VOID_RETURN;
1610 }
1611 QueryStripComments *query_strip_comments = &(thd->query_strip_comments);
1612 QueryStripComments_Backup backup(thd,query_strip_comments);
1613
1614 /* Key is query + database + flag */
1615 size_t tot_length;
1616 char *cache_key= make_cache_key(thd, thd->query(), &flags, &tot_length);
1617 if (cache_key == NULL)
1618 {
1619 unlock();
1620 DBUG_VOID_RETURN;
1621 }
1622
1623 /* Check if another thread is processing the same query? */
1624 Query_cache_block *competitor = (Query_cache_block *)
1625 my_hash_search(&queries, (uchar*) cache_key, tot_length);
1626 DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor));
1627 if (competitor == 0)
1628 {
1629 /* Query is not in cache and no one is working with it; Store it */
1630 Query_cache_block *query_block;
1631 query_block= write_block_data(tot_length, (uchar*) cache_key,
1632 ALIGN_SIZE(sizeof(Query_cache_query)),
1633 Query_cache_block::QUERY, local_tables);
1634 if (query_block != 0)
1635 {
1636 DBUG_PRINT("qcache", ("query block 0x%lx allocated, %lu",
1637 (ulong) query_block, query_block->used));
1638
1639 Query_cache_query *header = query_block->query();
1640 header->init_n_lock();
1641 if (my_hash_insert(&queries, (uchar*) query_block))
1642 {
1643 refused++;
1644 DBUG_PRINT("qcache", ("insertion in query hash"));
1645 header->unlock_n_destroy();
1646 free_memory_block(query_block);
1647 unlock();
1648 goto end;
1649 }
1650 if (!register_all_tables(query_block, tables_used, local_tables))
1651 {
1652 refused++;
1653 DBUG_PRINT("warning", ("tables list including failed"));
1654 my_hash_delete(&queries, (uchar *) query_block);
1655 header->unlock_n_destroy();
1656 free_memory_block(query_block);
1657
1658 unlock();
1659 goto end;
1660 }
1661 double_linked_list_simple_include(query_block, &queries_blocks);
1662 inserts++;
1663 queries_in_cache++;
1664 thd->query_cache_tls.first_query_block= query_block;
1665 header->writer(&thd->query_cache_tls);
1666 header->tables_type(tables_type);
1667 unlock();
1668
1669 // init_n_lock make query block locked
1670 BLOCK_UNLOCK_WR(query_block);
1671 }
1672 else
1673 {
1674 // We have not enough memory to store query => do nothing
1675 refused++;
1676 unlock();
1677 DBUG_PRINT("warning", ("Can't allocate query"));
1678 }
1679 }
1680 else
1681 {
1682 // Another thread is processing the same query => do nothing
1683 refused++;
1684 unlock();
1685 DBUG_PRINT("qcache", ("Another thread process same query"));
1686 }
1687 }
1688 else if (thd->lex->sql_command == SQLCOM_SELECT)
1689 refused++;
1690
1691 end:
1692 DBUG_VOID_RETURN;
1693 }
1694
1695
1696 #ifndef EMBEDDED_LIBRARY
1697 /**
1698 Send a single memory block from the query cache.
1699
1700 Respects the client/server protocol limits for the
1701 size of the network packet, and splits a large block
1702 in pieces to ensure that individual piece doesn't exceed
1703 the maximal allowed size of the network packet (16M).
1704
1705 @param[in] net NET handler
1706 @param[in] packet packet to send
1707 @param[in] len packet length
1708
1709 @return Operation status
1710 @retval FALSE On success
1711 @retval TRUE On error
1712 */
1713 static bool
send_data_in_chunks(NET * net,const uchar * packet,ulong len)1714 send_data_in_chunks(NET *net, const uchar *packet, ulong len)
1715 {
1716 /*
1717 On the client we may require more memory than max_allowed_packet
1718 to keep, both, the truncated last logical packet, and the
1719 compressed next packet. This never (or in practice never)
1720 happens without compression, since without compression it's very
1721 unlikely that a) a truncated logical packet would remain on the
1722 client when it's time to read the next packet b) a subsequent
1723 logical packet that is being read would be so large that
1724 size-of-new-packet + size-of-old-packet-tail >
1725 max_allowed_packet. To remedy this issue, we send data in 1MB
1726 sized packets, that's below the current client default of 16MB
1727 for max_allowed_packet, but large enough to ensure there is no
1728 unnecessary overhead from too many syscalls per result set.
1729 */
1730 static const ulong MAX_CHUNK_LENGTH= 1024*1024;
1731
1732 while (len > MAX_CHUNK_LENGTH)
1733 {
1734 if (net_write_packet(net, packet, MAX_CHUNK_LENGTH))
1735 return TRUE;
1736 packet+= MAX_CHUNK_LENGTH;
1737 len-= MAX_CHUNK_LENGTH;
1738 }
1739 if (len && net_write_packet(net, packet, len))
1740 return TRUE;
1741
1742 return FALSE;
1743 }
1744 #endif
1745
1746
1747 /*
1748 Check if the query is in the cache. If it was cached, send it
1749 to the user.
1750
1751 @param thd Pointer to the thread handler
1752 @param sql A reference to the sql statement *
1753
1754 @return status code
1755 @retval 0 Query was not cached.
1756 @retval 1 The query was cached and user was sent the result.
1757 @retval -1 The query was cached but we didn't have rights to use it.
1758
1759 In case of -1, no error is sent to the client.
1760
1761 *) The buffer must be allocated memory of size:
1762 tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
1763 */
1764
send_result_to_client(THD * thd,const LEX_CSTRING & sql)1765 int Query_cache::send_result_to_client(THD *thd, const LEX_CSTRING &sql)
1766 {
1767 ulonglong engine_data;
1768 Query_cache_query *query;
1769 #ifndef EMBEDDED_LIBRARY
1770 Query_cache_block *first_result_block;
1771 #endif
1772 Query_cache_block *result_block;
1773 Query_cache_block_table *block_table, *block_table_end;
1774 char *cache_key= NULL;
1775 size_t tot_length;
1776 Query_cache_query_flags flags;
1777 QueryStripComments *query_strip_comments = &(thd->query_strip_comments);
1778 DBUG_ENTER("Query_cache::send_result_to_client");
1779
1780 /*
1781 Testing 'query_cache_size' without a lock here is safe: the thing
1782 we may loose is that the query won't be served from cache, but we
1783 save on mutex locking in the case when query cache is disabled.
1784
1785 See also a note on double-check locking usage above.
1786 */
1787 if (is_disabled() || thd->locked_tables_mode ||
1788 thd->variables.query_cache_type == 0 || query_cache_size == 0)
1789 goto err;
1790
1791 /*
1792 Don't work with Query_cache if the state of XA transaction is
1793 either IDLE or PREPARED. If we didn't do so we would get an
1794 assert fired later in the function trx_start_if_not_started_low()
1795 that is called when we are checking that query cache is allowed at
1796 this moment to operate on an InnoDB table.
1797 */
1798 if (thd->get_transaction()->xid_state()->check_xa_idle_or_prepared(false))
1799 goto err;
1800
1801 /*
1802 Don't allow serving from Query_cache while tracking transaction
1803 state. This is a safeguard in case an otherwise matching query
1804 was added to the cache before tracking was turned on.
1805 */
1806 if (thd->variables.session_track_transaction_info != TX_TRACK_NONE)
1807 goto err;
1808
1809 if (!thd->lex->safe_to_cache_query)
1810 {
1811 DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
1812 goto err;
1813 }
1814
1815 {
1816 uint i= 0;
1817 if(opt_query_cache_strip_comments)
1818 {
1819 /* Skip all comments and non-letter symbols */
1820 uint& query_position = i;
1821 const char* query = sql.str;
1822 while(query_position < sql.length)
1823 {
1824 bool check = false;
1825 char current = query[query_position];
1826 switch(current)
1827 {
1828 case '/':
1829 if (((query_position + 2) < sql.length)
1830 && ('*' == query[query_position+1])
1831 && ('!' != query[query_position+2]))
1832 {
1833 query_position += 2; // skip "/*"
1834 do
1835 {
1836 if('*' == query[query_position] && '/' == query[query_position+1]) // check for "*/" (without space)
1837 {
1838 query_position += 2; // skip "*/" (without space)
1839 break;
1840 }
1841 else
1842 {
1843 ++query_position;
1844 }
1845 }
1846 while (query_position < sql.length);
1847 continue; // analyze current symbol
1848 }
1849 break;
1850 case '-':
1851 if(query[query_position+1] == '-')
1852 {
1853 ++query_position; // skip "-"
1854 }
1855 else
1856 {
1857 break;
1858 }
1859 // fallthrough
1860 case '#':
1861 do
1862 {
1863 ++query_position; // skip current symbol
1864 if('\n' == query[query_position]) // check for '\n'
1865 {
1866 ++query_position; // skip '\n'
1867 break;
1868 }
1869 }
1870 while (query_position < sql.length);
1871 continue; // analyze current symbol
1872 case '\r':
1873 case '\n':
1874 case '\t':
1875 case ' ':
1876 case '(':
1877 case ')':
1878 break;
1879 default:
1880 check = true;
1881 break; // make gcc happy
1882 } // switch(current)
1883 if(check)
1884 {
1885 if (query_position + 2 < sql.length)
1886 {
1887 // cacheable
1888 break;
1889 }
1890 else
1891 {
1892 DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
1893 goto err;
1894 }
1895 } // if(check)
1896 ++query_position;
1897 } // while(query_position < query_length)
1898 }
1899 else // if(opt_query_cache_strip_comments)
1900 {
1901 /*
1902 Skip '(' characters in queries like following:
1903 (select a from t1) union (select a from t1);
1904 */
1905 while (sql.str[i]=='(')
1906 i++;
1907
1908 } // if(opt_query_cache_strip_comments)
1909 /*
1910 Test if the query is a SELECT
1911 (pre-space is removed in dispatch_command).
1912
1913 First '/' looks like comment before command it is not
1914 frequently appeared in real life, consequently we can
1915 check all such queries, too.
1916 */
1917 if ((my_toupper(system_charset_info, sql.str[i]) != 'S' ||
1918 my_toupper(system_charset_info, sql.str[i + 1]) != 'E' ||
1919 my_toupper(system_charset_info, sql.str[i + 2]) != 'L' ||
1920 my_toupper(system_charset_info, sql.str[i + 3]) != 'E' ||
1921 my_toupper(system_charset_info, sql.str[i + 4]) != 'C' ||
1922 my_toupper(system_charset_info, sql.str[i + 5]) != 'T') &&
1923 (sql.str[i] != '/' || sql.length < i+6))
1924 {
1925 DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
1926 goto err;
1927 }
1928
1929 DBUG_EXECUTE_IF("test_sql_no_cache",
1930 assert(has_no_cache_directive(sql.str, i+6,
1931 sql.length)););
1932 if (has_no_cache_directive(sql.str, i+6, sql.length))
1933 {
1934 /*
1935 We do not increase 'refused' statistics here since it will be done
1936 later when the query is parsed.
1937 */
1938 DBUG_PRINT("qcache", ("The statement has a SQL_NO_CACHE directive"));
1939 goto err;
1940 }
1941 }
1942 /*
1943 Try to obtain an exclusive lock on the query cache. If the cache is
1944 disabled or if a full cache flush is in progress, the attempt to
1945 get the lock is aborted.
1946
1947 The 'TRUE' parameter indicate that the lock is allowed to timeout
1948 */
1949 if (try_lock(TRUE))
1950 goto err;
1951
1952 if (query_cache_size == 0)
1953 goto err_unlock;
1954
1955 Query_cache_block *query_block;
1956 LEX_CSTRING stripped_query;
1957 if(opt_query_cache_strip_comments)
1958 {
1959 query_strip_comments->set(sql, // TODO remove additional length
1960 QUERY_BUFFER_ADDITIONAL_LENGTH(
1961 thd->db().length));
1962 stripped_query.str= query_strip_comments->query();
1963 stripped_query.length= query_strip_comments->query_length();
1964 }
1965
1966 THD_STAGE_INFO(thd, stage_checking_query_cache_for_query);
1967
1968 // fill all gaps between fields with 0 to get repeatable key
1969 memset(&flags, 0, QUERY_CACHE_FLAGS_SIZE);
1970 flags.client_long_flag= MY_TEST(
1971 thd->get_protocol()->has_client_capability(CLIENT_LONG_FLAG));
1972 flags.client_protocol_41= MY_TEST(
1973 thd->get_protocol()->has_client_capability(CLIENT_PROTOCOL_41));
1974 flags.protocol_type= (unsigned int) thd->get_protocol()->type();
1975 flags.more_results_exists= MY_TEST(thd->server_status &
1976 SERVER_MORE_RESULTS_EXISTS);
1977 flags.in_trans= thd->in_active_multi_stmt_transaction();
1978 flags.autocommit= MY_TEST(thd->server_status & SERVER_STATUS_AUTOCOMMIT);
1979 flags.pkt_nr= thd->get_protocol_classic()->get_pkt_nr();
1980 flags.character_set_client_num= thd->variables.character_set_client->number;
1981 flags.character_set_results_num=
1982 (thd->variables.character_set_results ?
1983 thd->variables.character_set_results->number :
1984 UINT_MAX);
1985 flags.collation_connection_num= thd->variables.collation_connection->number;
1986 flags.limit= thd->variables.select_limit;
1987 flags.time_zone= thd->variables.time_zone;
1988 flags.sql_mode= thd->variables.sql_mode;
1989 flags.max_sort_length= thd->variables.max_sort_length;
1990 flags.group_concat_max_len= thd->variables.group_concat_max_len;
1991 flags.div_precision_increment= thd->variables.div_precincrement;
1992 flags.default_week_format= thd->variables.default_week_format;
1993 flags.lc_time_names= thd->variables.lc_time_names;
1994 DBUG_PRINT("qcache", ("\
1995 long %d, 4.1: %d, bin_proto: %d, more results %d, pkt_nr: %d, \
1996 CS client: %u, CS result: %u, CS conn: %u, limit: %lu, TZ: 0x%lx, \
1997 sql mode: 0x%llx, sort len: %lu, conncat len: %lu, div_precision: %lu, \
1998 def_week_frmt: %lu, in_trans: %d, autocommit: %d",
1999 (int)flags.client_long_flag,
2000 (int)flags.client_protocol_41,
2001 (int)flags.protocol_type,
2002 (int)flags.more_results_exists,
2003 flags.pkt_nr,
2004 flags.character_set_client_num,
2005 flags.character_set_results_num,
2006 flags.collation_connection_num,
2007 (ulong) flags.limit,
2008 (ulong) flags.time_zone,
2009 flags.sql_mode,
2010 flags.max_sort_length,
2011 flags.group_concat_max_len,
2012 flags.div_precision_increment,
2013 flags.default_week_format,
2014 (int)flags.in_trans,
2015 (int)flags.autocommit));
2016
2017 cache_key= make_cache_key(thd, opt_query_cache_strip_comments
2018 ? stripped_query : thd->query(), &flags,
2019 &tot_length);
2020 if (cache_key == NULL)
2021 goto err_unlock;
2022
2023 query_block = (Query_cache_block *) my_hash_search(&queries,
2024 (uchar*) cache_key,
2025 tot_length);
2026 /* Quick abort on unlocked data */
2027 if (query_block == 0 ||
2028 query_block->query()->result() == 0 ||
2029 query_block->query()->result()->type != Query_cache_block::RESULT)
2030 {
2031 DBUG_PRINT("qcache", ("No query in query hash or no results"));
2032 goto err_unlock;
2033 }
2034 DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block));
2035
2036 /*
2037 We only need to clear the diagnostics area when we actually
2038 find the query, as in all other cases, we'll go through
2039 regular parsing and execution, where the DA will be reset
2040 as needed, anyway.
2041
2042 We're not pushing/popping a private DA here the way we do for
2043 parsing; if we got this far, we know we've got a SELECT on our
2044 hands and not a diagnotics statement that might need the
2045 previous statement's diagnostics area, so we just clear the DA.
2046
2047 We're doing it here and not in the caller as there's three of
2048 them (PS, SP, interactive). Doing it any earlier in this routine
2049 would reset the DA in "SELECT @@error_count"/"SELECT @@warning_count"
2050 before we can save the counts we'll need later (QC will see the
2051 SELECT go into this branch, but since we haven't parsed yet, we
2052 don't know yet that it's one of those legacy variables that require
2053 saving and basically turn SELECT into a sort of, sort of not
2054 diagnostics command. Ugly stuff.
2055 */
2056 thd->get_stmt_da()->reset_diagnostics_area();
2057 thd->get_stmt_da()->reset_condition_info(thd);
2058
2059 /* Now lock and test that nothing changed while blocks was unlocked */
2060 BLOCK_LOCK_RD(query_block);
2061
2062 query = query_block->query();
2063 result_block= query->result();
2064 #ifndef EMBEDDED_LIBRARY
2065 first_result_block= result_block;
2066 #endif
2067
2068 if (result_block == 0 || result_block->type != Query_cache_block::RESULT)
2069 {
2070 /* The query is probably yet processed */
2071 DBUG_PRINT("qcache", ("query found, but no data or data incomplete"));
2072 BLOCK_UNLOCK_RD(query_block);
2073 goto err_unlock;
2074 }
2075 DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
2076
2077 if (thd->in_multi_stmt_transaction_mode() &&
2078 (query->tables_type() & HA_CACHE_TBL_TRANSACT))
2079 {
2080 DBUG_PRINT("qcache",
2081 ("we are in transaction and have transaction tables in query"));
2082 BLOCK_UNLOCK_RD(query_block);
2083 goto err_unlock;
2084 }
2085
2086 // Check access;
2087 THD_STAGE_INFO(thd, stage_checking_privileges_on_cached_query);
2088 block_table= query_block->table(0);
2089 block_table_end= block_table+query_block->n_tables;
2090 for (; block_table != block_table_end; block_table++)
2091 {
2092 TABLE_LIST table_list;
2093 TABLE *tmptable;
2094 Query_cache_table *table = block_table->parent;
2095
2096 /*
2097 Check that we have not temporary tables with same names of tables
2098 of this query. If we have such tables, we will not send data from
2099 query cache, because temporary tables hide real tables by which
2100 query in query cache was made.
2101 */
2102 for (tmptable= thd->temporary_tables; tmptable ; tmptable= tmptable->next)
2103 {
2104 if (tmptable->s->table_cache_key.length - TMP_TABLE_KEY_EXTRA ==
2105 table->key_length() &&
2106 !memcmp(tmptable->s->table_cache_key.str, table->data(),
2107 table->key_length()))
2108 {
2109 DBUG_PRINT("qcache",
2110 ("Temporary table detected: '%s.%s'",
2111 tmptable->s->db.str, tmptable->s->table_name.str));
2112 unlock();
2113 /*
2114 We should not store result of this query because it contain
2115 temporary tables => assign following variable to make check
2116 faster.
2117 */
2118 thd->lex->safe_to_cache_query=0;
2119 BLOCK_UNLOCK_RD(query_block);
2120 DBUG_RETURN(-1);
2121 }
2122 }
2123
2124 table_list.db = table->db();
2125 table_list.alias= table_list.table_name= table->table();
2126 #ifndef NO_EMBEDDED_ACCESS_CHECKS
2127 if (check_table_access(thd,SELECT_ACL,&table_list, FALSE, 1,TRUE))
2128 {
2129 DBUG_PRINT("qcache",
2130 ("probably no SELECT access to %s.%s => return to normal processing",
2131 table_list.db, table_list.alias));
2132 unlock();
2133 thd->lex->safe_to_cache_query=0; // Don't try to cache this
2134 BLOCK_UNLOCK_RD(query_block);
2135 DBUG_RETURN(-1); // Privilege error
2136 }
2137 assert((SELECT_ACL & ~table_list.grant.privilege) ==
2138 table_list.grant.want_privilege);
2139 if ((table_list.grant.privilege & SELECT_ACL) == 0)
2140 {
2141 DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
2142 table_list.db, table_list.alias));
2143 BLOCK_UNLOCK_RD(query_block);
2144 thd->lex->safe_to_cache_query= 0; // Don't try to cache this
2145 goto err_unlock; // Parse query
2146 }
2147 #endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
2148 engine_data= table->engine_data();
2149 if (table->callback())
2150 {
2151 char qcache_se_key_name[FN_REFLEN + 1];
2152 size_t qcache_se_key_len;
2153 engine_data= table->engine_data();
2154
2155 qcache_se_key_len= build_table_filename(qcache_se_key_name,
2156 sizeof(qcache_se_key_name),
2157 table->db(), table->table(),
2158 "", 0);
2159
2160 if (!(*table->callback())(thd, qcache_se_key_name,
2161 static_cast<uint>(qcache_se_key_len),
2162 &engine_data))
2163 {
2164 DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
2165 table_list.db, table_list.alias));
2166 BLOCK_UNLOCK_RD(query_block);
2167 if (engine_data != table->engine_data())
2168 {
2169 DBUG_PRINT("qcache",
2170 ("Handler require invalidation queries of %s.%s %lu-%lu",
2171 table_list.db, table_list.alias,
2172 (ulong) engine_data, (ulong) table->engine_data()));
2173 invalidate_table_internal(thd, (uchar *) table->db(),
2174 table->key_length());
2175 }
2176 else
2177 thd->lex->safe_to_cache_query= 0; // Don't try to cache this
2178 /*
2179 End the statement transaction potentially started by engine.
2180 Currently our engines do not request rollback from callbacks.
2181 If this is going to change code needs to be reworked.
2182 */
2183 assert(! thd->transaction_rollback_request);
2184 trans_rollback_stmt(thd);
2185 goto err_unlock; // Parse query
2186 }
2187 }
2188 else
2189 DBUG_PRINT("qcache", ("handler allow caching %s,%s",
2190 table_list.db, table_list.alias));
2191 }
2192 move_to_query_list_end(query_block);
2193 hits++;
2194 unlock();
2195
2196 /*
2197 Send cached result to client
2198 */
2199 #ifndef EMBEDDED_LIBRARY
2200 THD_STAGE_INFO(thd, stage_sending_cached_result_to_client);
2201 do
2202 {
2203 DBUG_PRINT("qcache", ("Results (len: %lu used: %lu headers: %lu)",
2204 result_block->length, result_block->used,
2205 (ulong) (result_block->headers_len()+
2206 ALIGN_SIZE(sizeof(Query_cache_result)))));
2207
2208 Query_cache_result *result = result_block->result();
2209 if (send_data_in_chunks(thd->get_protocol_classic()->get_net(),
2210 result->data(),
2211 result_block->used -
2212 result_block->headers_len() -
2213 ALIGN_SIZE(sizeof(Query_cache_result))))
2214 break; // Client aborted
2215 result_block = result_block->next;
2216 // Keep packet number updated
2217 thd->get_protocol_classic()->set_pkt_nr(query->last_pkt_nr);
2218 } while (result_block != first_result_block);
2219 #else
2220 {
2221 Querycache_stream qs(result_block, result_block->headers_len() +
2222 ALIGN_SIZE(sizeof(Query_cache_result)));
2223 emb_load_querycache_result(thd, &qs);
2224 }
2225 #endif /*!EMBEDDED_LIBRARY*/
2226
2227 thd->current_found_rows= query->found_rows();
2228 thd->update_previous_found_rows();
2229 thd->clear_current_query_costs();
2230 thd->save_current_query_costs();
2231
2232 {
2233 Opt_trace_start ots(thd, NULL, SQLCOM_SELECT, NULL,
2234 thd->query().str, thd->query().length, NULL,
2235 thd->variables.character_set_client);
2236
2237 Opt_trace_object (&thd->opt_trace)
2238 .add("query_result_read_from_cache", true);
2239 }
2240
2241 /*
2242 End the statement transaction potentially started by an
2243 engine callback. We ignore the return value for now,
2244 since as long as EOF packet is part of the query cache
2245 response, we can't handle it anyway.
2246 */
2247 (void) trans_commit_stmt(thd);
2248 thd->query_plan_flags|= QPLAN_QC;
2249 if (!thd->get_stmt_da()->is_set())
2250 thd->get_stmt_da()->disable_status();
2251
2252 BLOCK_UNLOCK_RD(query_block);
2253 MYSQL_QUERY_CACHE_HIT(const_cast<char*>(thd->query().str),
2254 (ulong) thd->current_found_rows);
2255 DBUG_RETURN(1); // Result sent to client
2256
2257 err_unlock:
2258 unlock();
2259 err:
2260 thd->query_plan_flags|= QPLAN_QC_NO;
2261 MYSQL_QUERY_CACHE_MISS(const_cast<char*>(thd->query().str));
2262 DBUG_RETURN(0); // Query was not cached
2263 }
2264
2265
2266 /**
2267 Remove all cached queries that use the given table.
2268
2269 @param thd Thread handle
2270 @param table_used TABLE_LIST representing the table to be
2271 invalidated.
2272 @param using_transactions If we are inside a transaction only add
2273 the table to a list of changed tables for now,
2274 don't invalidate directly. The table will instead
2275 be invalidated once the transaction commits.
2276 */
2277
invalidate_single(THD * thd,TABLE_LIST * table_used,my_bool using_transactions)2278 void Query_cache::invalidate_single(THD *thd, TABLE_LIST *table_used,
2279 my_bool using_transactions)
2280 {
2281 DBUG_ENTER("Query_cache::invalidate_single (table list)");
2282 if (is_disabled())
2283 DBUG_VOID_RETURN;
2284
2285 using_transactions&= thd->in_multi_stmt_transaction_mode();
2286 assert(!using_transactions || table_used->table!=0);
2287 assert(!table_used->is_view_or_derived());
2288 if (table_used->is_view_or_derived())
2289 DBUG_VOID_RETURN;
2290 if (using_transactions &&
2291 (table_used->table->file->table_cache_type() ==
2292 HA_CACHE_TBL_TRANSACT))
2293 /*
2294 table_used->table can't be 0 in transaction.
2295 Only 'drop' invalidate not opened table, but 'drop'
2296 force transaction finish.
2297 */
2298 thd->add_changed_table(table_used->table);
2299 else
2300 invalidate_table(thd, table_used);
2301
2302 DBUG_VOID_RETURN;
2303 }
2304
2305 /**
2306 Remove all cached queries that use any of the tables in the list.
2307
2308 @see Query_cache::invalidate_single().
2309 */
2310
invalidate(THD * thd,TABLE_LIST * tables_used,my_bool using_transactions)2311 void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
2312 my_bool using_transactions)
2313 {
2314 DBUG_ENTER("Query_cache::invalidate (table list)");
2315 if (is_disabled())
2316 DBUG_VOID_RETURN;
2317
2318 using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode();
2319 for (; tables_used; tables_used= tables_used->next_local)
2320 invalidate_single(thd, tables_used, using_transactions);
2321
2322 DEBUG_SYNC(thd, "wait_after_query_cache_invalidate");
2323
2324 DBUG_VOID_RETURN;
2325 }
2326
invalidate(CHANGED_TABLE_LIST * tables_used)2327 void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
2328 {
2329 DBUG_ENTER("Query_cache::invalidate (changed table list)");
2330 if (is_disabled())
2331 DBUG_VOID_RETURN;
2332
2333 THD *thd= current_thd;
2334 for (; tables_used; tables_used= tables_used->next)
2335 {
2336 THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table_list);
2337 invalidate_table(thd, (uchar*) tables_used->key, tables_used->key_length);
2338 DBUG_PRINT("qcache", ("db: %s table: %s", tables_used->key,
2339 tables_used->key+
2340 strlen(tables_used->key)+1));
2341 }
2342 DBUG_VOID_RETURN;
2343 }
2344
2345
2346 /*
2347 Invalidate locked for write
2348
2349 SYNOPSIS
2350 Query_cache::invalidate_locked_for_write()
2351 tables_used - table list
2352
2353 NOTE
2354 can be used only for opened tables
2355 */
invalidate_locked_for_write(TABLE_LIST * tables_used)2356 void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
2357 {
2358 DBUG_ENTER("Query_cache::invalidate_locked_for_write");
2359 if (is_disabled())
2360 DBUG_VOID_RETURN;
2361
2362 THD *thd= current_thd;
2363 for (; tables_used; tables_used= tables_used->next_local)
2364 {
2365 THD_STAGE_INFO(thd, stage_invalidating_query_cache_entries_table);
2366 if (tables_used->lock_type >= TL_WRITE_ALLOW_WRITE &&
2367 tables_used->table)
2368 {
2369 invalidate_table(thd, tables_used->table);
2370 }
2371 }
2372 DBUG_VOID_RETURN;
2373 }
2374
2375 /*
2376 Remove all cached queries that uses the given table
2377 */
2378
invalidate(THD * thd,TABLE * table,my_bool using_transactions)2379 void Query_cache::invalidate(THD *thd, TABLE *table,
2380 my_bool using_transactions)
2381 {
2382 DBUG_ENTER("Query_cache::invalidate (table)");
2383 if (is_disabled())
2384 DBUG_VOID_RETURN;
2385
2386 using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode();
2387 if (using_transactions &&
2388 (table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
2389 thd->add_changed_table(table);
2390 else
2391 invalidate_table(thd, table);
2392
2393
2394 DBUG_VOID_RETURN;
2395 }
2396
invalidate(THD * thd,const char * key,uint32 key_length,my_bool using_transactions)2397 void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
2398 my_bool using_transactions)
2399 {
2400 DBUG_ENTER("Query_cache::invalidate (key)");
2401 if (is_disabled())
2402 DBUG_VOID_RETURN;
2403
2404 using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode();
2405 if (using_transactions) // used for innodb => has_transactions() is TRUE
2406 thd->add_changed_table(key, key_length);
2407 else
2408 invalidate_table(thd, (uchar*)key, key_length);
2409
2410 DBUG_VOID_RETURN;
2411 }
2412
2413
2414 /**
2415 Remove all cached queries that uses the given database.
2416 */
2417
invalidate(const char * db)2418 void Query_cache::invalidate(const char *db)
2419 {
2420
2421 DBUG_ENTER("Query_cache::invalidate (db)");
2422 if (is_disabled())
2423 DBUG_VOID_RETURN;
2424
2425 bool restart= FALSE;
2426 /*
2427 Lock the query cache and queue all invalidation attempts to avoid
2428 the risk of a race between invalidation, cache inserts and flushes.
2429 */
2430 lock();
2431
2432 THD *thd= current_thd;
2433
2434 if (query_cache_size > 0)
2435 {
2436 if (tables_blocks)
2437 {
2438 Query_cache_block *table_block = tables_blocks;
2439 do {
2440 restart= FALSE;
2441 do
2442 {
2443 Query_cache_block *next= table_block->next;
2444 Query_cache_table *table = table_block->table();
2445 if (strcmp(table->db(),db) == 0)
2446 {
2447 Query_cache_block_table *list_root= table_block->table(0);
2448 invalidate_query_block_list(thd,list_root);
2449 }
2450
2451 table_block= next;
2452
2453 /*
2454 If our root node to used tables became null then the last element
2455 in the table list was removed when a query was invalidated;
2456 Terminate the search.
2457 */
2458 if (tables_blocks == 0)
2459 {
2460 table_block= tables_blocks;
2461 }
2462 /*
2463 If the iterated list has changed underlying structure;
2464 we need to restart the search.
2465 */
2466 else if (table_block->type == Query_cache_block::FREE)
2467 {
2468 restart= TRUE;
2469 table_block= tables_blocks;
2470 }
2471 /*
2472 The used tables are linked in a circular list;
2473 loop until we return to the begining.
2474 */
2475 } while (table_block != tables_blocks);
2476 /*
2477 Invalidating a table will also mean that all cached queries using
2478 this table also will be invalidated. This will in turn change the
2479 list of tables associated with these queries and the linked list of
2480 used table will be changed. Because of this we might need to restart
2481 the search when a table has been invalidated.
2482 */
2483 } while (restart);
2484 } // end if( tables_blocks )
2485 }
2486 unlock();
2487
2488 DBUG_VOID_RETURN;
2489 }
2490
2491
invalidate_by_MyISAM_filename(const char * filename)2492 void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
2493 {
2494 DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
2495
2496 /* Calculate the key outside the lock to make the lock shorter */
2497 char key[MAX_DBKEY_LENGTH];
2498 size_t db_length;
2499 size_t key_length= filename_2_table_key(key, filename, &db_length);
2500 THD *thd= current_thd;
2501 invalidate_table(thd,(uchar *)key, key_length);
2502 DBUG_EXECUTE("check_querycache", check_integrity(LOCK_WHILE_CHECKING););
2503 DBUG_VOID_RETURN;
2504 }
2505
2506 /* Remove all queries from cache */
2507
flush()2508 void Query_cache::flush()
2509 {
2510 DBUG_ENTER("Query_cache::flush");
2511 if (is_disabled())
2512 DBUG_VOID_RETURN;
2513
2514 QC_DEBUG_SYNC("wait_in_query_cache_flush1");
2515
2516 lock_and_suspend();
2517 if (query_cache_size > 0)
2518 {
2519 DUMP(this);
2520 flush_cache();
2521 DUMP(this);
2522 }
2523
2524 DBUG_EXECUTE("check_querycache", check_integrity(CALLER_HOLDS_LOCK););
2525 unlock();
2526 DBUG_VOID_RETURN;
2527 }
2528
2529
2530 /**
2531 Rearrange the memory blocks and join result in cache in 1 block (if
2532 result length > join_limit)
2533
2534 @param[in] join_limit If the minimum length of a result block to be joined.
2535 @param[in] iteration_limit The maximum number of packing and joining
2536 sequences.
2537
2538 */
2539
pack(ulong join_limit,uint iteration_limit)2540 void Query_cache::pack(ulong join_limit, uint iteration_limit)
2541 {
2542 DBUG_ENTER("Query_cache::pack");
2543
2544 if (is_disabled())
2545 DBUG_VOID_RETURN;
2546
2547 /*
2548 If the entire qc is being invalidated we can bail out early
2549 instead of waiting for the lock.
2550 */
2551 if (try_lock())
2552 DBUG_VOID_RETURN;
2553
2554 if (query_cache_size == 0)
2555 {
2556 unlock();
2557 DBUG_VOID_RETURN;
2558 }
2559
2560 uint i = 0;
2561 do
2562 {
2563 pack_cache();
2564 } while ((++i < iteration_limit) && join_results(join_limit));
2565
2566 unlock();
2567 DBUG_VOID_RETURN;
2568 }
2569
2570
destroy()2571 void Query_cache::destroy()
2572 {
2573 DBUG_ENTER("Query_cache::destroy");
2574 if (!initialized)
2575 {
2576 DBUG_PRINT("qcache", ("Query Cache not initialized"));
2577 }
2578 else
2579 {
2580 /* Underlying code expects the lock. */
2581 lock_and_suspend();
2582 free_cache();
2583 unlock();
2584
2585 mysql_cond_destroy(&COND_cache_status_changed);
2586 mysql_mutex_destroy(&structure_guard_mutex);
2587 initialized = 0;
2588 }
2589 DBUG_VOID_RETURN;
2590 }
2591
2592
2593 /*****************************************************************************
2594 init/destroy
2595 *****************************************************************************/
2596
init()2597 void Query_cache::init()
2598 {
2599 DBUG_ENTER("Query_cache::init");
2600 mysql_mutex_init(key_structure_guard_mutex,
2601 &structure_guard_mutex, MY_MUTEX_INIT_FAST);
2602 mysql_cond_init(key_COND_cache_status_changed,
2603 &COND_cache_status_changed);
2604 m_cache_lock_status= Query_cache::UNLOCKED;
2605 initialized = 1;
2606 /*
2607 If we explicitly turn off query cache from the command line query cache will
2608 be disabled for the reminder of the server life time. This is because we
2609 want to avoid locking the QC specific mutex if query cache isn't going to
2610 be used.
2611 */
2612 if (global_system_variables.query_cache_type == 0)
2613 query_cache.disable_query_cache();
2614
2615 DBUG_VOID_RETURN;
2616 }
2617
2618
init_cache()2619 ulong Query_cache::init_cache()
2620 {
2621 uint mem_bin_count, num, step;
2622 ulong mem_bin_size, prev_size, inc;
2623 ulong additional_data_size, max_mem_bin_size, approx_additional_data_size;
2624 int align;
2625
2626 DBUG_ENTER("Query_cache::init_cache");
2627
2628 approx_additional_data_size = (/* FIXME: WHAT FOR ? sizeof(Query_cache) + */
2629 sizeof(uchar*)*(def_query_hash_size+
2630 def_table_hash_size));
2631 if (query_cache_size < approx_additional_data_size)
2632 goto err;
2633
2634 query_cache_size-= approx_additional_data_size;
2635 align= query_cache_size % ALIGN_SIZE(1);
2636 if (align)
2637 {
2638 query_cache_size-= align;
2639 approx_additional_data_size+= align;
2640 }
2641
2642 /*
2643 Count memory bins number.
2644 Check section 6. in start comment for the used algorithm.
2645 */
2646
2647 max_mem_bin_size = query_cache_size >> QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2;
2648 mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
2649 QUERY_CACHE_MEM_BIN_PARTS_MUL);
2650 mem_bin_num = 1;
2651 mem_bin_steps = 1;
2652 mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
2653 prev_size = 0;
2654 if (mem_bin_size <= min_allocation_unit)
2655 {
2656 DBUG_PRINT("qcache", ("too small query cache => query cache disabled"));
2657 // TODO here (and above) should be warning in 4.1
2658 goto err;
2659 }
2660 while (mem_bin_size > min_allocation_unit)
2661 {
2662 mem_bin_num += mem_bin_count;
2663 prev_size = mem_bin_size;
2664 mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
2665 mem_bin_steps++;
2666 mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
2667 mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
2668
2669 // Prevent too small bins spacing
2670 if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
2671 mem_bin_count= (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
2672 }
2673 inc = (prev_size - mem_bin_size) / mem_bin_count;
2674 mem_bin_num += (mem_bin_count - (min_allocation_unit - mem_bin_size)/inc);
2675 mem_bin_steps++;
2676 additional_data_size = ((mem_bin_num+1) *
2677 ALIGN_SIZE(sizeof(Query_cache_memory_bin))+
2678 (mem_bin_steps *
2679 ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
2680
2681 if (query_cache_size < additional_data_size)
2682 goto err;
2683 query_cache_size -= additional_data_size;
2684
2685 if (!(cache= (uchar *)
2686 my_malloc(key_memory_Query_cache,
2687 query_cache_size+additional_data_size, MYF(0))))
2688 goto err;
2689
2690 DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins",
2691 query_cache_size, min_allocation_unit, mem_bin_num));
2692
2693 steps = (Query_cache_memory_bin_step *) cache;
2694 bins = ((Query_cache_memory_bin *)
2695 (cache + mem_bin_steps *
2696 ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
2697
2698 first_block = (Query_cache_block *) (cache + additional_data_size);
2699 first_block->init(query_cache_size);
2700 total_blocks++;
2701 first_block->pnext=first_block->pprev=first_block;
2702 first_block->next=first_block->prev=first_block;
2703
2704 /* Prepare bins */
2705
2706 bins[0].init(max_mem_bin_size);
2707 steps[0].init(max_mem_bin_size,0,0);
2708 mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
2709 QUERY_CACHE_MEM_BIN_PARTS_MUL);
2710 num= step= 1;
2711 mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
2712 while (mem_bin_size > min_allocation_unit)
2713 {
2714 ulong incr = (steps[step-1].size - mem_bin_size) / mem_bin_count;
2715 unsigned long size = mem_bin_size;
2716 for (uint i= mem_bin_count; i > 0; i--)
2717 {
2718 bins[num+i-1].init(size);
2719 size += incr;
2720 }
2721 num += mem_bin_count;
2722 steps[step].init(mem_bin_size, num-1, incr);
2723 mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
2724 step++;
2725 mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
2726 mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
2727 if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
2728 mem_bin_count=(mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
2729 }
2730 inc = (steps[step-1].size - mem_bin_size) / mem_bin_count;
2731
2732 /*
2733 num + mem_bin_count > mem_bin_num, but index never be > mem_bin_num
2734 because block with size < min_allocated_unit never will be requested
2735 */
2736
2737 steps[step].init(mem_bin_size, num + mem_bin_count - 1, inc);
2738 {
2739 uint skiped = (min_allocation_unit - mem_bin_size)/inc;
2740 ulong size = mem_bin_size + inc*skiped;
2741 uint i = mem_bin_count - skiped;
2742 while (i-- > 0)
2743 {
2744 bins[num+i].init(size);
2745 size += inc;
2746 }
2747 }
2748 bins[mem_bin_num].number = 1; // For easy end test in get_free_block
2749 free_memory = free_memory_blocks = 0;
2750 insert_into_free_memory_list(first_block);
2751
2752 DUMP(this);
2753
2754 (void) my_hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0,
2755 query_cache_query_get_key, 0, 0,
2756 key_memory_Query_cache);
2757 #ifndef FN_NO_CASE_SENSE
2758 /*
2759 If lower_case_table_names!=0 then db and table names are already
2760 converted to lower case and we can use binary collation for their
2761 comparison (no matter if file system case sensitive or not).
2762 If we have case-sensitive file system (like on most Unixes) and
2763 lower_case_table_names == 0 then we should distinguish my_table
2764 and MY_TABLE cases and so again can use binary collation.
2765 */
2766 (void) my_hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0,
2767 query_cache_table_get_key, 0, 0,
2768 key_memory_Query_cache);
2769 #else
2770 /*
2771 On windows, OS/2, MacOS X with HFS+ or any other case insensitive
2772 file system if lower_case_table_names!=0 we have same situation as
2773 in previous case, but if lower_case_table_names==0 then we should
2774 not distinguish cases (to be compatible in behavior with underlying
2775 file system) and so should use case insensitive collation for
2776 comparison.
2777 */
2778 (void) my_hash_init(&tables,
2779 lower_case_table_names ? &my_charset_bin :
2780 files_charset_info,
2781 def_table_hash_size, 0, 0,query_cache_table_get_key,
2782 0, 0,
2783 key_memory_Query_cache);
2784 #endif
2785
2786 queries_in_cache = 0;
2787 queries_blocks = 0;
2788 DBUG_RETURN(query_cache_size +
2789 additional_data_size + approx_additional_data_size);
2790
2791 err:
2792 make_disabled();
2793 DBUG_RETURN(0);
2794 }
2795
2796
2797 /* Disable the use of the query cache */
2798
make_disabled()2799 void Query_cache::make_disabled()
2800 {
2801 DBUG_ENTER("Query_cache::make_disabled");
2802 query_cache_size= 0;
2803 queries_blocks= 0;
2804 free_memory= 0;
2805 free_memory_blocks= 0;
2806 bins= 0;
2807 steps= 0;
2808 cache= 0;
2809 mem_bin_num= mem_bin_steps= 0;
2810 queries_in_cache= 0;
2811 first_block= 0;
2812 total_blocks= 0;
2813 tables_blocks= 0;
2814 DBUG_VOID_RETURN;
2815 }
2816
2817
2818 /**
2819 @class Query_cache
2820 Free all resources allocated by the cache.
2821
2822 This function frees all resources allocated by the cache. You
2823 have to call init_cache() before using the cache again. This function
2824 requires the structure_guard_mutex to be locked.
2825 */
2826
free_cache()2827 void Query_cache::free_cache()
2828 {
2829 DBUG_ENTER("Query_cache::free_cache");
2830
2831 my_free(cache);
2832 make_disabled();
2833 my_hash_free(&queries);
2834 my_hash_free(&tables);
2835 DBUG_VOID_RETURN;
2836 }
2837
2838 /*****************************************************************************
2839 Free block data
2840 *****************************************************************************/
2841
2842
2843 /**
2844 Flush the cache.
2845
2846 This function will flush cache contents. It assumes we have
2847 'structure_guard_mutex' locked. The function sets the m_cache_status flag and
2848 releases the lock, so other threads may proceed skipping the cache as if it
2849 is disabled. Concurrent flushes are performed in turn.
2850 After flush_cache() call, the cache is flushed, all the freed memory is
2851 accumulated in bin[0], and the 'structure_guard_mutex' is locked. However,
2852 since we could release the mutex during execution, the rest of the cache
2853 state could have been changed, and should not be relied on.
2854 */
2855
flush_cache()2856 void Query_cache::flush_cache()
2857 {
2858 QC_DEBUG_SYNC("wait_in_query_cache_flush2");
2859
2860 my_hash_reset(&queries);
2861 while (queries_blocks != 0)
2862 {
2863 BLOCK_LOCK_WR(queries_blocks);
2864 free_query_internal(queries_blocks);
2865 }
2866 }
2867
2868 /*
2869 Free oldest query that is not in use by another thread.
2870 Returns 1 if we couldn't remove anything
2871 */
2872
free_old_query()2873 my_bool Query_cache::free_old_query()
2874 {
2875 DBUG_ENTER("Query_cache::free_old_query");
2876 if (queries_blocks)
2877 {
2878 /*
2879 try_lock_writing used to prevent client because here lock
2880 sequence is breached.
2881 Also we don't need remove locked queries at this point.
2882 */
2883 Query_cache_block *query_block= 0;
2884 if (queries_blocks != 0)
2885 {
2886 Query_cache_block *block = queries_blocks;
2887 /* Search until we find first query that we can remove */
2888 do
2889 {
2890 Query_cache_query *header = block->query();
2891 if (header->result() != 0 &&
2892 header->result()->type == Query_cache_block::RESULT &&
2893 block->query()->try_lock_writing())
2894 {
2895 query_block = block;
2896 break;
2897 }
2898 } while ((block=block->next) != queries_blocks );
2899 }
2900
2901 if (query_block != 0)
2902 {
2903 free_query(query_block);
2904 lowmem_prunes++;
2905 DBUG_RETURN(0);
2906 }
2907 }
2908 DBUG_RETURN(1); // Nothing to remove
2909 }
2910
2911
2912 /*
2913 free_query_internal() - free query from query cache.
2914
2915 SYNOPSIS
2916 free_query_internal()
2917 query_block Query_cache_block representing the query
2918
2919 DESCRIPTION
2920 This function will remove the query from a cache, and place its
2921 memory blocks to the list of free blocks. 'query_block' must be
2922 locked for writing, this function will release (and destroy) this
2923 lock.
2924
2925 NOTE
2926 'query_block' should be removed from 'queries' hash _before_
2927 calling this method, as the lock will be destroyed here.
2928 */
2929
free_query_internal(Query_cache_block * query_block)2930 void Query_cache::free_query_internal(Query_cache_block *query_block)
2931 {
2932 DBUG_ENTER("Query_cache::free_query_internal");
2933 DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
2934 (ulong) query_block,
2935 query_block->query()->length() ));
2936
2937 queries_in_cache--;
2938
2939 Query_cache_query *query= query_block->query();
2940
2941 if (query->writer() != 0)
2942 {
2943 /* Tell MySQL that this query should not be cached anymore */
2944 query->writer()->first_query_block= NULL;
2945 query->writer(0);
2946 }
2947 double_linked_list_exclude(query_block, &queries_blocks);
2948 Query_cache_block_table *table= query_block->table(0);
2949
2950 for (TABLE_COUNTER_TYPE i= 0; i < query_block->n_tables; i++)
2951 unlink_table(table++);
2952 Query_cache_block *result_block= query->result();
2953
2954 /*
2955 The following is true when query destruction was called and no results
2956 in query . (query just registered and then abort/pack/flush called)
2957 */
2958 if (result_block != 0)
2959 {
2960 if (result_block->type != Query_cache_block::RESULT)
2961 {
2962 // removing unfinished query
2963 refused++;
2964 inserts--;
2965 }
2966 Query_cache_block *block= result_block;
2967 do
2968 {
2969 Query_cache_block *current= block;
2970 block= block->next;
2971 free_memory_block(current);
2972 } while (block != result_block);
2973 }
2974 else
2975 {
2976 // removing unfinished query
2977 refused++;
2978 inserts--;
2979 }
2980
2981 query->unlock_n_destroy();
2982 free_memory_block(query_block);
2983
2984 DBUG_VOID_RETURN;
2985 }
2986
2987
2988 /*
2989 free_query() - free query from query cache.
2990
2991 SYNOPSIS
2992 free_query()
2993 query_block Query_cache_block representing the query
2994
2995 DESCRIPTION
2996 This function will remove 'query_block' from 'queries' hash, and
2997 then call free_query_internal(), which see.
2998 */
2999
free_query(Query_cache_block * query_block)3000 void Query_cache::free_query(Query_cache_block *query_block)
3001 {
3002 DBUG_ENTER("Query_cache::free_query");
3003 DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
3004 (ulong) query_block,
3005 query_block->query()->length() ));
3006
3007 my_hash_delete(&queries,(uchar *) query_block);
3008 free_query_internal(query_block);
3009
3010 DBUG_VOID_RETURN;
3011 }
3012
3013 /*****************************************************************************
3014 Query data creation
3015 *****************************************************************************/
3016
3017 Query_cache_block *
write_block_data(size_t data_len,uchar * data,size_t header_len,Query_cache_block::block_type type,TABLE_COUNTER_TYPE ntab)3018 Query_cache::write_block_data(size_t data_len, uchar* data,
3019 size_t header_len,
3020 Query_cache_block::block_type type,
3021 TABLE_COUNTER_TYPE ntab)
3022 {
3023 size_t all_headers_len= (ALIGN_SIZE(sizeof(Query_cache_block)) +
3024 ALIGN_SIZE(ntab*sizeof(Query_cache_block_table)) +
3025 header_len);
3026 size_t len = data_len + all_headers_len;
3027 size_t align_len= ALIGN_SIZE(len);
3028 DBUG_ENTER("Query_cache::write_block_data");
3029 DBUG_PRINT("qcache", ("data: %zu, header: %zu, all header: %zu",
3030 data_len, header_len, all_headers_len));
3031 Query_cache_block *block= allocate_block(max<size_t>(align_len,
3032 min_allocation_unit),1, 0);
3033 if (block != 0)
3034 {
3035 block->type = type;
3036 block->n_tables = ntab;
3037 block->used = static_cast<ulong>(len);
3038
3039 memcpy((uchar *) block+ all_headers_len, data, data_len);
3040 }
3041 DBUG_RETURN(block);
3042 }
3043
3044
3045 my_bool
append_result_data(Query_cache_block ** current_block,ulong data_len,uchar * data,Query_cache_block * query_block)3046 Query_cache::append_result_data(Query_cache_block **current_block,
3047 ulong data_len, uchar* data,
3048 Query_cache_block *query_block)
3049 {
3050 DBUG_ENTER("Query_cache::append_result_data");
3051 DBUG_PRINT("qcache", ("append %lu bytes to 0x%lx query",
3052 data_len, (long) query_block));
3053
3054 if (query_block->query()->add(data_len) > query_cache_limit)
3055 {
3056 DBUG_PRINT("qcache", ("size limit reached %lu > %lu",
3057 query_block->query()->length(),
3058 query_cache_limit));
3059 DBUG_RETURN(0);
3060 }
3061 if (*current_block == 0)
3062 {
3063 DBUG_PRINT("qcache", ("allocated first result data block %lu", data_len));
3064 DBUG_RETURN(write_result_data(current_block, data_len, data, query_block,
3065 Query_cache_block::RES_BEG));
3066 }
3067 Query_cache_block *last_block = (*current_block)->prev;
3068
3069 DBUG_PRINT("qcache", ("lastblock 0x%lx len %lu used %lu",
3070 (ulong) last_block, last_block->length,
3071 last_block->used));
3072 my_bool success = 1;
3073 ulong last_block_free_space= last_block->length - last_block->used;
3074
3075 /*
3076 We will first allocate and write the 'tail' of data, that doesn't fit
3077 in the 'last_block'. Only if this succeeds, we will fill the last_block.
3078 This saves us a memcpy if the query doesn't fit in the query cache.
3079 */
3080
3081 // Try join blocks if physically next block is free...
3082 ulong tail = data_len - last_block_free_space;
3083 ulong append_min = get_min_append_result_data_size();
3084 if (last_block_free_space < data_len &&
3085 append_next_free_block(last_block,
3086 max(tail, append_min)))
3087 last_block_free_space = last_block->length - last_block->used;
3088 // If no space in last block (even after join) allocate new block
3089 if (last_block_free_space < data_len)
3090 {
3091 DBUG_PRINT("qcache", ("allocate new block for %lu bytes",
3092 data_len-last_block_free_space));
3093 Query_cache_block *new_block = 0;
3094 success = write_result_data(&new_block, data_len-last_block_free_space,
3095 (uchar*)(data+last_block_free_space),
3096 query_block,
3097 Query_cache_block::RES_CONT);
3098 /*
3099 new_block may be != 0 even !success (if write_result_data
3100 allocate a small block but failed to allocate continue)
3101 */
3102 if (new_block != 0)
3103 double_linked_list_join(last_block, new_block);
3104 }
3105 else
3106 {
3107 // It is success (nobody can prevent us write data)
3108 unlock();
3109 }
3110
3111 // Now finally write data to the last block
3112 if (success && last_block_free_space > 0)
3113 {
3114 ulong to_copy = min(data_len,last_block_free_space);
3115 DBUG_PRINT("qcache", ("use free space %lub at block 0x%lx to copy %lub",
3116 last_block_free_space, (ulong)last_block, to_copy));
3117 memcpy((uchar*) last_block + last_block->used, data, to_copy);
3118 last_block->used+=to_copy;
3119 }
3120 DBUG_RETURN(success);
3121 }
3122
3123
write_result_data(Query_cache_block ** result_block,ulong data_len,uchar * data,Query_cache_block * query_block,Query_cache_block::block_type type)3124 my_bool Query_cache::write_result_data(Query_cache_block **result_block,
3125 ulong data_len, uchar* data,
3126 Query_cache_block *query_block,
3127 Query_cache_block::block_type type)
3128 {
3129 DBUG_ENTER("Query_cache::write_result_data");
3130 DBUG_PRINT("qcache", ("data_len %lu",data_len));
3131
3132 /*
3133 Reserve block(s) for filling
3134 During data allocation we must have structure_guard_mutex locked.
3135 As data copy is not a fast operation, it's better if we don't have
3136 structure_guard_mutex locked during data coping.
3137 Thus we first allocate space and lock query, then unlock
3138 structure_guard_mutex and copy data.
3139 */
3140
3141 my_bool success = allocate_data_chain(result_block, data_len, query_block,
3142 type == Query_cache_block::RES_BEG);
3143 if (success)
3144 {
3145 // It is success (nobody can prevent us write data)
3146 unlock();
3147 uint headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
3148 ALIGN_SIZE(sizeof(Query_cache_result)));
3149 #ifndef EMBEDDED_LIBRARY
3150 Query_cache_block *block= *result_block;
3151 uchar *rest= data;
3152 // Now fill list of blocks that created by allocate_data_chain
3153 do
3154 {
3155 block->type = type;
3156 ulong length = block->used - headers_len;
3157 DBUG_PRINT("qcache", ("write %lu byte in block 0x%lx",length,
3158 (ulong)block));
3159 memcpy((uchar*) block+headers_len, rest, length);
3160 rest += length;
3161 block = block->next;
3162 type = Query_cache_block::RES_CONT;
3163 } while (block != *result_block);
3164 #else
3165 /*
3166 Set type of first block, emb_store_querycache_result() will handle
3167 the others.
3168 */
3169 (*result_block)->type= type;
3170 Querycache_stream qs(*result_block, headers_len);
3171 emb_store_querycache_result(&qs, (THD*)data);
3172 #endif /*!EMBEDDED_LIBRARY*/
3173 }
3174 else
3175 {
3176 if (*result_block != 0)
3177 {
3178 // Destroy list of blocks that was created & locked by lock_result_data
3179 Query_cache_block *block = *result_block;
3180 do
3181 {
3182 Query_cache_block *current = block;
3183 block = block->next;
3184 free_memory_block(current);
3185 } while (block != *result_block);
3186 *result_block = 0;
3187 /*
3188 It is not success => not unlock structure_guard_mutex (we need it to
3189 free query)
3190 */
3191 }
3192 }
3193 DBUG_PRINT("qcache", ("success %d", (int) success));
3194 DBUG_RETURN(success);
3195 }
3196
get_min_first_result_data_size()3197 inline ulong Query_cache::get_min_first_result_data_size()
3198 {
3199 if (queries_in_cache < QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER)
3200 return min_result_data_size;
3201 ulong avg_result = (query_cache_size - free_memory) / queries_in_cache;
3202 avg_result = min(avg_result, query_cache_limit);
3203 return max(min_result_data_size, avg_result);
3204 }
3205
get_min_append_result_data_size()3206 inline ulong Query_cache::get_min_append_result_data_size()
3207 {
3208 return min_result_data_size;
3209 }
3210
3211 /*
3212 Allocate one or more blocks to hold data
3213 */
allocate_data_chain(Query_cache_block ** result_block,ulong data_len,Query_cache_block * query_block,my_bool first_block_arg)3214 my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
3215 ulong data_len,
3216 Query_cache_block *query_block,
3217 my_bool first_block_arg)
3218 {
3219 ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
3220 ALIGN_SIZE(sizeof(Query_cache_result)));
3221 ulong min_size = (first_block_arg ?
3222 get_min_first_result_data_size():
3223 get_min_append_result_data_size());
3224 Query_cache_block *prev_block= NULL;
3225 Query_cache_block *new_block;
3226 DBUG_ENTER("Query_cache::allocate_data_chain");
3227 DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu",
3228 data_len, all_headers_len));
3229
3230 do
3231 {
3232 ulong len= data_len + all_headers_len;
3233 ulong align_len= ALIGN_SIZE(len);
3234
3235 if (!(new_block= allocate_block(max(min_size, align_len),
3236 min_result_data_size == 0,
3237 all_headers_len + min_result_data_size)))
3238 {
3239 DBUG_PRINT("warning", ("Can't allocate block for results"));
3240 DBUG_RETURN(FALSE);
3241 }
3242
3243 new_block->n_tables = 0;
3244 new_block->used = min(len, new_block->length);
3245 new_block->type = Query_cache_block::RES_INCOMPLETE;
3246 new_block->next = new_block->prev = new_block;
3247 Query_cache_result *header = new_block->result();
3248 header->parent(query_block);
3249
3250 DBUG_PRINT("qcache", ("Block len %lu used %lu",
3251 new_block->length, new_block->used));
3252
3253 if (prev_block)
3254 double_linked_list_join(prev_block, new_block);
3255 else
3256 *result_block= new_block;
3257 if (new_block->length >= len)
3258 break;
3259
3260 /*
3261 We got less memory then we need (no big memory blocks) =>
3262 Continue to allocated more blocks until we got everything we need.
3263 */
3264 data_len= len - new_block->length;
3265 prev_block= new_block;
3266 } while (1);
3267
3268 DBUG_RETURN(TRUE);
3269 }
3270
3271 /*****************************************************************************
3272 Tables management
3273 *****************************************************************************/
3274
3275 /*
3276 Invalidate the first table in the table_list
3277 */
3278
invalidate_table(THD * thd,TABLE_LIST * table_list)3279 void Query_cache::invalidate_table(THD *thd, TABLE_LIST *table_list)
3280 {
3281 if (table_list->table != 0)
3282 invalidate_table(thd, table_list->table); // Table is open
3283 else
3284 {
3285 const char *key;
3286 size_t key_length;
3287 key_length= get_table_def_key(table_list, &key);
3288
3289 // We don't store temporary tables => no key_length+=4 ...
3290 invalidate_table(thd, (uchar *)key, key_length);
3291 }
3292 }
3293
invalidate_table(THD * thd,TABLE * table)3294 void Query_cache::invalidate_table(THD *thd, TABLE *table)
3295 {
3296 invalidate_table(thd, (uchar*) table->s->table_cache_key.str,
3297 table->s->table_cache_key.length);
3298 }
3299
invalidate_table(THD * thd,uchar * key,size_t key_length)3300 void Query_cache::invalidate_table(THD *thd, uchar * key, size_t key_length)
3301 {
3302 DEBUG_SYNC(thd, "wait_in_query_cache_invalidate1");
3303
3304 /*
3305 Lock the query cache and queue all invalidation attempts to avoid
3306 the risk of a race between invalidation, cache inserts and flushes.
3307 */
3308 lock();
3309
3310 DEBUG_SYNC(thd, "wait_in_query_cache_invalidate2");
3311
3312 if (query_cache_size > 0)
3313 invalidate_table_internal(thd, key, key_length);
3314
3315 unlock();
3316 }
3317
3318
3319 /**
3320 Try to locate and invalidate a table by name.
3321 The caller must ensure that no other thread is trying to work with
3322 the query cache when this function is executed.
3323
3324 @pre structure_guard_mutex is acquired or LOCKED is set.
3325 */
3326
3327 void
invalidate_table_internal(THD * thd,uchar * key,size_t key_length)3328 Query_cache::invalidate_table_internal(THD *thd, uchar *key, size_t key_length)
3329 {
3330 Query_cache_block *table_block=
3331 (Query_cache_block*)my_hash_search(&tables, key, key_length);
3332 if (table_block)
3333 {
3334 Query_cache_block_table *list_root= table_block->table(0);
3335 invalidate_query_block_list(thd, list_root);
3336 }
3337 }
3338
3339 /**
3340 Invalidate a linked list of query cache blocks.
3341
3342 Each block tries to acquire a block level lock before
3343 free_query is a called. This function will in turn affect
3344 related table- and result-blocks.
3345
3346 @param[in,out] thd Thread context.
3347 @param[in,out] list_root A pointer to a circular list of query blocks.
3348
3349 */
3350
3351 void
invalidate_query_block_list(THD * thd,Query_cache_block_table * list_root)3352 Query_cache::invalidate_query_block_list(THD *thd,
3353 Query_cache_block_table *list_root)
3354 {
3355 while (list_root->next != list_root)
3356 {
3357 Query_cache_block *query_block= list_root->next->block();
3358 BLOCK_LOCK_WR(query_block);
3359 free_query(query_block);
3360 }
3361 }
3362
3363 /*
3364 Register given table list begining with given position in tables table of
3365 block
3366
3367 SYNOPSIS
3368 Query_cache::register_tables_from_list
3369 tables_used given table list
3370 counter number current position in table of tables of block
3371 block_table pointer to current position in tables table of block
3372
3373 RETURN
3374 0 error
3375 number of next position of table entry in table of tables of block
3376 */
3377
3378 TABLE_COUNTER_TYPE
register_tables_from_list(TABLE_LIST * tables_used,TABLE_COUNTER_TYPE counter,Query_cache_block_table * block_table)3379 Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
3380 TABLE_COUNTER_TYPE counter,
3381 Query_cache_block_table *block_table)
3382 {
3383 TABLE_COUNTER_TYPE n;
3384 DBUG_ENTER("Query_cache::register_tables_from_list");
3385 for (n= counter;
3386 tables_used;
3387 tables_used= tables_used->next_global, n++, block_table++)
3388 {
3389 if (tables_used->is_derived())
3390 {
3391 DBUG_PRINT("qcache", ("derived table skipped"));
3392 n--;
3393 block_table--;
3394 continue;
3395 }
3396 block_table->n= n;
3397 if (tables_used->is_view())
3398 {
3399 const char *key;
3400 size_t key_length;
3401 DBUG_PRINT("qcache", ("view: %s db: %s",
3402 tables_used->view_name.str,
3403 tables_used->view_db.str));
3404 key_length= get_table_def_key(tables_used, &key);
3405 /*
3406 There are not callback function for for VIEWs
3407 */
3408 if (!insert_table(key_length, key, block_table,
3409 tables_used->view_db.length + 1,
3410 HA_CACHE_TBL_NONTRANSACT, 0, 0))
3411 DBUG_RETURN(0);
3412 /*
3413 We do not need to register view tables here because they are already
3414 present in the global list.
3415 */
3416 }
3417 else
3418 {
3419 DBUG_PRINT("qcache",
3420 ("table: %s db: %s openinfo: 0x%lx keylen: %lu key: 0x%lx",
3421 tables_used->table->s->table_name.str,
3422 tables_used->table->s->table_cache_key.str,
3423 (ulong) tables_used->table,
3424 (ulong) tables_used->table->s->table_cache_key.length,
3425 (ulong) tables_used->table->s->table_cache_key.str));
3426
3427 if (!insert_table(tables_used->table->s->table_cache_key.length,
3428 tables_used->table->s->table_cache_key.str,
3429 block_table,
3430 tables_used->db_length,
3431 tables_used->table->file->table_cache_type(),
3432 tables_used->callback_func,
3433 tables_used->engine_data))
3434 DBUG_RETURN(0);
3435
3436 /*
3437 XXX FIXME: Some generic mechanism is required here instead of this
3438 MYISAMMRG-specific implementation.
3439 */
3440 if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM)
3441 {
3442 ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
3443 MYRG_INFO *file = handler->myrg_info();
3444 for (MYRG_TABLE *table = file->open_tables;
3445 table != file->end_table ;
3446 table++)
3447 {
3448 char key[MAX_DBKEY_LENGTH];
3449 size_t db_length;
3450 size_t key_length= filename_2_table_key(key, table->table->filename,
3451 &db_length);
3452 (++block_table)->n= ++n;
3453 /*
3454 There are not callback function for for MyISAM, and engine data
3455 */
3456 if (!insert_table(key_length, key, block_table,
3457 db_length,
3458 tables_used->table->file->table_cache_type(),
3459 0, 0))
3460 DBUG_RETURN(0);
3461 }
3462 }
3463 }
3464 }
3465 DBUG_RETURN(n - counter);
3466 }
3467
3468 /*
3469 Store all used tables
3470
3471 SYNOPSIS
3472 register_all_tables()
3473 block Store tables in this block
3474 tables_used List if used tables
3475 tables_arg Not used ?
3476 */
3477
register_all_tables(Query_cache_block * block,TABLE_LIST * tables_used,TABLE_COUNTER_TYPE tables_arg)3478 my_bool Query_cache::register_all_tables(Query_cache_block *block,
3479 TABLE_LIST *tables_used,
3480 TABLE_COUNTER_TYPE tables_arg)
3481 {
3482 TABLE_COUNTER_TYPE n;
3483 DBUG_PRINT("qcache", ("register tables block 0x%lx, n %d, header %x",
3484 (ulong) block, (int) tables_arg,
3485 (int) ALIGN_SIZE(sizeof(Query_cache_block))));
3486
3487 Query_cache_block_table *block_table = block->table(0);
3488
3489 n= register_tables_from_list(tables_used, 0, block_table);
3490
3491 if (n==0)
3492 {
3493 /* Unlink the tables we allocated above */
3494 for (Query_cache_block_table *tmp = block->table(0) ;
3495 tmp != block_table;
3496 tmp++)
3497 unlink_table(tmp);
3498 }
3499 return MY_TEST(n);
3500 }
3501
3502
3503 /**
3504 Insert used table name into the cache.
3505
3506 @return Error status
3507 @retval FALSE On error
3508 @retval TRUE On success
3509 */
3510
3511 my_bool
insert_table(size_t key_len,const char * key,Query_cache_block_table * node,size_t db_length,uint8 cache_type,qc_engine_callback callback,ulonglong engine_data)3512 Query_cache::insert_table(size_t key_len, const char *key,
3513 Query_cache_block_table *node,
3514 size_t db_length, uint8 cache_type,
3515 qc_engine_callback callback,
3516 ulonglong engine_data)
3517 {
3518 DBUG_ENTER("Query_cache::insert_table");
3519 DBUG_PRINT("qcache", ("insert table node 0x%lx, len %zu",
3520 (ulong)node, key_len));
3521
3522 THD *thd= current_thd;
3523
3524 Query_cache_block *table_block=
3525 (Query_cache_block *) my_hash_search(&tables, (uchar*) key, key_len);
3526
3527 if (table_block &&
3528 table_block->table()->engine_data() != engine_data)
3529 {
3530 DBUG_PRINT("qcache",
3531 ("Handler require invalidation queries of %s.%s %lu-%lu",
3532 table_block->table()->db(),
3533 table_block->table()->table(),
3534 (ulong) engine_data,
3535 (ulong) table_block->table()->engine_data()));
3536 /*
3537 as far as we delete all queries with this table, table block will be
3538 deleted, too
3539 */
3540 {
3541 Query_cache_block_table *list_root= table_block->table(0);
3542 invalidate_query_block_list(thd, list_root);
3543 }
3544
3545 table_block= 0;
3546 }
3547
3548 if (table_block == 0)
3549 {
3550 DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
3551 (ulong) key, (int) key_len));
3552 table_block= write_block_data(key_len, (uchar*) key,
3553 ALIGN_SIZE(sizeof(Query_cache_table)),
3554 Query_cache_block::TABLE, 1);
3555 if (table_block == 0)
3556 {
3557 DBUG_PRINT("qcache", ("Can't write table name to cache"));
3558 DBUG_RETURN(0);
3559 }
3560 Query_cache_table *header= table_block->table();
3561 double_linked_list_simple_include(table_block,
3562 &tables_blocks);
3563 /*
3564 First node in the Query_cache_block_table-chain is the table-type
3565 block. This block will only have one Query_cache_block_table (n=0).
3566 */
3567 Query_cache_block_table *list_root= table_block->table(0);
3568 list_root->n= 0;
3569
3570 /*
3571 The node list is circular in nature.
3572 */
3573 list_root->next= list_root->prev= list_root;
3574
3575 if (my_hash_insert(&tables, (const uchar *) table_block))
3576 {
3577 DBUG_PRINT("qcache", ("Can't insert table to hash"));
3578 // write_block_data return locked block
3579 free_memory_block(table_block);
3580 DBUG_RETURN(0);
3581 }
3582 char *db= header->db();
3583 header->table(db + db_length + 1);
3584 header->key_length(key_len);
3585 header->type(cache_type);
3586 header->callback(callback);
3587 header->engine_data(engine_data);
3588
3589 /*
3590 We insert this table without the assumption that it isn't refrenenced by
3591 any queries.
3592 */
3593 header->m_cached_query_count= 0;
3594 }
3595
3596 /*
3597 Table is now in the cache; link the table_block-node associated
3598 with the currently processed query into the chain of queries depending
3599 on the cached table.
3600 */
3601 Query_cache_block_table *list_root= table_block->table(0);
3602 node->next= list_root->next;
3603 list_root->next= node;
3604 node->next->prev= node;
3605 node->prev= list_root;
3606 node->parent= table_block->table();
3607 /*
3608 Increase the counter to keep track on how long this chain
3609 of queries is.
3610 */
3611 Query_cache_table *table_block_data= table_block->table();
3612 table_block_data->m_cached_query_count++;
3613 DBUG_RETURN(1);
3614 }
3615
3616
unlink_table(Query_cache_block_table * node)3617 void Query_cache::unlink_table(Query_cache_block_table *node)
3618 {
3619 DBUG_ENTER("Query_cache::unlink_table");
3620 node->prev->next= node->next;
3621 node->next->prev= node->prev;
3622 Query_cache_block_table *neighbour= node->next;
3623 Query_cache_table *table_block_data= node->parent;
3624 table_block_data->m_cached_query_count--;
3625
3626 assert(table_block_data->m_cached_query_count >= 0);
3627
3628 if (neighbour->next == neighbour)
3629 {
3630 assert(table_block_data->m_cached_query_count == 0);
3631 /*
3632 If neighbor is root of list, the list is empty.
3633 The root of the list is always a table-type block
3634 which contain exactly one Query_cache_block_table
3635 node object, thus we can use the block() method
3636 to calculate the Query_cache_block address.
3637 */
3638 Query_cache_block *table_block= neighbour->block();
3639 double_linked_list_exclude(table_block,
3640 &tables_blocks);
3641 my_hash_delete(&tables,(uchar *) table_block);
3642 free_memory_block(table_block);
3643 }
3644 DBUG_VOID_RETURN;
3645 }
3646
3647 /*****************************************************************************
3648 Free memory management
3649 *****************************************************************************/
3650
3651 Query_cache_block *
allocate_block(size_t len,my_bool not_less,size_t minimum)3652 Query_cache::allocate_block(size_t len, my_bool not_less, size_t minimum)
3653 {
3654 DBUG_ENTER("Query_cache::allocate_block");
3655 DBUG_PRINT("qcache", ("len %zu, not less %d, min %zu",
3656 len, not_less, minimum));
3657
3658 if (len >= min(query_cache_size, query_cache_limit))
3659 {
3660 DBUG_PRINT("qcache", ("Query cache hase only %lu memory and limit %lu",
3661 query_cache_size, query_cache_limit));
3662 DBUG_RETURN(0); // in any case we don't have such piece of memory
3663 }
3664
3665 /* Free old queries until we have enough memory to store this block */
3666 Query_cache_block *block;
3667 do
3668 {
3669 block= get_free_block(len, not_less, minimum);
3670 }
3671 while (block == 0 && !free_old_query());
3672
3673 if (block != 0) // If we found a suitable block
3674 {
3675 if (block->length >= ALIGN_SIZE(len) + min_allocation_unit)
3676 split_block(block,ALIGN_SIZE(len));
3677 }
3678
3679 DBUG_RETURN(block);
3680 }
3681
3682
3683 Query_cache_block *
get_free_block(size_t len,my_bool not_less,size_t min)3684 Query_cache::get_free_block(size_t len, my_bool not_less, size_t min)
3685 {
3686 Query_cache_block *block = 0, *first = 0;
3687 DBUG_ENTER("Query_cache::get_free_block");
3688 DBUG_PRINT("qcache",("length %zu, not_less %d, min %zu", len,
3689 (int)not_less, min));
3690
3691 /* Find block with minimal size > len */
3692 uint start = find_bin(len);
3693 // try matching bin
3694 if (bins[start].number != 0)
3695 {
3696 Query_cache_block *list = bins[start].free_blocks;
3697 if (list->prev->length >= len) // check block with max size
3698 {
3699 first = list;
3700 uint n = 0;
3701 while ( n < QUERY_CACHE_MEM_BIN_TRY &&
3702 first->length < len) //we don't need irst->next != list
3703 {
3704 first=first->next;
3705 n++;
3706 }
3707 if (first->length >= len)
3708 block=first;
3709 else // we don't need if (first->next != list)
3710 {
3711 n = 0;
3712 block = list->prev;
3713 while (n < QUERY_CACHE_MEM_BIN_TRY &&
3714 block->length > len)
3715 {
3716 block=block->prev;
3717 n++;
3718 }
3719 if (block->length < len)
3720 block=block->next;
3721 }
3722 }
3723 else
3724 first = list->prev;
3725 }
3726 if (block == 0 && start > 0)
3727 {
3728 DBUG_PRINT("qcache",("Try bins with bigger block size"));
3729 // Try more big bins
3730 int i = start - 1;
3731 while (i > 0 && bins[i].number == 0)
3732 i--;
3733 if (bins[i].number > 0)
3734 block = bins[i].free_blocks;
3735 }
3736
3737 // If no big blocks => try less size (if it is possible)
3738 if (block == 0 && ! not_less)
3739 {
3740 DBUG_PRINT("qcache",("Try to allocate a smaller block"));
3741 if (first != 0 && first->length > min)
3742 block = first;
3743 else
3744 {
3745 uint i = start + 1;
3746 /* bins[mem_bin_num].number contains 1 for easy end test */
3747 for (i= start+1 ; bins[i].number == 0 ; i++) ;
3748 if (i < mem_bin_num && bins[i].free_blocks->prev->length >= min)
3749 block = bins[i].free_blocks->prev;
3750 }
3751 }
3752 if (block != 0)
3753 exclude_from_free_memory_list(block);
3754
3755 DBUG_PRINT("qcache",("getting block 0x%lx", (ulong) block));
3756 DBUG_RETURN(block);
3757 }
3758
3759
free_memory_block(Query_cache_block * block)3760 void Query_cache::free_memory_block(Query_cache_block *block)
3761 {
3762 DBUG_ENTER("Query_cache::free_memory_block");
3763 block->used=0;
3764 block->type= Query_cache_block::FREE; // mark block as free in any case
3765 DBUG_PRINT("qcache",
3766 ("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
3767 (ulong) first_block, (ulong) block, (ulong) block->pnext,
3768 (ulong) block->pprev));
3769
3770 if (block->pnext != first_block && block->pnext->is_free())
3771 block = join_free_blocks(block, block->pnext);
3772 if (block != first_block && block->pprev->is_free())
3773 block = join_free_blocks(block->pprev, block->pprev);
3774 insert_into_free_memory_list(block);
3775 DBUG_VOID_RETURN;
3776 }
3777
3778
split_block(Query_cache_block * block,ulong len)3779 void Query_cache::split_block(Query_cache_block *block, ulong len)
3780 {
3781 DBUG_ENTER("Query_cache::split_block");
3782 Query_cache_block *new_block = (Query_cache_block*)(((uchar*) block)+len);
3783
3784 new_block->init(block->length - len);
3785 total_blocks++;
3786 block->length=len;
3787 new_block->pnext = block->pnext;
3788 block->pnext = new_block;
3789 new_block->pprev = block;
3790 new_block->pnext->pprev = new_block;
3791
3792 if (block->type == Query_cache_block::FREE)
3793 {
3794 // if block was free then it already joined with all free neighbours
3795 insert_into_free_memory_list(new_block);
3796 }
3797 else
3798 free_memory_block(new_block);
3799
3800 DBUG_PRINT("qcache", ("split 0x%lx (%lu) new 0x%lx",
3801 (ulong) block, len, (ulong) new_block));
3802 DBUG_VOID_RETURN;
3803 }
3804
3805
3806 Query_cache_block *
join_free_blocks(Query_cache_block * first_block_arg,Query_cache_block * block_in_list)3807 Query_cache::join_free_blocks(Query_cache_block *first_block_arg,
3808 Query_cache_block *block_in_list)
3809 {
3810 Query_cache_block *second_block;
3811 DBUG_ENTER("Query_cache::join_free_blocks");
3812 DBUG_PRINT("qcache",
3813 ("join first 0x%lx, pnext 0x%lx, in list 0x%lx",
3814 (ulong) first_block_arg, (ulong) first_block_arg->pnext,
3815 (ulong) block_in_list));
3816
3817 exclude_from_free_memory_list(block_in_list);
3818 second_block = first_block_arg->pnext;
3819 // May be was not free block
3820 second_block->used=0;
3821 second_block->destroy();
3822 total_blocks--;
3823
3824 first_block_arg->length += second_block->length;
3825 first_block_arg->pnext = second_block->pnext;
3826 second_block->pnext->pprev = first_block_arg;
3827
3828 DBUG_RETURN(first_block_arg);
3829 }
3830
3831
append_next_free_block(Query_cache_block * block,ulong add_size)3832 my_bool Query_cache::append_next_free_block(Query_cache_block *block,
3833 ulong add_size)
3834 {
3835 Query_cache_block *next_block = block->pnext;
3836 DBUG_ENTER("Query_cache::append_next_free_block");
3837 DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
3838 add_size));
3839
3840 if (next_block != first_block && next_block->is_free())
3841 {
3842 ulong old_len = block->length;
3843 exclude_from_free_memory_list(next_block);
3844 next_block->destroy();
3845 total_blocks--;
3846
3847 block->length += next_block->length;
3848 block->pnext = next_block->pnext;
3849 next_block->pnext->pprev = block;
3850
3851 if (block->length > ALIGN_SIZE(old_len + add_size) + min_allocation_unit)
3852 split_block(block,ALIGN_SIZE(old_len + add_size));
3853 DBUG_PRINT("exit", ("block was appended"));
3854 DBUG_RETURN(1);
3855 }
3856 DBUG_RETURN(0);
3857 }
3858
3859
exclude_from_free_memory_list(Query_cache_block * free_block)3860 void Query_cache::exclude_from_free_memory_list(Query_cache_block *free_block)
3861 {
3862 DBUG_ENTER("Query_cache::exclude_from_free_memory_list");
3863 Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
3864 free_block->data());
3865 double_linked_list_exclude(free_block, &bin->free_blocks);
3866 bin->number--;
3867 free_memory-=free_block->length;
3868 free_memory_blocks--;
3869 DBUG_PRINT("qcache",("exclude block 0x%lx, bin 0x%lx", (ulong) free_block,
3870 (ulong) bin));
3871 DBUG_VOID_RETURN;
3872 }
3873
insert_into_free_memory_list(Query_cache_block * free_block)3874 void Query_cache::insert_into_free_memory_list(Query_cache_block *free_block)
3875 {
3876 DBUG_ENTER("Query_cache::insert_into_free_memory_list");
3877 uint idx = find_bin(free_block->length);
3878 insert_into_free_memory_sorted_list(free_block, &bins[idx].free_blocks);
3879 /*
3880 We have enough memory in block for storing bin reference due to
3881 min_allocation_unit choice
3882 */
3883 Query_cache_memory_bin **bin_ptr = ((Query_cache_memory_bin**)
3884 free_block->data());
3885 *bin_ptr = bins+idx;
3886 (*bin_ptr)->number++;
3887 DBUG_PRINT("qcache",("insert block 0x%lx, bin[%d] 0x%lx",
3888 (ulong) free_block, idx, (ulong) *bin_ptr));
3889 DBUG_VOID_RETURN;
3890 }
3891
find_bin(size_t size)3892 uint Query_cache::find_bin(size_t size)
3893 {
3894 DBUG_ENTER("Query_cache::find_bin");
3895 // Binary search
3896 int left = 0, right = mem_bin_steps;
3897 do
3898 {
3899 int middle = (left + right) / 2;
3900 if (steps[middle].size > size)
3901 left = middle+1;
3902 else
3903 right = middle;
3904 } while (left < right);
3905 if (left == 0)
3906 {
3907 // first bin not subordinate of common rules
3908 DBUG_PRINT("qcache", ("first bin (# 0), size %zu",size));
3909 DBUG_RETURN(0);
3910 }
3911 uint bin = steps[left].idx -
3912 (uint)((size - steps[left].size)/steps[left].increment);
3913
3914 DBUG_PRINT("qcache", ("bin %u step %u, size %zu step size %lu",
3915 bin, left, size, steps[left].size));
3916 DBUG_RETURN(bin);
3917 }
3918
3919
3920 /*****************************************************************************
3921 Lists management
3922 *****************************************************************************/
3923
move_to_query_list_end(Query_cache_block * query_block)3924 void Query_cache::move_to_query_list_end(Query_cache_block *query_block)
3925 {
3926 DBUG_ENTER("Query_cache::move_to_query_list_end");
3927 double_linked_list_exclude(query_block, &queries_blocks);
3928 double_linked_list_simple_include(query_block, &queries_blocks);
3929 DBUG_VOID_RETURN;
3930 }
3931
3932
insert_into_free_memory_sorted_list(Query_cache_block * new_block,Query_cache_block ** list)3933 void Query_cache::insert_into_free_memory_sorted_list(Query_cache_block *
3934 new_block,
3935 Query_cache_block **
3936 list)
3937 {
3938 DBUG_ENTER("Query_cache::insert_into_free_memory_sorted_list");
3939 /*
3940 list sorted by size in ascendant order, because we need small blocks
3941 more frequently than bigger ones
3942 */
3943
3944 new_block->used = 0;
3945 new_block->n_tables = 0;
3946 new_block->type = Query_cache_block::FREE;
3947
3948 if (*list == 0)
3949 {
3950 *list = new_block->next=new_block->prev=new_block;
3951 DBUG_PRINT("qcache", ("inserted into empty list"));
3952 }
3953 else
3954 {
3955 Query_cache_block *point = *list;
3956 if (point->length >= new_block->length)
3957 {
3958 point = point->prev;
3959 *list = new_block;
3960 }
3961 else
3962 {
3963 /* Find right position in sorted list to put block */
3964 while (point->next != *list &&
3965 point->next->length < new_block->length)
3966 point=point->next;
3967 }
3968 new_block->prev = point;
3969 new_block->next = point->next;
3970 new_block->next->prev = new_block;
3971 point->next = new_block;
3972 }
3973 free_memory+=new_block->length;
3974 free_memory_blocks++;
3975 DBUG_VOID_RETURN;
3976 }
3977
3978
3979 void
double_linked_list_simple_include(Query_cache_block * point,Query_cache_block ** list_pointer)3980 Query_cache::double_linked_list_simple_include(Query_cache_block *point,
3981 Query_cache_block **
3982 list_pointer)
3983 {
3984 DBUG_ENTER("Query_cache::double_linked_list_simple_include");
3985 DBUG_PRINT("qcache", ("including block 0x%lx", (ulong) point));
3986 if (*list_pointer == 0)
3987 *list_pointer=point->next=point->prev=point;
3988 else
3989 {
3990 // insert to the end of list
3991 point->next = (*list_pointer);
3992 point->prev = (*list_pointer)->prev;
3993 point->prev->next = point;
3994 (*list_pointer)->prev = point;
3995 }
3996 DBUG_VOID_RETURN;
3997 }
3998
3999 void
double_linked_list_exclude(Query_cache_block * point,Query_cache_block ** list_pointer)4000 Query_cache::double_linked_list_exclude(Query_cache_block *point,
4001 Query_cache_block **list_pointer)
4002 {
4003 DBUG_ENTER("Query_cache::double_linked_list_exclude");
4004 DBUG_PRINT("qcache", ("excluding block 0x%lx, list 0x%lx",
4005 (ulong) point, (ulong) list_pointer));
4006 if (point->next == point)
4007 *list_pointer = 0; // empty list
4008 else
4009 {
4010 point->next->prev = point->prev;
4011 point->prev->next = point->next;
4012 /*
4013 If the root is removed; select a new root
4014 */
4015 if (point == *list_pointer)
4016 *list_pointer= point->next;
4017 }
4018 DBUG_VOID_RETURN;
4019 }
4020
4021
double_linked_list_join(Query_cache_block * head_tail,Query_cache_block * tail_head)4022 void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
4023 Query_cache_block *tail_head)
4024 {
4025 Query_cache_block *head_head = head_tail->next,
4026 *tail_tail = tail_head->prev;
4027 head_head->prev = tail_tail;
4028 head_tail->next = tail_head;
4029 tail_head->prev = head_tail;
4030 tail_tail->next = head_head;
4031 }
4032
4033 /*****************************************************************************
4034 Query
4035 *****************************************************************************/
4036
4037 /*
4038 Collect information about table types, check that tables are cachable and
4039 count them
4040
4041 SYNOPSIS
4042 process_and_count_tables()
4043 tables_used table list for processing
4044 tables_type pointer to variable for table types collection
4045
4046 RETURN
4047 0 error
4048 >0 number of tables
4049 */
4050
4051 TABLE_COUNTER_TYPE
process_and_count_tables(THD * thd,TABLE_LIST * tables_used,uint8 * tables_type)4052 Query_cache::process_and_count_tables(THD *thd, TABLE_LIST *tables_used,
4053 uint8 *tables_type)
4054 {
4055 DBUG_ENTER("process_and_count_tables");
4056 TABLE_COUNTER_TYPE table_count = 0;
4057 for (; tables_used; tables_used= tables_used->next_global)
4058 {
4059 table_count++;
4060 #ifndef NO_EMBEDDED_ACCESS_CHECKS
4061 /*
4062 Disable any attempt to store this statement if there are
4063 column level grants on any referenced tables.
4064 The grant.want_privileges flag was set to 1 in the
4065 check_grant() function earlier if the TABLE_LIST object
4066 had any associated column privileges.
4067
4068 We need to check that the TABLE_LIST object isn't part
4069 of a VIEW definition because we want to be able to cache
4070 views.
4071
4072 Tables underlying a MERGE table does not have useful privilege
4073 information in their grant objects, so skip these tables from the test.
4074 */
4075 if (tables_used->belong_to_view == NULL &&
4076 (!tables_used->parent_l ||
4077 tables_used->parent_l->table->file->ht->db_type != DB_TYPE_MRG_MYISAM))
4078 {
4079 assert((SELECT_ACL & ~tables_used->grant.privilege) ==
4080 tables_used->grant.want_privilege);
4081 if ((tables_used->grant.privilege & SELECT_ACL) == 0)
4082 {
4083 DBUG_PRINT("qcache", ("Don't cache statement as it refers to "
4084 "tables with column privileges."));
4085 thd->lex->safe_to_cache_query= 0;
4086 DBUG_RETURN(0);
4087 }
4088 }
4089 #endif
4090 if (tables_used->is_view())
4091 {
4092 DBUG_PRINT("qcache", ("view: %s db: %s",
4093 tables_used->view_name.str,
4094 tables_used->view_db.str));
4095 *tables_type|= HA_CACHE_TBL_NONTRANSACT;
4096 }
4097 else
4098 {
4099 if (tables_used->is_derived())
4100 {
4101 DBUG_PRINT("qcache", ("table: %s", tables_used->alias));
4102 table_count--;
4103 DBUG_PRINT("qcache", ("derived table skipped"));
4104 continue;
4105 }
4106 DBUG_PRINT("qcache", ("table: %s db: %s type: %u",
4107 tables_used->table->s->table_name.str,
4108 tables_used->table->s->db.str,
4109 tables_used->table->s->db_type()->db_type));
4110 *tables_type|= tables_used->table->file->table_cache_type();
4111
4112 /*
4113 table_alias_charset used here because it depends of
4114 lower_case_table_names variable
4115 */
4116 if (tables_used->table->s->tmp_table != NO_TMP_TABLE ||
4117 (*tables_type & HA_CACHE_TBL_NOCACHE) ||
4118 (tables_used->db_length == 5 &&
4119 my_strnncoll(table_alias_charset,
4120 (uchar*)tables_used->table->s->table_cache_key.str, 6,
4121 (uchar*)"mysql",6) == 0))
4122 {
4123 DBUG_PRINT("qcache",
4124 ("select not cacheable: temporary, system or "
4125 "other non-cacheable table(s)"));
4126 DBUG_RETURN(0);
4127 }
4128 /*
4129 XXX FIXME: Some generic mechanism is required here instead of this
4130 MYISAMMRG-specific implementation.
4131 */
4132 if (tables_used->table->s->db_type()->db_type == DB_TYPE_MRG_MYISAM)
4133 {
4134 ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
4135 MYRG_INFO *file = handler->myrg_info();
4136 table_count+= (file->end_table - file->open_tables);
4137 }
4138 }
4139 }
4140 DBUG_RETURN(table_count);
4141 }
4142
4143
4144 /*
4145 If query is cacheable return number tables in query
4146 (query without tables are not cached)
4147 */
4148
4149 TABLE_COUNTER_TYPE
is_cacheable(THD * thd,LEX * lex,TABLE_LIST * tables_used,uint8 * tables_type)4150 Query_cache::is_cacheable(THD *thd, LEX *lex,
4151 TABLE_LIST *tables_used, uint8 *tables_type)
4152 {
4153 TABLE_COUNTER_TYPE table_count;
4154 DBUG_ENTER("Query_cache::is_cacheable");
4155
4156 if (lex->sql_command == SQLCOM_SELECT &&
4157 lex->safe_to_cache_query &&
4158 !lex->describe &&
4159 (thd->variables.query_cache_type == 1 ||
4160 (thd->variables.query_cache_type == 2 &&
4161 (lex->select_lex->active_options() & OPTION_TO_QUERY_CACHE))))
4162 {
4163 DBUG_PRINT("qcache", ("options: %lx %lx type: %u",
4164 (long) OPTION_TO_QUERY_CACHE,
4165 (long) lex->select_lex->active_options(),
4166 (int) thd->variables.query_cache_type));
4167
4168 if (!(table_count= process_and_count_tables(thd, tables_used,
4169 tables_type)))
4170 DBUG_RETURN(0);
4171
4172 if (thd->in_multi_stmt_transaction_mode() &&
4173 ((*tables_type)&HA_CACHE_TBL_TRANSACT))
4174 {
4175 DBUG_PRINT("qcache", ("not in autocommin mode"));
4176 DBUG_RETURN(0);
4177 }
4178 DBUG_PRINT("qcache", ("select is using %zu tables", table_count));
4179 DBUG_RETURN(table_count);
4180 }
4181
4182 DBUG_PRINT("qcache",
4183 ("not interesting query: %d or not cacheable, options %lx %lx type: %u",
4184 (int) lex->sql_command,
4185 (long) OPTION_TO_QUERY_CACHE,
4186 (long) lex->select_lex->active_options(),
4187 (int) thd->variables.query_cache_type));
4188 DBUG_RETURN(0);
4189 }
4190
4191 /*
4192 Check handler allowance to cache query with these tables
4193
4194 SYNOPSYS
4195 Query_cache::ask_handler_allowance()
4196 thd - thread handlers
4197 tables_used - tables list used in query
4198
4199 RETURN
4200 0 - caching allowed
4201 1 - caching disallowed
4202 */
ask_handler_allowance(THD * thd,TABLE_LIST * tables_used)4203 my_bool Query_cache::ask_handler_allowance(THD *thd,
4204 TABLE_LIST *tables_used)
4205 {
4206 DBUG_ENTER("Query_cache::ask_handler_allowance");
4207
4208 for (; tables_used; tables_used= tables_used->next_global)
4209 {
4210 TABLE *table;
4211 handler *handler;
4212 if (!(table= tables_used->table))
4213 continue;
4214 handler= table->file;
4215 // Allow caching of queries with materialized derived tables or views
4216 if (tables_used->uses_materialization())
4217 {
4218 /*
4219 Skip the derived table itself, but process its underlying tables and
4220 other tables that follow.
4221 */
4222 continue;
4223 }
4224
4225 /*
4226 @todo: I think this code can be skipped, anyway it is dead now!
4227 We're skipping a special case here (MERGE VIEW on top of a TEMPTABLE
4228 view). This is MyISAMly safe because we know it's not a user-created
4229 TEMPTABLE as those are guarded against in
4230 Query_cache::process_and_count_tables(), and schema-tables clear
4231 safe_to_cache_query. This implies that nobody else will change our
4232 TEMPTABLE while we're using it, so calling register_query_cache_table()
4233 in MyISAM to check on it is pointless. Finally, we should see the
4234 TEMPTABLE view again in a subsequent iteration, anyway.
4235 */
4236 if (tables_used->is_view() && tables_used->is_merged() &&
4237 table->s->get_table_ref_type() == TABLE_REF_TMP_TABLE)
4238 {
4239 assert(false);
4240 continue;
4241 }
4242 if (!handler->register_query_cache_table(thd,
4243 table->s->normalized_path.str,
4244 table->s->normalized_path.length,
4245 &tables_used->callback_func,
4246 &tables_used->engine_data))
4247 {
4248 DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
4249 tables_used->db, tables_used->alias));
4250 thd->lex->safe_to_cache_query= 0; // Don't try to cache this
4251 DBUG_RETURN(1);
4252 }
4253 }
4254 DBUG_RETURN(0);
4255 }
4256
4257
4258 /*****************************************************************************
4259 Packing
4260 *****************************************************************************/
4261
4262
4263 /**
4264 Rearrange all memory blocks so that free memory joins at the
4265 'bottom' of the allocated memory block containing all cache data.
4266 @see Query_cache::pack(ulong join_limit, uint iteration_limit)
4267 */
4268
pack_cache()4269 void Query_cache::pack_cache()
4270 {
4271 DBUG_ENTER("Query_cache::pack_cache");
4272
4273 DBUG_EXECUTE("check_querycache", check_integrity(CALLER_HOLDS_LOCK););
4274
4275 uchar *border = 0;
4276 Query_cache_block *before = 0;
4277 ulong gap = 0;
4278 my_bool ok = 1;
4279 Query_cache_block *block = first_block;
4280 DUMP(this);
4281
4282 if (first_block)
4283 {
4284 do
4285 {
4286 Query_cache_block *next=block->pnext;
4287 ok = move_by_type(&border, &before, &gap, block);
4288 block = next;
4289 } while (ok && block != first_block);
4290
4291 if (border != 0)
4292 {
4293 Query_cache_block *new_block = (Query_cache_block *) border;
4294 new_block->init(gap);
4295 total_blocks++;
4296 new_block->pnext = before->pnext;
4297 before->pnext = new_block;
4298 new_block->pprev = before;
4299 new_block->pnext->pprev = new_block;
4300 insert_into_free_memory_list(new_block);
4301 }
4302 DUMP(this);
4303 }
4304
4305 DBUG_EXECUTE("check_querycache", check_integrity(CALLER_HOLDS_LOCK););
4306 DBUG_VOID_RETURN;
4307 }
4308
4309
move_by_type(uchar ** border,Query_cache_block ** before,ulong * gap,Query_cache_block * block)4310 my_bool Query_cache::move_by_type(uchar **border,
4311 Query_cache_block **before, ulong *gap,
4312 Query_cache_block *block)
4313 {
4314 DBUG_ENTER("Query_cache::move_by_type");
4315
4316 my_bool ok = 1;
4317 switch (block->type) {
4318 case Query_cache_block::FREE:
4319 {
4320 DBUG_PRINT("qcache", ("block 0x%lx FREE", (ulong) block));
4321 if (*border == 0)
4322 {
4323 *border = (uchar *) block;
4324 *before = block->pprev;
4325 DBUG_PRINT("qcache", ("gap beginning here"));
4326 }
4327 exclude_from_free_memory_list(block);
4328 *gap +=block->length;
4329 block->pprev->pnext=block->pnext;
4330 block->pnext->pprev=block->pprev;
4331 block->destroy();
4332 total_blocks--;
4333 DBUG_PRINT("qcache", ("added to gap (%lu)", *gap));
4334 break;
4335 }
4336 case Query_cache_block::TABLE:
4337 {
4338 HASH_SEARCH_STATE record_idx;
4339 DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block));
4340 if (*border == 0)
4341 break;
4342 ulong len = block->length, used = block->used;
4343 Query_cache_block_table *list_root = block->table(0);
4344 Query_cache_block_table *tprev = list_root->prev,
4345 *tnext = list_root->next;
4346 Query_cache_block *prev = block->prev,
4347 *next = block->next,
4348 *pprev = block->pprev,
4349 *pnext = block->pnext,
4350 *new_block =(Query_cache_block *) *border;
4351 size_t tablename_offset = block->table()->table() - block->table()->db();
4352 char *data = (char*) block->data();
4353 uchar *key;
4354 size_t key_length;
4355 key=query_cache_table_get_key((uchar*) block, &key_length, 0);
4356 my_hash_first(&tables, key, key_length, &record_idx);
4357
4358 block->destroy();
4359 new_block->init(len);
4360 new_block->type=Query_cache_block::TABLE;
4361 new_block->used=used;
4362 new_block->n_tables=1;
4363 memmove((char*) new_block->data(), data, len-new_block->headers_len());
4364 relink(block, new_block, next, prev, pnext, pprev);
4365 if (tables_blocks == block)
4366 tables_blocks = new_block;
4367
4368 Query_cache_block_table *nlist_root = new_block->table(0);
4369 nlist_root->n = 0;
4370 nlist_root->next = tnext;
4371 tnext->prev = nlist_root;
4372 nlist_root->prev = tprev;
4373 tprev->next = nlist_root;
4374 DBUG_PRINT("qcache",
4375 ("list_root: 0x%lx tnext 0x%lx tprev 0x%lx tprev->next 0x%lx tnext->prev 0x%lx",
4376 (ulong) list_root, (ulong) tnext, (ulong) tprev,
4377 (ulong)tprev->next, (ulong)tnext->prev));
4378 /*
4379 Go through all queries that uses this table and change them to
4380 point to the new table object
4381 */
4382 Query_cache_table *new_block_table=new_block->table();
4383 for (;tnext != nlist_root; tnext=tnext->next)
4384 tnext->parent= new_block_table;
4385 *border += len;
4386 *before = new_block;
4387 /* Fix pointer to table name */
4388 new_block->table()->table(new_block->table()->db() + tablename_offset);
4389 /* Fix hash to point at moved block */
4390 my_hash_replace(&tables, &record_idx, (uchar*) new_block);
4391
4392 DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
4393 len, (ulong) new_block, (ulong) *border));
4394 break;
4395 }
4396 case Query_cache_block::QUERY:
4397 {
4398 HASH_SEARCH_STATE record_idx;
4399 DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block));
4400 if (*border == 0)
4401 break;
4402 BLOCK_LOCK_WR(block);
4403 ulong len = block->length, used = block->used;
4404 TABLE_COUNTER_TYPE n_tables = block->n_tables;
4405 Query_cache_block *prev = block->prev,
4406 *next = block->next,
4407 *pprev = block->pprev,
4408 *pnext = block->pnext,
4409 *new_block =(Query_cache_block*) *border;
4410 char *data = (char*) block->data();
4411 Query_cache_block *first_result_block = ((Query_cache_query *)
4412 block->data())->result();
4413 uchar *key;
4414 size_t key_length;
4415 key=query_cache_query_get_key((uchar*) block, &key_length, 0);
4416 my_hash_first(&queries, key, key_length, &record_idx);
4417 // Move table of used tables
4418 memmove((char*) new_block->table(0), (char*) block->table(0),
4419 ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
4420 block->query()->unlock_n_destroy();
4421 block->destroy();
4422 new_block->init(len);
4423 new_block->type=Query_cache_block::QUERY;
4424 new_block->used=used;
4425 new_block->n_tables=n_tables;
4426 memmove((char*) new_block->data(), data, len - new_block->headers_len());
4427 relink(block, new_block, next, prev, pnext, pprev);
4428 if (queries_blocks == block)
4429 queries_blocks = new_block;
4430 Query_cache_block_table *beg_of_table_table= block->table(0),
4431 *end_of_table_table= block->table(n_tables);
4432 uchar *beg_of_new_table_table= (uchar*) new_block->table(0);
4433
4434 for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++)
4435 {
4436 Query_cache_block_table *block_table = new_block->table(j);
4437
4438 // use aligment from begining of table if 'next' is in same block
4439 if ((beg_of_table_table <= block_table->next) &&
4440 (block_table->next < end_of_table_table))
4441 ((Query_cache_block_table *)(beg_of_new_table_table +
4442 (((uchar*)block_table->next) -
4443 ((uchar*)beg_of_table_table))))->prev=
4444 block_table;
4445 else
4446 block_table->next->prev= block_table;
4447
4448 // use aligment from begining of table if 'prev' is in same block
4449 if ((beg_of_table_table <= block_table->prev) &&
4450 (block_table->prev < end_of_table_table))
4451 ((Query_cache_block_table *)(beg_of_new_table_table +
4452 (((uchar*)block_table->prev) -
4453 ((uchar*)beg_of_table_table))))->next=
4454 block_table;
4455 else
4456 block_table->prev->next = block_table;
4457 }
4458 DBUG_PRINT("qcache", ("after circle tt"));
4459 *border += len;
4460 *before = new_block;
4461 new_block->query()->result(first_result_block);
4462 if (first_result_block != 0)
4463 {
4464 Query_cache_block *result_block = first_result_block;
4465 do
4466 {
4467 result_block->result()->parent(new_block);
4468 result_block = result_block->next;
4469 } while ( result_block != first_result_block );
4470 }
4471 Query_cache_query *new_query= ((Query_cache_query *) new_block->data());
4472 mysql_rwlock_init(key_rwlock_query_cache_query_lock, &new_query->lock);
4473
4474 /*
4475 If someone is writing to this block, inform the writer that the block
4476 has been moved.
4477 */
4478 Query_cache_tls *query_cache_tls= new_block->query()->writer();
4479 if (query_cache_tls != NULL)
4480 {
4481 query_cache_tls->first_query_block= new_block;
4482 }
4483 /* Fix hash to point at moved block */
4484 my_hash_replace(&queries, &record_idx, (uchar*) new_block);
4485 DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
4486 len, (ulong) new_block, (ulong) *border));
4487 break;
4488 }
4489 case Query_cache_block::RES_INCOMPLETE:
4490 case Query_cache_block::RES_BEG:
4491 case Query_cache_block::RES_CONT:
4492 case Query_cache_block::RESULT:
4493 {
4494 DBUG_PRINT("qcache", ("block 0x%lx RES* (%d)", (ulong) block,
4495 (int) block->type));
4496 if (*border == 0)
4497 break;
4498 Query_cache_block *query_block= block->result()->parent();
4499 BLOCK_LOCK_WR(query_block);
4500 Query_cache_block *next= block->next, *prev= block->prev;
4501 Query_cache_block::block_type type= block->type;
4502 ulong len = block->length, used = block->used;
4503 Query_cache_block *pprev = block->pprev,
4504 *pnext = block->pnext,
4505 *new_block =(Query_cache_block*) *border;
4506 char *data = (char*) block->data();
4507 block->destroy();
4508 new_block->init(len);
4509 new_block->type=type;
4510 new_block->used=used;
4511 memmove((char*) new_block->data(), data, len - new_block->headers_len());
4512 relink(block, new_block, next, prev, pnext, pprev);
4513 new_block->result()->parent(query_block);
4514 Query_cache_query *query = query_block->query();
4515 if (query->result() == block)
4516 query->result(new_block);
4517 *border += len;
4518 *before = new_block;
4519 /* If result writing complete && we have free space in block */
4520 ulong free_space= new_block->length - new_block->used;
4521 free_space-= free_space % ALIGN_SIZE(1);
4522 if (query->result()->type == Query_cache_block::RESULT &&
4523 new_block->length > new_block->used &&
4524 *gap + free_space > min_allocation_unit &&
4525 new_block->length - free_space > min_allocation_unit)
4526 {
4527 *border-= free_space;
4528 *gap+= free_space;
4529 DBUG_PRINT("qcache",
4530 ("rest of result free space added to gap (%lu)", *gap));
4531 new_block->length -= free_space;
4532 }
4533 BLOCK_UNLOCK_WR(query_block);
4534 DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
4535 len, (ulong) new_block, (ulong) *border));
4536 break;
4537 }
4538 default:
4539 DBUG_PRINT("error", ("unexpected block type %d, block 0x%lx",
4540 (int)block->type, (ulong) block));
4541 ok = 0;
4542 }
4543 DBUG_RETURN(ok);
4544 }
4545
4546
relink(Query_cache_block * oblock,Query_cache_block * nblock,Query_cache_block * next,Query_cache_block * prev,Query_cache_block * pnext,Query_cache_block * pprev)4547 void Query_cache::relink(Query_cache_block *oblock,
4548 Query_cache_block *nblock,
4549 Query_cache_block *next, Query_cache_block *prev,
4550 Query_cache_block *pnext, Query_cache_block *pprev)
4551 {
4552 if (prev == oblock) //check pointer to himself
4553 {
4554 nblock->prev = nblock;
4555 nblock->next = nblock;
4556 }
4557 else
4558 {
4559 nblock->prev = prev;
4560 prev->next=nblock;
4561 }
4562 if (next != oblock)
4563 {
4564 nblock->next = next;
4565 next->prev=nblock;
4566 }
4567 nblock->pprev = pprev; // Physical pointer to himself have only 1 free block
4568 nblock->pnext = pnext;
4569 pprev->pnext=nblock;
4570 pnext->pprev=nblock;
4571 }
4572
4573
join_results(ulong join_limit)4574 my_bool Query_cache::join_results(ulong join_limit)
4575 {
4576 my_bool has_moving = 0;
4577 DBUG_ENTER("Query_cache::join_results");
4578
4579 if (queries_blocks != 0)
4580 {
4581 assert(query_cache_size > 0);
4582 Query_cache_block *block = queries_blocks;
4583 do
4584 {
4585 Query_cache_query *header = block->query();
4586 if (header->result() != 0 &&
4587 header->result()->type == Query_cache_block::RESULT &&
4588 header->length() > join_limit)
4589 {
4590 Query_cache_block *new_result_block =
4591 get_free_block(ALIGN_SIZE(header->length()) +
4592 ALIGN_SIZE(sizeof(Query_cache_block)) +
4593 ALIGN_SIZE(sizeof(Query_cache_result)), 1, 0);
4594 if (new_result_block != 0)
4595 {
4596 has_moving = 1;
4597 Query_cache_block *first_result = header->result();
4598 ulong new_len = (header->length() +
4599 ALIGN_SIZE(sizeof(Query_cache_block)) +
4600 ALIGN_SIZE(sizeof(Query_cache_result)));
4601 if (new_result_block->length >
4602 ALIGN_SIZE(new_len) + min_allocation_unit)
4603 split_block(new_result_block, ALIGN_SIZE(new_len));
4604 BLOCK_LOCK_WR(block);
4605 header->result(new_result_block);
4606 new_result_block->type = Query_cache_block::RESULT;
4607 new_result_block->n_tables = 0;
4608 new_result_block->used = new_len;
4609
4610 new_result_block->next = new_result_block->prev = new_result_block;
4611 DBUG_PRINT("qcache", ("new block %lu/%lu (%lu)",
4612 new_result_block->length,
4613 new_result_block->used,
4614 header->length()));
4615
4616 Query_cache_result *new_result = new_result_block->result();
4617 new_result->parent(block);
4618 uchar *write_to = new_result->data();
4619 Query_cache_block *result_block = first_result;
4620 do
4621 {
4622 ulong len = (result_block->used - result_block->headers_len() -
4623 ALIGN_SIZE(sizeof(Query_cache_result)));
4624 DBUG_PRINT("loop", ("add block %lu/%lu (%lu)",
4625 result_block->length,
4626 result_block->used,
4627 len));
4628 memcpy((char *) write_to,
4629 (char*) result_block->result()->data(),
4630 len);
4631 write_to += len;
4632 Query_cache_block *old_result_block = result_block;
4633 result_block = result_block->next;
4634 free_memory_block(old_result_block);
4635 } while (result_block != first_result);
4636 BLOCK_UNLOCK_WR(block);
4637 }
4638 }
4639 block = block->next;
4640 } while ( block != queries_blocks );
4641 }
4642 DBUG_RETURN(has_moving);
4643 }
4644
4645
filename_2_table_key(char * key,const char * path,size_t * db_length)4646 size_t Query_cache::filename_2_table_key (char *key, const char *path,
4647 size_t *db_length)
4648 {
4649 char tablename[FN_REFLEN+2], *filename, *dbname;
4650 DBUG_ENTER("Query_cache::filename_2_table_key");
4651
4652 /* Safety if filename didn't have a directory name */
4653 tablename[0]= FN_LIBCHAR;
4654 tablename[1]= FN_LIBCHAR;
4655 /* Convert filename to this OS's format in tablename */
4656 fn_format(tablename + 2, path, "", "", MY_REPLACE_EXT);
4657 filename= tablename + dirname_length(tablename + 2) + 2;
4658 /* Find start of databasename */
4659 for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ;
4660 *db_length= (filename - dbname) - 1;
4661 DBUG_PRINT("qcache", ("table '%-.*s.%s'", static_cast<int>(*db_length), dbname, filename));
4662
4663 DBUG_RETURN(static_cast<size_t>(strmake(strmake(key, dbname,
4664 min<size_t>(*db_length,
4665 NAME_LEN)) + 1,
4666 filename, NAME_LEN) - key) + 1);
4667 }
4668
4669 /****************************************************************************
4670 Functions to be used when debugging
4671 ****************************************************************************/
4672
4673 #if defined(NDEBUG) || !defined(EXTRA_DEBUG)
4674
wreck(uint line,const char * message)4675 void Query_cache::wreck(uint line, const char *message) { query_cache_size = 0; }
bins_dump()4676 void Query_cache::bins_dump() {}
cache_dump()4677 void Query_cache::cache_dump() {}
queries_dump()4678 void Query_cache::queries_dump() {}
tables_dump()4679 void Query_cache::tables_dump() {}
check_integrity(enum_qcci_lock_mode locking)4680 bool Query_cache::check_integrity(enum_qcci_lock_mode locking) { return false; }
in_list(Query_cache_block * root,Query_cache_block * point,const char * name)4681 my_bool Query_cache::in_list(Query_cache_block *root, Query_cache_block *point,
4682 const char *name) { return 0;}
in_blocks(Query_cache_block * point)4683 my_bool Query_cache::in_blocks(Query_cache_block * point) { return 0; }
4684
4685 #else
4686
4687
4688 /*
4689 Debug method which switch query cache off but left content for
4690 investigation.
4691
4692 SYNOPSIS
4693 Query_cache::wreck()
4694 line line of the wreck() call
4695 message message for logging
4696 */
4697
wreck(uint line,const char * message)4698 void Query_cache::wreck(uint line, const char *message)
4699 {
4700 THD *thd=current_thd;
4701 DBUG_ENTER("Query_cache::wreck");
4702 query_cache_size = 0;
4703 if (*message)
4704 DBUG_PRINT("error", (" %s", message));
4705 DBUG_PRINT("warning", ("=================================="));
4706 DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
4707 DBUG_PRINT("warning", ("=================================="));
4708 if (thd)
4709 thd->killed= THD::KILL_CONNECTION;
4710 cache_dump();
4711 bins_dump();
4712 DBUG_VOID_RETURN;
4713 }
4714
4715
bins_dump()4716 void Query_cache::bins_dump()
4717 {
4718 uint i;
4719
4720 if (!initialized || query_cache_size == 0)
4721 {
4722 DBUG_PRINT("qcache", ("Query Cache not initialized"));
4723 return;
4724 }
4725
4726 DBUG_PRINT("qcache", ("mem_bin_num=%u, mem_bin_steps=%u",
4727 mem_bin_num, mem_bin_steps));
4728 DBUG_PRINT("qcache", ("-------------------------"));
4729 DBUG_PRINT("qcache", (" size idx step"));
4730 DBUG_PRINT("qcache", ("-------------------------"));
4731 for (i=0; i < mem_bin_steps; i++)
4732 {
4733 DBUG_PRINT("qcache", ("%10lu %3d %10lu", steps[i].size, steps[i].idx,
4734 steps[i].increment));
4735 }
4736 DBUG_PRINT("qcache", ("-------------------------"));
4737 DBUG_PRINT("qcache", (" size num"));
4738 DBUG_PRINT("qcache", ("-------------------------"));
4739 for (i=0; i < mem_bin_num; i++)
4740 {
4741 DBUG_PRINT("qcache", ("%10lu %3d 0x%lx", bins[i].size, bins[i].number,
4742 (ulong)&(bins[i])));
4743 if (bins[i].free_blocks)
4744 {
4745 Query_cache_block *block = bins[i].free_blocks;
4746 do{
4747 DBUG_PRINT("qcache", ("\\-- %lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
4748 block->length, (ulong)block,
4749 (ulong)block->next, (ulong)block->prev,
4750 (ulong)block->pnext, (ulong)block->pprev));
4751 block = block->next;
4752 } while ( block != bins[i].free_blocks );
4753 }
4754 }
4755 DBUG_PRINT("qcache", ("-------------------------"));
4756 }
4757
4758
cache_dump()4759 void Query_cache::cache_dump()
4760 {
4761 if (!initialized || query_cache_size == 0)
4762 {
4763 DBUG_PRINT("qcache", ("Query Cache not initialized"));
4764 return;
4765 }
4766
4767 DBUG_PRINT("qcache", ("-------------------------------------"));
4768 DBUG_PRINT("qcache", (" length used t nt"));
4769 DBUG_PRINT("qcache", ("-------------------------------------"));
4770 Query_cache_block *i = first_block;
4771 do
4772 {
4773 DBUG_PRINT("qcache",
4774 ("%10lu %10lu %1d %2d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
4775 i->length, i->used, (int)i->type,
4776 i->n_tables, (ulong)i,
4777 (ulong)i->next, (ulong)i->prev, (ulong)i->pnext,
4778 (ulong)i->pprev));
4779 i = i->pnext;
4780 } while ( i != first_block );
4781 DBUG_PRINT("qcache", ("-------------------------------------"));
4782 }
4783
4784
queries_dump()4785 void Query_cache::queries_dump()
4786 {
4787
4788 if (!initialized)
4789 {
4790 DBUG_PRINT("qcache", ("Query Cache not initialized"));
4791 return;
4792 }
4793
4794 DBUG_PRINT("qcache", ("------------------"));
4795 DBUG_PRINT("qcache", (" QUERIES"));
4796 DBUG_PRINT("qcache", ("------------------"));
4797 if (queries_blocks != 0)
4798 {
4799 Query_cache_block *block = queries_blocks;
4800 do
4801 {
4802 size_t len;
4803 char *str = (char*) query_cache_query_get_key((uchar*) block, &len, 0);
4804 len-= QUERY_CACHE_FLAGS_SIZE; // Point at flags
4805 Query_cache_query_flags flags;
4806 memcpy(&flags, str+len, QUERY_CACHE_FLAGS_SIZE);
4807 str[len]= 0; // make zero ending DB name
4808 DBUG_PRINT("qcache", ("F: %u C: %u L: %lu T: '%s' (%lu) '%s' '%s'",
4809 flags.client_long_flag,
4810 flags.character_set_client_num,
4811 (ulong)flags.limit,
4812 flags.time_zone->get_name()->ptr(),
4813 (ulong) len, str, strend(str)+1));
4814 DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block,
4815 (ulong) block->next, (ulong) block->prev,
4816 (ulong)block->pnext, (ulong)block->pprev));
4817 memcpy(str + len, &flags, QUERY_CACHE_FLAGS_SIZE); // restore flags
4818 for (TABLE_COUNTER_TYPE t= 0; t < block->n_tables; t++)
4819 {
4820 Query_cache_table *table= block->table(t)->parent;
4821 DBUG_PRINT("qcache", ("-t- '%s' '%s'", table->db(), table->table()));
4822 }
4823 Query_cache_query *header = block->query();
4824 if (header->result())
4825 {
4826 Query_cache_block *result_block = header->result();
4827 Query_cache_block *result_beg = result_block;
4828 do
4829 {
4830 DBUG_PRINT("qcache", ("-r- %u %lu/%lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
4831 (uint) result_block->type,
4832 result_block->length, result_block->used,
4833 (ulong) result_block,
4834 (ulong) result_block->next,
4835 (ulong) result_block->prev,
4836 (ulong) result_block->pnext,
4837 (ulong) result_block->pprev));
4838 result_block = result_block->next;
4839 } while ( result_block != result_beg );
4840 }
4841 } while ((block=block->next) != queries_blocks);
4842 }
4843 else
4844 {
4845 DBUG_PRINT("qcache", ("no queries in list"));
4846 }
4847 DBUG_PRINT("qcache", ("------------------"));
4848 }
4849
4850
tables_dump()4851 void Query_cache::tables_dump()
4852 {
4853 if (!initialized || query_cache_size == 0)
4854 {
4855 DBUG_PRINT("qcache", ("Query Cache not initialized"));
4856 return;
4857 }
4858
4859 DBUG_PRINT("qcache", ("--------------------"));
4860 DBUG_PRINT("qcache", ("TABLES"));
4861 DBUG_PRINT("qcache", ("--------------------"));
4862 if (tables_blocks != 0)
4863 {
4864 Query_cache_block *table_block = tables_blocks;
4865 do
4866 {
4867 Query_cache_table *table = table_block->table();
4868 DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
4869 table_block = table_block->next;
4870 } while (table_block != tables_blocks);
4871 }
4872 else
4873 DBUG_PRINT("qcache", ("no tables in list"));
4874 DBUG_PRINT("qcache", ("--------------------"));
4875 }
4876
4877
4878 /**
4879 Checks integrity of the various linked lists
4880
4881 @param locking CALLER_HOLDS_LOCK | LOCK_WHILE_CHECKING Who does locking?
4882
4883 @return Error status code
4884 @retval false Query cache is operational.
4885 @retval true Query cache is broken.
4886 */
4887
check_integrity(enum_qcci_lock_mode locking)4888 bool Query_cache::check_integrity(enum_qcci_lock_mode locking)
4889 {
4890 bool result= false;
4891 uint i;
4892
4893 DBUG_ENTER("check_integrity");
4894
4895 /*
4896 If we can't get a lock here, it means someone's throwing out the cache so
4897 there's nothing to check, anyway, so that's OK.
4898 */
4899 if ((locking == LOCK_WHILE_CHECKING) && (try_lock()))
4900 DBUG_RETURN(false);
4901
4902 if (my_hash_check(&queries))
4903 {
4904 DBUG_PRINT("error", ("queries hash is damaged"));
4905 result= true;
4906 }
4907
4908 if (my_hash_check(&tables))
4909 {
4910 DBUG_PRINT("error", ("tables hash is damaged"));
4911 result= true;
4912 }
4913
4914 DBUG_PRINT("qcache", ("physical address check ..."));
4915 ulong free=0, used=0;
4916 Query_cache_block * block = first_block;
4917 do
4918 {
4919 /* When checking at system start, there is no block. */
4920 if (!block)
4921 break;
4922
4923 DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
4924 (ulong) block, (uint) block->type));
4925 // Check allignment
4926 if ((((long)block) % (long) ALIGN_SIZE(1)) !=
4927 (((long)first_block) % (long)ALIGN_SIZE(1)))
4928 {
4929 DBUG_PRINT("error",
4930 ("block 0x%lx do not aligned by %d", (ulong) block,
4931 (int) ALIGN_SIZE(1)));
4932 result= true;
4933 }
4934 // Check memory allocation
4935 if (block->pnext == first_block) // Is it last block?
4936 {
4937 if (((uchar*)block) + block->length !=
4938 ((uchar*)first_block) + query_cache_size)
4939 {
4940 DBUG_PRINT("error",
4941 ("block 0x%lx, type %u, ended at 0x%lx, but cache ended at 0x%lx",
4942 (ulong) block, (uint) block->type,
4943 (ulong) (((uchar*)block) + block->length),
4944 (ulong) (((uchar*)first_block) + query_cache_size)));
4945 result= true;
4946 }
4947 }
4948 else
4949 if (((uchar*)block) + block->length != ((uchar*)block->pnext))
4950 {
4951 DBUG_PRINT("error",
4952 ("block 0x%lx, type %u, ended at 0x%lx, but next block begining at 0x%lx",
4953 (ulong) block, (uint) block->type,
4954 (ulong) (((uchar*)block) + block->length),
4955 (ulong) ((uchar*)block->pnext)));
4956 }
4957 if (block->type == Query_cache_block::FREE)
4958 free+= block->length;
4959 else
4960 used+= block->length;
4961 switch(block->type) {
4962 case Query_cache_block::FREE:
4963 {
4964 Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
4965 block->data());
4966 //is it correct pointer?
4967 if (((uchar*)bin) < ((uchar*)bins) ||
4968 ((uchar*)bin) >= ((uchar*)first_block))
4969 {
4970 DBUG_PRINT("error",
4971 ("free block 0x%lx have bin pointer 0x%lx beyaond of bins array bounds [0x%lx,0x%lx]",
4972 (ulong) block,
4973 (ulong) bin,
4974 (ulong) bins,
4975 (ulong) first_block));
4976 result= true;
4977 }
4978 else
4979 {
4980 int idx = (((uchar*)bin) - ((uchar*)bins)) /
4981 sizeof(Query_cache_memory_bin);
4982 if (in_list(bins[idx].free_blocks, block, "free memory"))
4983 result= true;
4984 }
4985 break;
4986 }
4987 case Query_cache_block::TABLE:
4988 if (in_list(tables_blocks, block, "tables"))
4989 result= true;
4990 if (in_table_list(block->table(0), block->table(0), "table list root"))
4991 result= true;
4992 break;
4993 case Query_cache_block::QUERY:
4994 {
4995 if (in_list(queries_blocks, block, "query"))
4996 result = true;
4997 for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++)
4998 {
4999 Query_cache_block_table *block_table = block->table(j);
5000 Query_cache_block_table *block_table_root =
5001 (Query_cache_block_table *)
5002 (((uchar*)block_table->parent) -
5003 ALIGN_SIZE(sizeof(Query_cache_block_table)));
5004
5005 if (in_table_list(block_table, block_table_root, "table list"))
5006 result= true;
5007 }
5008 break;
5009 }
5010 case Query_cache_block::RES_INCOMPLETE:
5011 // This type of block can be not lincked yet (in multithread environment)
5012 break;
5013 case Query_cache_block::RES_BEG:
5014 case Query_cache_block::RES_CONT:
5015 case Query_cache_block::RESULT:
5016 {
5017 Query_cache_block * query_block = block->result()->parent();
5018 if (((uchar*)query_block) < ((uchar*)first_block) ||
5019 ((uchar*)query_block) >= (((uchar*)first_block) + query_cache_size))
5020 {
5021 DBUG_PRINT("error",
5022 ("result block 0x%lx have query block pointer 0x%lx beyaond of block pool bounds [0x%lx,0x%lx]",
5023 (ulong) block,
5024 (ulong) query_block,
5025 (ulong) first_block,
5026 (ulong) (((uchar*)first_block) + query_cache_size)));
5027 result= true;
5028 }
5029 else
5030 {
5031 BLOCK_LOCK_RD(query_block);
5032 if (in_list(queries_blocks, query_block, "query from results"))
5033 result= true;
5034 if (in_list(query_block->query()->result(), block,
5035 "results"))
5036 result= true;
5037 BLOCK_UNLOCK_RD(query_block);
5038 }
5039 break;
5040 }
5041 default:
5042 DBUG_PRINT("error", ("block 0x%lx have incorrect type %u",
5043 (long) block, block->type));
5044 result= true;
5045 }
5046
5047 block = block->pnext;
5048 } while (block != first_block);
5049
5050 if (used + free != query_cache_size)
5051 {
5052 DBUG_PRINT("error",
5053 ("used memory (%lu) + free memory (%lu) != query_cache_size (%lu)",
5054 used, free, query_cache_size));
5055 result= true;
5056 }
5057
5058 if (free != free_memory)
5059 {
5060 DBUG_PRINT("error",
5061 ("free memory (%lu) != free_memory (%lu)",
5062 free, free_memory));
5063 result= true;
5064 }
5065
5066 DBUG_PRINT("qcache", ("check queries ..."));
5067 if ((block = queries_blocks))
5068 {
5069 do
5070 {
5071 DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
5072 (ulong) block, (uint) block->type));
5073 size_t length;
5074 uchar *key = query_cache_query_get_key((uchar*) block, &length, 0);
5075 uchar* val = my_hash_search(&queries, key, length);
5076 if (((uchar*)block) != val)
5077 {
5078 DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
5079 (ulong) block, (ulong) val));
5080 }
5081 if (in_blocks(block))
5082 result= true;
5083 Query_cache_block * results = block->query()->result();
5084 if (results)
5085 {
5086 Query_cache_block * result_block = results;
5087 do
5088 {
5089 DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
5090 (ulong) block, (uint) block->type));
5091 if (in_blocks(result_block))
5092 result= true;
5093
5094 result_block = result_block->next;
5095 } while (result_block != results);
5096 }
5097 block = block->next;
5098 } while (block != queries_blocks);
5099 }
5100
5101 DBUG_PRINT("qcache", ("check tables ..."));
5102 if ((block = tables_blocks))
5103 {
5104 do
5105 {
5106 DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
5107 (ulong) block, (uint) block->type));
5108 size_t length;
5109 uchar *key = query_cache_table_get_key((uchar*) block, &length, 0);
5110 uchar* val = my_hash_search(&tables, key, length);
5111 if (((uchar*)block) != val)
5112 {
5113 DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
5114 (ulong) block, (ulong) val));
5115 }
5116
5117 if (in_blocks(block))
5118 result= true;
5119 block=block->next;
5120 } while (block != tables_blocks);
5121 }
5122
5123 DBUG_PRINT("qcache", ("check free blocks"));
5124 for (i = 0; i < mem_bin_num; i++)
5125 {
5126 if ((block = bins[i].free_blocks))
5127 {
5128 uint count = 0;
5129 do
5130 {
5131 DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
5132 (ulong) block, (uint) block->type));
5133 if (in_blocks(block))
5134 result= true;
5135
5136 count++;
5137 block=block->next;
5138 } while (block != bins[i].free_blocks);
5139 if (count != bins[i].number)
5140 {
5141 DBUG_PRINT("error", ("bins[%d].number= %d, but bin have %d blocks",
5142 i, bins[i].number, count));
5143 result= true;
5144 }
5145 }
5146 }
5147 assert(result == 0);
5148
5149 if (locking == LOCK_WHILE_CHECKING)
5150 unlock();
5151
5152 DBUG_RETURN(result);
5153 }
5154
5155
in_blocks(Query_cache_block * point)5156 my_bool Query_cache::in_blocks(Query_cache_block * point)
5157 {
5158 my_bool result = 0;
5159 Query_cache_block *block = point;
5160 //back
5161 do
5162 {
5163 if (block->pprev->pnext != block)
5164 {
5165 DBUG_PRINT("error",
5166 ("block 0x%lx in physical list is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
5167 (ulong) block, (ulong) block->pprev,
5168 (ulong) block->pprev->pnext,
5169 (ulong) point));
5170 //back trace
5171 for (; block != point; block = block->pnext)
5172 DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
5173 result = 1;
5174 goto err1;
5175 }
5176 block = block->pprev;
5177 } while (block != first_block && block != point);
5178 if (block != first_block)
5179 {
5180 DBUG_PRINT("error",
5181 ("block 0x%lx (0x%lx<-->0x%lx) not owned by pysical list",
5182 (ulong) block, (ulong) block->pprev, (ulong )block->pnext));
5183 return 1;
5184 }
5185
5186 err1:
5187 //forward
5188 block = point;
5189 do
5190 {
5191 if (block->pnext->pprev != block)
5192 {
5193 DBUG_PRINT("error",
5194 ("block 0x%lx in physicel list is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
5195 (ulong) block, (ulong) block->pnext,
5196 (ulong) block->pnext->pprev,
5197 (ulong) point));
5198 //back trace
5199 for (; block != point; block = block->pprev)
5200 DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
5201 result = 1;
5202 goto err2;
5203 }
5204 block = block->pnext;
5205 } while (block != first_block);
5206 err2:
5207 return result;
5208 }
5209
5210
in_list(Query_cache_block * root,Query_cache_block * point,const char * name)5211 my_bool Query_cache::in_list(Query_cache_block * root,
5212 Query_cache_block * point,
5213 const char *name)
5214 {
5215 my_bool result = 0;
5216 Query_cache_block *block = point;
5217 //back
5218 do
5219 {
5220 if (block->prev->next != block)
5221 {
5222 DBUG_PRINT("error",
5223 ("block 0x%lx in list '%s' 0x%lx is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
5224 (ulong) block, name, (ulong) root, (ulong) block->prev,
5225 (ulong) block->prev->next,
5226 (ulong) point));
5227 //back trace
5228 for (; block != point; block = block->next)
5229 DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
5230 result = 1;
5231 goto err1;
5232 }
5233 block = block->prev;
5234 } while (block != root && block != point);
5235 if (block != root)
5236 {
5237 DBUG_PRINT("error",
5238 ("block 0x%lx (0x%lx<-->0x%lx) not owned by list '%s' 0x%lx",
5239 (ulong) block,
5240 (ulong) block->prev, (ulong) block->next,
5241 name, (ulong) root));
5242 return 1;
5243 }
5244 err1:
5245 // forward
5246 block = point;
5247 do
5248 {
5249 if (block->next->prev != block)
5250 {
5251 DBUG_PRINT("error",
5252 ("block 0x%lx in list '%s' 0x%lx is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
5253 (ulong) block, name, (ulong) root, (ulong) block->next,
5254 (ulong) block->next->prev,
5255 (ulong) point));
5256 //back trace
5257 for (; block != point; block = block->prev)
5258 DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
5259 result = 1;
5260 goto err2;
5261 }
5262 block = block->next;
5263 } while (block != root);
5264 err2:
5265 return result;
5266 }
5267
dump_node(Query_cache_block_table * node,const char * call,const char * descr)5268 void dump_node(Query_cache_block_table * node,
5269 const char * call, const char * descr)
5270 {
5271 DBUG_PRINT("qcache", ("%s: %s: node: 0x%lx", call, descr, (ulong) node));
5272 DBUG_PRINT("qcache", ("%s: %s: node block: 0x%lx",
5273 call, descr, (ulong) node->block()));
5274 DBUG_PRINT("qcache", ("%s: %s: next: 0x%lx", call, descr,
5275 (ulong) node->next));
5276 DBUG_PRINT("qcache", ("%s: %s: prev: 0x%lx", call, descr,
5277 (ulong) node->prev));
5278 }
5279
in_table_list(Query_cache_block_table * root,Query_cache_block_table * point,const char * name)5280 my_bool Query_cache::in_table_list(Query_cache_block_table * root,
5281 Query_cache_block_table * point,
5282 const char *name)
5283 {
5284 my_bool result = 0;
5285 Query_cache_block_table *table = point;
5286 dump_node(root, name, "parameter root");
5287 //back
5288 do
5289 {
5290 dump_node(table, name, "list element << ");
5291 if (table->prev->next != table)
5292 {
5293 DBUG_PRINT("error",
5294 ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, prev table 0x%lx(0x%lx) refered as next to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
5295 (ulong) table, (ulong) table->block(), name,
5296 (ulong) root, (ulong) root->block(),
5297 (ulong) table->prev, (ulong) table->prev->block(),
5298 (ulong) table->prev->next,
5299 (ulong) table->prev->next->block(),
5300 (ulong) point, (ulong) point->block()));
5301 //back trace
5302 for (; table != point; table = table->next)
5303 DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
5304 (ulong) table, (ulong) table->block()));
5305 result = 1;
5306 goto err1;
5307 }
5308 table = table->prev;
5309 } while (table != root && table != point);
5310 if (table != root)
5311 {
5312 DBUG_PRINT("error",
5313 ("table 0x%lx(0x%lx) (0x%lx(0x%lx)<-->0x%lx(0x%lx)) not owned by list '%s' 0x%lx(0x%lx)",
5314 (ulong) table, (ulong) table->block(),
5315 (ulong) table->prev, (ulong) table->prev->block(),
5316 (ulong) table->next, (ulong) table->next->block(),
5317 name, (ulong) root, (ulong) root->block()));
5318 return 1;
5319 }
5320 err1:
5321 // forward
5322 table = point;
5323 do
5324 {
5325 dump_node(table, name, "list element >> ");
5326 if (table->next->prev != table)
5327 {
5328 DBUG_PRINT("error",
5329 ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, next table 0x%lx(0x%lx) refered as prev to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
5330 (ulong) table, (ulong) table->block(),
5331 name, (ulong) root, (ulong) root->block(),
5332 (ulong) table->next, (ulong) table->next->block(),
5333 (ulong) table->next->prev,
5334 (ulong) table->next->prev->block(),
5335 (ulong) point, (ulong) point->block()));
5336 //back trace
5337 for (; table != point; table = table->prev)
5338 DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
5339 (ulong) table, (ulong) table->block()));
5340 result = 1;
5341 goto err2;
5342 }
5343 table = table->next;
5344 } while (table != root);
5345 err2:
5346 return result;
5347 }
5348
5349 #endif /* NDEBUG */
5350
5351