My Project
sql_cache.h
00001 /* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software Foundation,
00014    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
00015 
00016 #ifndef _SQL_CACHE_H
00017 #define _SQL_CACHE_H
00018 
00019 #include "hash.h"
00020 #include "my_base.h"                            /* ha_rows */
00021 
00022 class MY_LOCALE;
00023 struct TABLE_LIST;
00024 class Time_zone;
00025 struct LEX;
00026 struct TABLE;
00027 typedef struct st_changed_table_list CHANGED_TABLE_LIST;
00028 typedef ulonglong sql_mode_t;
00029 
00030 /* Query cache */
00031 
00032 /*
00033    Can't create new free memory block if unused memory in block less
00034    then QUERY_CACHE_MIN_ALLOCATION_UNIT.
00035    if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then
00036    QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly
00037 */
00038 #define QUERY_CACHE_MIN_ALLOCATION_UNIT         512
00039 
00040 /* inittial size of hashes */
00041 #define QUERY_CACHE_DEF_QUERY_HASH_SIZE         1024
00042 #define QUERY_CACHE_DEF_TABLE_HASH_SIZE         1024
00043 
00044 /* minimal result data size when data allocated */
00045 #define QUERY_CACHE_MIN_RESULT_DATA_SIZE        1024*4
00046 
00047 /* 
00048    start estimation of first result block size only when number of queries
00049    bigger then: 
00050 */
00051 #define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3
00052 
00053 
00054 
00055 /* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */
00056 #define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2     4
00057 #define QUERY_CACHE_MEM_BIN_STEP_PWR2           2
00058 #define QUERY_CACHE_MEM_BIN_PARTS_INC           1
00059 #define QUERY_CACHE_MEM_BIN_PARTS_MUL           1.2
00060 #define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2        3
00061 
00062 /* how many free blocks check when finding most suitable before other 'end'
00063    of list of free blocks */
00064 #define QUERY_CACHE_MEM_BIN_TRY                 5
00065 
00066 /* packing parameters */
00067 #define QUERY_CACHE_PACK_ITERATION              2
00068 #define QUERY_CACHE_PACK_LIMIT                  (512*1024L)
00069 
00070 #define TABLE_COUNTER_TYPE uint
00071 
00072 struct Query_cache_block;
00073 struct Query_cache_block_table;
00074 struct Query_cache_table;
00075 struct Query_cache_query;
00076 struct Query_cache_result;
00077 class Query_cache;
00078 struct Query_cache_tls;
00079 struct LEX;
00080 class THD;
00081 
00082 typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
00083                                       uint key_length,
00084                                       ulonglong *engine_data);
00085 
00093 struct Query_cache_block_table
00094 {
00095   Query_cache_block_table() {}                /* Remove gcc warning */
00096 
00101   TABLE_COUNTER_TYPE n;
00102 
00107   Query_cache_block_table *next, *prev;
00108 
00113   Query_cache_table *parent;
00114 
00121   inline Query_cache_block *block();
00122 };
00123 
00124 struct Query_cache_block
00125 {
00126   Query_cache_block() {}                      /* Remove gcc warning */
00127   enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG,
00128                    RES_INCOMPLETE, TABLE, INCOMPLETE};
00129 
00130   ulong length;                                 // length of all block
00131   ulong used;                                   // length of data
00132   /*
00133     Not used **pprev, **prev because really needed access to pervious block:
00134     *pprev to join free blocks
00135     *prev to access to opposite side of list in cyclic sorted list
00136   */
00137   Query_cache_block *pnext,*pprev,              // physical next/previous block
00138                     *next,*prev;                // logical next/previous block
00139   block_type type;
00140   TABLE_COUNTER_TYPE n_tables;                  // number of tables in query
00141 
00142   inline my_bool is_free(void) { return type == FREE; }
00143   void init(ulong length);
00144   void destroy();
00145   inline uint headers_len();
00146   inline uchar* data(void);
00147   inline Query_cache_query *query();
00148   inline Query_cache_table *table();
00149   inline Query_cache_result *result();
00150   inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
00151 };
00152 
00153 struct Query_cache_query
00154 {
00155   ulonglong limit_found_rows;
00156   mysql_rwlock_t lock;
00157   Query_cache_block *res;
00158   Query_cache_tls *wri;
00159   ulong len;
00160   uint8 tbls_type;
00161   unsigned int last_pkt_nr;
00162 
00163   Query_cache_query() {}                      /* Remove gcc warning */
00164   inline void init_n_lock();
00165   void unlock_n_destroy();
00166   inline ulonglong found_rows()            { return limit_found_rows; }
00167   inline void found_rows(ulonglong rows)   { limit_found_rows= rows; }
00168   inline Query_cache_block *result()       { return res; }
00169   inline void result(Query_cache_block *p) { res= p; }
00170   inline Query_cache_tls *writer()         { return wri; }
00171   inline void writer(Query_cache_tls *p)   { wri= p; }
00172   inline uint8 tables_type()               { return tbls_type; }
00173   inline void tables_type(uint8 type)      { tbls_type= type; }
00174   inline ulong length()                    { return len; }
00175   inline ulong add(ulong packet_len)       { return(len+= packet_len); }
00176   inline void length(ulong length_arg)     { len= length_arg; }
00177   inline uchar* query()
00178   {
00179     return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query)));
00180   }
00181   void lock_writing();
00182   void lock_reading();
00183   my_bool try_lock_writing();
00184   void unlock_writing();
00185   void unlock_reading();
00186 };
00187 
00188 
00189 struct Query_cache_table
00190 {
00191   Query_cache_table() {}                      /* Remove gcc warning */
00192   char *tbl;
00193   uint32 key_len;
00194   uint8 table_type;
00195   /* unique for every engine reference */
00196   qc_engine_callback callback_func;
00197   /* data need by some engines */
00198   ulonglong engine_data_buff;
00199 
00203   int32 m_cached_query_count;
00204 
00205   inline char *db()                          { return (char *) data(); }
00206   inline char *table()                       { return tbl; }
00207   inline void table(char *table_arg)         { tbl= table_arg; }
00208   inline uint32 key_length()                 { return key_len; }
00209   inline void key_length(uint32 len)         { key_len= len; }
00210   inline uint8 type()                        { return table_type; }
00211   inline void type(uint8 t)                  { table_type= t; }
00212   inline qc_engine_callback callback()       { return callback_func; }
00213   inline void callback(qc_engine_callback fn){ callback_func= fn; }
00214   inline ulonglong engine_data()             { return engine_data_buff; }
00215   inline void engine_data(ulonglong data_arg){ engine_data_buff= data_arg; }
00216   inline uchar* data()
00217   {
00218     return (uchar*)(((uchar*)this)+
00219                   ALIGN_SIZE(sizeof(Query_cache_table)));
00220   }
00221 };
00222 
00223 struct Query_cache_result
00224 {
00225   Query_cache_result() {}                     /* Remove gcc warning */
00226   Query_cache_block *query;
00227 
00228   inline uchar* data()
00229   {
00230     return (uchar*)(((uchar*) this)+
00231                   ALIGN_SIZE(sizeof(Query_cache_result)));
00232   }
00233   /* data_continue (if not whole packet contained by this block) */
00234   inline Query_cache_block *parent()              { return query; }
00235   inline void parent (Query_cache_block *p)       { query=p; }
00236 };
00237 
00238 
00239 extern "C"
00240 {
00241   uchar *query_cache_query_get_key(const uchar *record, size_t *length,
00242                                    my_bool not_used);
00243   uchar *query_cache_table_get_key(const uchar *record, size_t *length,
00244                                    my_bool not_used);
00245 }
00246 extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
00247 
00248 
00249 struct Query_cache_memory_bin
00250 {
00251   Query_cache_memory_bin() {}                 /* Remove gcc warning */
00252 #ifndef DBUG_OFF
00253   ulong size;
00254 #endif
00255   uint number;
00256   Query_cache_block *free_blocks;
00257 
00258   inline void init(ulong size_arg)
00259   {
00260 #ifndef DBUG_OFF
00261     size = size_arg;
00262 #endif
00263     number = 0;
00264     free_blocks = 0;
00265   }
00266 };
00267 
00268 struct Query_cache_memory_bin_step
00269 {
00270   Query_cache_memory_bin_step() {}            /* Remove gcc warning */
00271   ulong size;
00272   ulong increment;
00273   uint idx;
00274   inline void init(ulong size_arg, uint idx_arg, ulong increment_arg)
00275   {
00276     size = size_arg;
00277     idx = idx_arg;
00278     increment = increment_arg;
00279   }
00280 };
00281 
00282 class Query_cache
00283 {
00284 public:
00285   /* Info */
00286   ulong query_cache_size, query_cache_limit;
00287   /* statistics */
00288   ulong free_memory, queries_in_cache, hits, inserts, refused,
00289     free_memory_blocks, total_blocks, lowmem_prunes;
00290 
00291 
00292 private:
00293 #ifndef DBUG_OFF
00294   my_thread_id m_cache_lock_thread_id;
00295 #endif
00296   mysql_cond_t COND_cache_status_changed;
00297   enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED };
00298   Cache_lock_status m_cache_lock_status;
00299 
00300   bool m_query_cache_is_disabled;
00301 
00302   void free_query_internal(Query_cache_block *point);
00303   void invalidate_table_internal(THD *thd, uchar *key, uint32 key_length);
00304   void disable_query_cache(void) { m_query_cache_is_disabled= TRUE; }
00305 
00306 protected:
00307   /*
00308     The following mutex is locked when searching or changing global
00309     query, tables lists or hashes. When we are operating inside the
00310     query structure we locked an internal query block mutex.
00311     LOCK SEQUENCE (to prevent deadlocks):
00312       1. structure_guard_mutex
00313       2. query block (for operation inside query (query block/results))
00314 
00315     Thread doing cache flush releases the mutex once it sets
00316     m_cache_status flag, so other threads may bypass the cache as
00317     if it is disabled, not waiting for reset to finish.  The exception
00318     is other threads that were going to do cache flush---they'll wait
00319     till the end of a flush operation.
00320   */
00321   mysql_mutex_t structure_guard_mutex;
00322   uchar *cache;                                 // cache memory
00323   Query_cache_block *first_block;               // physical location block list
00324   Query_cache_block *queries_blocks;            // query list (LIFO)
00325   Query_cache_block *tables_blocks;
00326 
00327   Query_cache_memory_bin *bins;                 // free block lists
00328   Query_cache_memory_bin_step *steps;           // bins spacing info
00329   HASH queries, tables;
00330   /* options */
00331   ulong min_allocation_unit, min_result_data_size;
00332   uint def_query_hash_size, def_table_hash_size;
00333   
00334   uint mem_bin_num, mem_bin_steps;              // See at init_cache & find_bin
00335 
00336   my_bool initialized;
00337 
00338   /* Exclude/include from cyclic double linked list */
00339   static void double_linked_list_exclude(Query_cache_block *point,
00340                                          Query_cache_block **list_pointer);
00341   static void double_linked_list_simple_include(Query_cache_block *point,
00342                                                 Query_cache_block **
00343                                                 list_pointer);
00344   static void double_linked_list_join(Query_cache_block *head_tail,
00345                                       Query_cache_block *tail_head);
00346 
00347   /* Table key generation */
00348   static uint filename_2_table_key (char *key, const char *filename,
00349                                     uint32 *db_langth);
00350 
00351   /* The following functions require that structure_guard_mutex is locked */
00352   void flush_cache();
00353   my_bool free_old_query();
00354   void free_query(Query_cache_block *point);
00355   my_bool allocate_data_chain(Query_cache_block **result_block,
00356                               ulong data_len,
00357                               Query_cache_block *query_block,
00358                               my_bool first_block);
00359   void invalidate_table(THD *thd, TABLE_LIST *table);
00360   void invalidate_table(THD *thd, TABLE *table);
00361   void invalidate_table(THD *thd, uchar *key, uint32  key_length);
00362   void invalidate_table(THD *thd, Query_cache_block *table_block);
00363   void invalidate_query_block_list(THD *thd, 
00364                                    Query_cache_block_table *list_root);
00365 
00366   TABLE_COUNTER_TYPE
00367     register_tables_from_list(TABLE_LIST *tables_used,
00368                               TABLE_COUNTER_TYPE counter,
00369                               Query_cache_block_table *block_table);
00370   my_bool register_all_tables(Query_cache_block *block,
00371                               TABLE_LIST *tables_used,
00372                               TABLE_COUNTER_TYPE tables);
00373   my_bool insert_table(uint key_len, const char *key,
00374                        Query_cache_block_table *node,
00375                        uint32 db_length, uint8 cache_type,
00376                        qc_engine_callback callback,
00377                        ulonglong engine_data);
00378   void unlink_table(Query_cache_block_table *node);
00379   Query_cache_block *get_free_block (ulong len, my_bool not_less,
00380                                       ulong min);
00381   void free_memory_block(Query_cache_block *point);
00382   void split_block(Query_cache_block *block, ulong len);
00383   Query_cache_block *join_free_blocks(Query_cache_block *first_block,
00384                                        Query_cache_block *block_in_list);
00385   my_bool append_next_free_block(Query_cache_block *block,
00386                                  ulong add_size);
00387   void exclude_from_free_memory_list(Query_cache_block *free_block);
00388   void insert_into_free_memory_list(Query_cache_block *new_block);
00389   my_bool move_by_type(uchar **border, Query_cache_block **before,
00390                        ulong *gap, Query_cache_block *i);
00391   uint find_bin(ulong size);
00392   void move_to_query_list_end(Query_cache_block *block);
00393   void insert_into_free_memory_sorted_list(Query_cache_block *new_block,
00394                                            Query_cache_block **list);
00395   void pack_cache();
00396   void relink(Query_cache_block *oblock,
00397               Query_cache_block *nblock,
00398               Query_cache_block *next,
00399               Query_cache_block *prev,
00400               Query_cache_block *pnext,
00401               Query_cache_block *pprev);
00402   my_bool join_results(ulong join_limit);
00403 
00404   /*
00405     Following function control structure_guard_mutex
00406     by themself or don't need structure_guard_mutex
00407   */
00408   ulong init_cache();
00409   void make_disabled();
00410   void free_cache();
00411   Query_cache_block *write_block_data(ulong data_len, uchar* data,
00412                                        ulong header_len,
00413                                        Query_cache_block::block_type type,
00414                                        TABLE_COUNTER_TYPE ntab = 0);
00415   my_bool append_result_data(Query_cache_block **result,
00416                              ulong data_len, uchar* data,
00417                              Query_cache_block *parent);
00418   my_bool write_result_data(Query_cache_block **result,
00419                             ulong data_len, uchar* data,
00420                             Query_cache_block *parent,
00421                             Query_cache_block::block_type
00422                             type=Query_cache_block::RESULT);
00423   inline ulong get_min_first_result_data_size();
00424   inline ulong get_min_append_result_data_size();
00425   Query_cache_block *allocate_block(ulong len, my_bool not_less,
00426                                      ulong min);
00427   /*
00428     If query is cacheable return number tables in query
00429     (query without tables not cached)
00430   */
00431   TABLE_COUNTER_TYPE is_cacheable(THD *thd, size_t query_len,
00432                                   const char *query,
00433                                   LEX *lex, TABLE_LIST *tables_used,
00434                                   uint8 *tables_type);
00435   TABLE_COUNTER_TYPE process_and_count_tables(THD *thd,
00436                                               TABLE_LIST *tables_used,
00437                                               uint8 *tables_type);
00438 
00439   static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used);
00440  public:
00441 
00442   Query_cache(ulong query_cache_limit = ULONG_MAX,
00443               ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT,
00444               ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE,
00445               uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE,
00446               uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE);
00447 
00448   bool is_disabled(void) { return m_query_cache_is_disabled; }
00449 
00450   /* initialize cache (mutex) */
00451   void init();
00452   /* resize query cache (return real query size, 0 if disabled) */
00453   ulong resize(ulong query_cache_size);
00454   /* set limit on result size */
00455   inline void result_size_limit(ulong limit){query_cache_limit=limit;}
00456   /* set minimal result data allocation unit size */
00457   ulong set_min_res_unit(ulong size);
00458 
00459   /* register query in cache */
00460   void store_query(THD *thd, TABLE_LIST *used_tables);
00461 
00462   /*
00463     Check if the query is in the cache and if this is true send the
00464     data to client.
00465   */
00466   int send_result_to_client(THD *thd, char *query, uint query_length);
00467 
00468   /* Remove all queries that uses any of the listed following tables */
00469   void invalidate(THD* thd, TABLE_LIST *tables_used,
00470                   my_bool using_transactions);
00471   void invalidate(CHANGED_TABLE_LIST *tables_used);
00472   void invalidate_locked_for_write(TABLE_LIST *tables_used);
00473   void invalidate(THD* thd, TABLE *table, my_bool using_transactions);
00474   void invalidate(THD *thd, const char *key, uint32  key_length,
00475                   my_bool using_transactions);
00476 
00477   /* Remove all queries that uses any of the tables in following database */
00478   void invalidate(char *db);
00479 
00480   /* Remove all queries that uses any of the listed following table */
00481   void invalidate_by_MyISAM_filename(const char *filename);
00482 
00483   void flush();
00484   void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT,
00485             uint iteration_limit = QUERY_CACHE_PACK_ITERATION);
00486 
00487   void destroy();
00488 
00489   void insert(Query_cache_tls *query_cache_tls,
00490               const char *packet,
00491               ulong length,
00492               unsigned pkt_nr);
00493 
00494   void end_of_result(THD *thd);
00495   void abort(Query_cache_tls *query_cache_tls);
00496 
00497   /*
00498     The following functions are only used when debugging
00499     We don't protect these with ifndef DBUG_OFF to not have to recompile
00500     everything if we want to add checks of the cache at some places.
00501   */
00502   void wreck(uint line, const char *message);
00503   void bins_dump();
00504   void cache_dump();
00505   void queries_dump();
00506   void tables_dump();
00507   my_bool check_integrity(bool not_locked);
00508   my_bool in_list(Query_cache_block * root, Query_cache_block * point,
00509                   const char *name);
00510   my_bool in_table_list(Query_cache_block_table * root,
00511                         Query_cache_block_table * point,
00512                         const char *name);
00513   my_bool in_blocks(Query_cache_block * point);
00514 
00515   bool try_lock(bool use_timeout= FALSE);
00516   void lock(void);
00517   void lock_and_suspend(void);
00518   void unlock(void);
00519 };
00520 
00521 #ifdef HAVE_QUERY_CACHE
00522 struct Query_cache_query_flags
00523 {
00524   unsigned int client_long_flag:1;
00525   unsigned int client_protocol_41:1;
00526   unsigned int protocol_type:2;
00527   unsigned int more_results_exists:1;
00528   unsigned int in_trans:1;
00529   unsigned int autocommit:1;
00530   unsigned int pkt_nr;
00531   uint character_set_client_num;
00532   uint character_set_results_num;
00533   uint collation_connection_num;
00534   ha_rows limit;
00535   Time_zone *time_zone;
00536   sql_mode_t sql_mode;
00537   ulong max_sort_length;
00538   ulong group_concat_max_len;
00539   ulong default_week_format;
00540   ulong div_precision_increment;
00541   MY_LOCALE *lc_time_names;
00542 };
00543 #define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
00544 #include "sql_cache.h"
00545 #define query_cache_abort(A) query_cache.abort(A)
00546 #define query_cache_end_of_result(A) query_cache.end_of_result(A)
00547 #define query_cache_store_query(A, B) query_cache.store_query(A, B)
00548 #define query_cache_destroy() query_cache.destroy()
00549 #define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
00550 #define query_cache_init() query_cache.init()
00551 #define query_cache_resize(A) query_cache.resize(A)
00552 #define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A)
00553 #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
00554 #define query_cache_invalidate1(A) query_cache.invalidate(A)
00555 #define query_cache_send_result_to_client(A, B, C) \
00556   query_cache.send_result_to_client(A, B, C)
00557 #define query_cache_invalidate_by_MyISAM_filename_ref \
00558   &query_cache_invalidate_by_MyISAM_filename
00559 /* note the "maybe": it's a read without mutex */
00560 #define query_cache_maybe_disabled(T)                                 \
00561   (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0)
00562 #define query_cache_is_cacheable_query(L) \
00563   (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query && \
00564    !(L)->describe)
00565 #else
00566 #define QUERY_CACHE_FLAGS_SIZE 0
00567 #define query_cache_store_query(A, B)
00568 #define query_cache_destroy()
00569 #define query_cache_result_size_limit(A)
00570 #define query_cache_init()
00571 #define query_cache_resize(A)
00572 #define query_cache_set_min_res_unit(A)
00573 #define query_cache_invalidate3(A, B, C)
00574 #define query_cache_invalidate1(A)
00575 #define query_cache_send_result_to_client(A, B, C) 0
00576 #define query_cache_invalidate_by_MyISAM_filename_ref NULL
00577 
00578 #define query_cache_abort(A)
00579 #define query_cache_end_of_result(A)
00580 #define query_cache_invalidate_by_MyISAM_filename_ref NULL
00581 #define query_cache_maybe_disabled(T) 1
00582 #define query_cache_is_cacheable_query(L) 0
00583 #endif /*HAVE_QUERY_CACHE*/
00584 
00585 extern Query_cache query_cache;
00586 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines