summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@hundin.mysql.fi>2001-12-02 14:34:01 +0200
committerunknown <monty@hundin.mysql.fi>2001-12-02 14:34:01 +0200
commit7c999bb03223114a4d07f23db2842363d32d1859 (patch)
tree8e30a64d5c7aaa0ba8554c4c316cc9b76a6724ca
parent95e94560eac0ee72bbc566517ca70f14128a01e8 (diff)
downloadmariadb-git-7c999bb03223114a4d07f23db2842363d32d1859.tar.gz
Query cache.
Remove some warnings Docs/manual.texi: Solaris and gcc include/ft_global.h: Remove warnings include/myisam.h: Query cache include/myisammrg.h: Query cache include/mysql_com.h: Query cache libmysqld/lib_sql.cc: Query cache myisam/ft_boolean_search.c: Remove warnings myisam/ft_dump.c: Remove warnings myisam/ft_parser.c: Remove warnings myisam/ft_static.c: Remove warnings myisam/ft_update.c: Remove warnings myisam/ftdefs.h: Remove warnings myisam/mi_delete.c: Query cache myisam/mi_locking.c: Query cache myisam/mi_update.c: Query cache myisam/myisamdef.h: Optimize for Ia64 myisammrg/myrg_extra.c: Query cache mysys/mf_keycache.c: DBUG statements regex/cclass.h: Remove warnings regex/cname.h: Remove warnings regex/main.c: Remove warnings regex/regcomp.c: Remove warnings regex/regcomp.ih: Remove warnings regex/regerror.c: Remove warnings regex/reginit.c: Remove warnings regex/split.c: Remove warnings sql-bench/test-connect.sh: Make tests query-cache safe. sql-bench/test-transactions.sh: Fix for old perl versions sql/convert.cc: Query cache sql/ha_myisammrg.cc: Query cache sql/ha_myisammrg.h: Query cache sql/handler.cc: Query cache sql/item_create.cc: Query cache sql/item_func.cc: Remove warnings sql/item_func.h: Remove warnings sql/lex.h: Query cache sql/mysql_priv.h: Query cache sql/mysqld.cc: Query cache sql/net_serv.cc: Query cache sql/sql_cache.cc: Query cache sql/sql_class.cc: Query cache sql/sql_class.h: Query cache sql/sql_db.cc: Query cache sql/sql_delete.cc: Query cache sql/sql_insert.cc: Query cache sql/sql_parse.cc: Query cache sql/sql_select.cc: Query cache sql/sql_table.cc: Query cache sql/sql_update.cc: Query cache sql/sql_yacc.yy: Query cache
-rw-r--r--Docs/manual.texi8
-rw-r--r--include/ft_global.h2
-rw-r--r--include/myisam.h2
-rw-r--r--include/myisammrg.h1
-rw-r--r--include/mysql_com.h4
-rw-r--r--libmysqld/lib_sql.cc2
-rw-r--r--myisam/ft_boolean_search.c6
-rw-r--r--myisam/ft_dump.c16
-rw-r--r--myisam/ft_parser.c5
-rw-r--r--myisam/ft_static.c2
-rw-r--r--myisam/ft_update.c5
-rw-r--r--myisam/ftdefs.h2
-rw-r--r--myisam/mi_delete.c6
-rw-r--r--myisam/mi_locking.c5
-rw-r--r--myisam/mi_update.c6
-rw-r--r--myisam/myisamdef.h80
-rw-r--r--myisammrg/myrg_extra.c10
-rw-r--r--mysys/mf_keycache.c25
-rw-r--r--regex/cclass.h6
-rw-r--r--regex/cname.h4
-rw-r--r--regex/main.c16
-rw-r--r--regex/regcomp.c72
-rw-r--r--regex/regcomp.ih2
-rw-r--r--regex/regerror.c8
-rw-r--r--regex/reginit.c2
-rw-r--r--regex/split.c2
-rw-r--r--sql-bench/test-connect.sh64
-rw-r--r--sql-bench/test-transactions.sh5
-rw-r--r--sql/convert.cc20
-rw-r--r--sql/ha_myisammrg.cc7
-rw-r--r--sql/ha_myisammrg.h1
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/item_create.cc12
-rw-r--r--sql/item_func.cc6
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/lex.h7
-rw-r--r--sql/mysql_priv.h5
-rw-r--r--sql/mysqld.cc74
-rw-r--r--sql/net_serv.cc6
-rw-r--r--sql/sql_cache.cc2530
-rw-r--r--sql/sql_cache.h402
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_class.h17
-rw-r--r--sql/sql_db.cc1
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_insert.cc6
-rw-r--r--sql/sql_parse.cc43
-rw-r--r--sql/sql_select.cc1
-rw-r--r--sql/sql_table.cc16
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_yacc.yy112
51 files changed, 3363 insertions, 292 deletions
diff --git a/Docs/manual.texi b/Docs/manual.texi
index 1e64a53ffbc..7b9479861b9 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -8528,6 +8528,14 @@ libc internal error: _rmutex_unlock: rmutex not held
Add @code{-mt} to @code{CFLAGS} and @code{CXXFLAGS} and try again.
+If you are using the SFW version of gcc (which comes with Solaris 8),
+you must add @file{/opt/sfw/lib} to the environment variable
+@code{LD_LIBRARY_PATH} before running configure.
+
+If you are using the gcc available from @code{sunfreeware.com}, you may
+have many problems. You should recompile gcc and GNU binutils on the
+machine you will be running them from to avoid any problems.
+
If you get the following error when compiling MySQL with @code{gcc},
it means that your @code{gcc} is not configured for your version of Solaris:
diff --git a/include/ft_global.h b/include/ft_global.h
index 064dd7a6538..e4b63aecbb2 100644
--- a/include/ft_global.h
+++ b/include/ft_global.h
@@ -49,7 +49,7 @@ extern const char *ft_precompiled_stopwords[];
extern ulong ft_min_word_len;
extern ulong ft_max_word_len;
extern ulong ft_max_word_len_for_sort;
-extern char *ft_boolean_syntax;
+extern const char *ft_boolean_syntax;
int ft_init_stopwords(const char **);
void ft_free_stopwords(void);
diff --git a/include/myisam.h b/include/myisam.h
index 36c0de5034f..352b87c82c2 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -191,6 +191,8 @@ typedef struct st_columndef /* column information */
#endif
} MI_COLUMNDEF;
+/* invalidator function reference for Query Cache */
+typedef void (* invalidator_by_filename) (char * filename);
extern my_string myisam_log_filename; /* Name of logfile */
extern uint myisam_block_size;
diff --git a/include/myisammrg.h b/include/myisammrg.h
index 1ae825b4b94..0230f077814 100644
--- a/include/myisammrg.h
+++ b/include/myisammrg.h
@@ -95,6 +95,7 @@ extern int myrg_lock_database(MYRG_INFO *file,int lock_type);
extern int myrg_create(const char *name, const char **table_names,
uint insert_method, my_bool fix_names);
extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function);
+extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv);
extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx,
const byte *start_key,uint start_key_len,
enum ha_rkey_function start_search_flag,
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 048b6b98918..16f603516f9 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -78,6 +78,9 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
#define REFRESH_READ_LOCK 16384 /* Lock tables for read */
#define REFRESH_FAST 32768 /* Intern flag */
+#define REFRESH_QUERY_CACHE 65536 /* flush query cache */
+#define REFRESH_QUERY_CACHE_FREE 0x10000L /* pack query cache */
+
#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
#define CLIENT_LONG_FLAG 4 /* Get all column flags */
@@ -126,6 +129,7 @@ typedef struct st_net {
unsigned char reading_or_writing;
char save_char;
my_bool no_send_ok;
+ gptr query_cache_query;
} NET;
#define packet_error (~(unsigned long) 0)
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index d241ceaada0..ab82b8de2f2 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -460,7 +460,7 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups)
umask(((~my_umask) & 0666));
table_cache_init();
hostname_cache_init();
- sql_cache_init();
+ /*sql_cache_init();*/
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c
index 0055842c24b..e7baad64d61 100644
--- a/myisam/ft_boolean_search.c
+++ b/myisam/ft_boolean_search.c
@@ -86,7 +86,7 @@ typedef struct st_ft_info {
MEM_ROOT mem_root;
} FTB;
-int FTB_WORD_cmp(void *v, byte *a, byte *b)
+int FTB_WORD_cmp(void *v __attribute__((unused)), byte *a, byte *b)
{
/* ORDER BY docid, ndepth DESC */
int i=CMP_NUM(((FTB_WORD *)a)->docid, ((FTB_WORD *)b)->docid);
@@ -109,7 +109,7 @@ void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
return;
param.prev=' ';
- while (res=ft_get_word(start,end,&w,&param))
+ while ((res=ft_get_word(start,end,&w,&param)))
{
byte r=param.plusminus;
float weight=(param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
@@ -280,7 +280,7 @@ void _ftb_climb_the_tree(FTB_WORD *ftbw, my_off_t curdoc)
int ft_boolean_read_next(FT_INFO *ftb, char *record)
{
- FTB_EXPR *ftbe, *up;
+ FTB_EXPR *ftbe;
FTB_WORD *ftbw;
MI_INFO *info=ftb->info;
MI_KEYDEF *keyinfo=info->s->keyinfo+ftb->keynr;
diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c
index 940164f89c5..0d5fa7c8fd6 100644
--- a/myisam/ft_dump.c
+++ b/myisam/ft_dump.c
@@ -184,14 +184,14 @@ static void get_options(int argc, char *argv[])
static void usage(char *argv[])
{
- printf("
-Use: %s [-%s] <table_name> <index_no>
-
--d dump index (incl. data offsets and word weights)
--s report global stats
--c calculate per-word stats (counts and global weights)
--v be verbose
--h this text\n
+ printf("\n\
+Use: %s [-%s] <table_name> <index_no>\n\
+\n\
+-d dump index (incl. data offsets and word weights)\n\
+-s report global stats\n\
+-c calculate per-word stats (counts and global weights)\n\
+-v be verbose\n\
+-h this text\n\
", *argv, options);
exit(1);
}
diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c
index 0d1495da548..c1b1190bcab 100644
--- a/myisam/ft_parser.c
+++ b/myisam/ft_parser.c
@@ -38,8 +38,9 @@ typedef struct st_ft_docstat {
static int FT_WORD_cmp(void* cmp_arg, FT_WORD *w1, FT_WORD *w2)
{
return _mi_compare_text(default_charset_info,
- (uchar*) w1->pos,w1->len,
- (uchar*) w2->pos, w2->len,(my_bool)cmp_arg);
+ (uchar*) w1->pos, w1->len,
+ (uchar*) w2->pos, w2->len,
+ (my_bool) (cmp_arg != 0));
}
static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
diff --git a/myisam/ft_static.c b/myisam/ft_static.c
index 08ecbdc1009..566b08596a3 100644
--- a/myisam/ft_static.c
+++ b/myisam/ft_static.c
@@ -21,7 +21,7 @@
ulong ft_min_word_len=4;
ulong ft_max_word_len=HA_FT_MAXLEN;
ulong ft_max_word_len_for_sort=20;
-char *ft_boolean_syntax="+ -><()~*";
+const char *ft_boolean_syntax="+ -><()~*";
const MI_KEYSEG ft_keysegs[FT_SEGS]={
{
diff --git a/myisam/ft_update.c b/myisam/ft_update.c
index 1bc0ace6c77..3d394eeacac 100644
--- a/myisam/ft_update.c
+++ b/myisam/ft_update.c
@@ -67,8 +67,9 @@ uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record)
return 0;
}
-FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf,
- const byte *record)
+FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr,
+ byte *keybuf __attribute__((unused)),
+ const byte *record)
{
TREE ptree;
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
index 147c3f5b5e6..ee35ccbb14a 100644
--- a/myisam/ftdefs.h
+++ b/myisam/ftdefs.h
@@ -123,6 +123,7 @@ byte ft_simple_get_word(byte **, byte *, FT_WORD *);
int ft_parse(TREE *, byte *, int);
FT_WORD * ft_linearize(/*MI_INFO *, uint, byte *, */TREE *);
FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, byte *, const byte *);
+uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record);
const struct _ft_vft _ft_vft_nlq;
FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, my_bool);
@@ -141,4 +142,3 @@ void ft_boolean_close_search(FT_INFO *);
float ft_boolean_get_relevance(FT_INFO *);
my_off_t ft_boolean_get_docid(FT_INFO *);
void ft_boolean_reinit_search(FT_INFO *);
-
diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c
index 65d245e64f9..2a0cd6f6b6d 100644
--- a/myisam/mi_delete.c
+++ b/myisam/mi_delete.c
@@ -97,6 +97,12 @@ int mi_delete(MI_INFO *info,const byte *record)
myisam_log_command(MI_LOG_DELETE,info,(byte*) lastpos,sizeof(lastpos),0);
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
allow_break(); /* Allow SIGHUP & SIGINT */
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (delete)", info->filename));
+ (*info->invalidator)(info->filename);
+ info->invalidator=0;
+ }
DBUG_RETURN(0);
err:
diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c
index 68ef52ea819..22ec4ba875c 100644
--- a/myisam/mi_locking.c
+++ b/myisam/mi_locking.c
@@ -43,8 +43,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
pthread_mutex_lock(&share->intern_lock);
if (share->kfile >= 0) /* May only be false on windows */
{
- switch (lock_type)
- {
+ switch (lock_type) {
case F_UNLCK:
if (info->lock_type == F_RDLCK)
count= --share->r_locks;
@@ -201,6 +200,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
}
VOID(_mi_test_if_changed(info));
info->lock_type=lock_type;
+ info->invalidator=info->s->invalidator;
share->w_locks++;
share->tot_locks++;
break;
@@ -319,6 +319,7 @@ int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
}
if (check_keybuffer)
VOID(_mi_test_if_changed(info));
+ info->invalidator=info->s->invalidator;
}
else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
{
diff --git a/myisam/mi_update.c b/myisam/mi_update.c
index ac843dbb6bd..bb022c5f4cd 100644
--- a/myisam/mi_update.c
+++ b/myisam/mi_update.c
@@ -136,6 +136,12 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
myisam_log_record(MI_LOG_UPDATE,info,newrec,info->lastpos,0);
VOID(_mi_writeinfo(info,key_changed ? WRITEINFO_UPDATE_KEYFILE : 0));
allow_break(); /* Allow SIGHUP & SIGINT */
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (update)", info->filename));
+ (*info->invalidator)(info->filename);
+ info->invalidator=0;
+ }
DBUG_RETURN(0);
err:
diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h
index e8b9c1b83ec..203101a2f48 100644
--- a/myisam/myisamdef.h
+++ b/myisam/myisamdef.h
@@ -66,8 +66,10 @@ typedef struct st_mi_state_info
ulong unique; /* Unique number for this process */
ulong update_count; /* Updated for each write lock */
ulong status;
+ ulong *rec_per_key_part;
my_off_t *key_root; /* Start of key trees */
my_off_t *key_del; /* delete links for trees */
+ my_off_t rec_per_key_rows; /* Rows when calculating rec_per_key */
ulong sec_index_changed; /* Updated when new sec_index */
ulong sec_index_used; /* which extra index are in use */
@@ -80,8 +82,6 @@ typedef struct st_mi_state_info
uint sortkey; /* sorted by this key (not used) */
uint open_count;
uint8 changed; /* Changed since myisamchk */
- my_off_t rec_per_key_rows; /* Rows when calculating rec_per_key */
- ulong *rec_per_key_part;
/* the following isn't saved on disk */
uint state_diff_length; /* Should be 0 */
@@ -164,10 +164,25 @@ typedef struct st_mi_isam_share { /* Shared between opens */
char *data_file_name, /* Resolved path names from symlinks */
*index_file_name;
byte *file_map; /* mem-map of file if possible */
+ MI_DECODE_TREE *decode_trees;
+ uint16 *decode_tables;
+ int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
+ int (*write_record)(struct st_myisam_info*, const byte*);
+ int (*update_record)(struct st_myisam_info*, my_off_t, const byte*);
+ int (*delete_record)(struct st_myisam_info*);
+ int (*read_rnd)(struct st_myisam_info*, byte*, my_off_t, my_bool);
+ int (*compare_record)(struct st_myisam_info*, const byte *);
+ ha_checksum (*calc_checksum)(struct st_myisam_info*, const byte *);
+ int (*compare_unique)(struct st_myisam_info*, MI_UNIQUEDEF *,
+ const byte *record, my_off_t pos);
+ invalidator_by_filename invalidator; /* query cache invalidator */
ulong this_process; /* processid */
ulong last_process; /* For table-change-check */
ulong last_version; /* Version on start */
ulong options; /* Options used */
+ ulong min_pack_length; /* Theese are used by packed data */
+ ulong max_pack_length;
+ ulong state_diff_length;
uint rec_reflength; /* rec_reflength in use now */
File kfile; /* Shared keyfile */
File data_file; /* Shared data file */
@@ -175,29 +190,15 @@ typedef struct st_mi_isam_share { /* Shared between opens */
uint reopen; /* How many times reopened */
uint w_locks,r_locks,tot_locks; /* Number of read/write locks */
uint blocksize; /* blocksize of keyfile */
- ulong min_pack_length; /* Theese are used by packed data */
- ulong max_pack_length;
- ulong state_diff_length;
+ myf write_flag;
+ int rnd; /* rnd-counter */
+ enum data_file_type data_file_type;
my_bool changed, /* If changed since lock */
global_changed, /* If changed since open */
not_flushed,
temporary,delay_key_write,
concurrent_insert,
fulltext_index;
- myf write_flag;
- int rnd; /* rnd-counter */
- MI_DECODE_TREE *decode_trees;
- uint16 *decode_tables;
- enum data_file_type data_file_type;
- int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
- int (*write_record)(struct st_myisam_info*, const byte*);
- int (*update_record)(struct st_myisam_info*, my_off_t, const byte*);
- int (*delete_record)(struct st_myisam_info*);
- int (*read_rnd)(struct st_myisam_info*, byte*, my_off_t, my_bool);
- int (*compare_record)(struct st_myisam_info*, const byte *);
- ha_checksum (*calc_checksum)(struct st_myisam_info*, const byte *);
- int (*compare_unique)(struct st_myisam_info*, MI_UNIQUEDEF *,
- const byte *record, my_off_t pos);
#ifdef THREAD
THR_LOCK lock;
pthread_mutex_t intern_lock; /* Locking for use with _locking */
@@ -215,16 +216,22 @@ typedef struct st_mi_bit_buff { /* Used for packing of record */
uint error;
} MI_BIT_BUFF;
-
struct st_myisam_info {
MYISAM_SHARE *s; /* Shared between open:s */
MI_STATUS_INFO *state,save_state;
MI_BLOB *blobs; /* Pointer to blobs */
- int dfile; /* The datafile */
- MI_BIT_BUFF bit_buff;
- uint opt_flag; /* Optim. for space/speed */
- uint update; /* If file changed since open */
+ MI_BIT_BUFF bit_buff;
+ /* accumulate indexfile changes between write's */
+ TREE *bulk_insert;
char *filename; /* parameter to open filename */
+ uchar *buff, /* Temp area for key */
+ *lastkey,*lastkey2; /* Last used search key */
+ byte *rec_buff, /* Tempbuff for recordpack */
+ *rec_alloc; /* Malloced area for record */
+ uchar *int_keypos, /* Save position for next/previous */
+ *int_maxpos; /* -""- */
+ int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
+ invalidator_by_filename invalidator; /* query cache invalidator */
ulong this_unique; /* uniq filenumber or thread */
ulong last_unique; /* last unique number */
ulong this_loop; /* counter for this open */
@@ -233,20 +240,16 @@ struct st_myisam_info {
nextpos; /* Position to next record */
my_off_t save_lastpos;
my_off_t pos; /* Intern variable */
+ my_off_t last_keypage; /* Last key page read */
+ my_off_t last_search_keypage; /* Last keypage when searching */
+ my_off_t dupp_key_pos;
ha_checksum checksum;
ulong packed_length,blob_length; /* Length of found, packed record */
+ int dfile; /* The datafile */
+ uint opt_flag; /* Optim. for space/speed */
+ uint update; /* If file changed since open */
uint alloced_rec_buff_length; /* Max recordlength malloced */
- uchar *buff, /* Temp area for key */
- *lastkey,*lastkey2; /* Last used search key */
- byte *rec_buff, /* Tempbuff for recordpack */
- *rec_alloc; /* Malloced area for record */
- uchar *int_keypos, /* Save position for next/previous */
- *int_maxpos; /* -""- */
- uint32 int_keytree_version; /* -""- */
uint int_nod_flag; /* -""- */
- my_off_t last_keypage; /* Last key page read */
- my_off_t last_search_keypage; /* Last keypage when searching */
- my_off_t dupp_key_pos;
int lastinx; /* Last used index */
uint lastkey_length; /* Length of key in lastkey */
uint last_rkey_length; /* Last length in mi_rkey() */
@@ -257,16 +260,15 @@ struct st_myisam_info {
uint data_changed; /* Somebody has changed data */
uint save_update; /* When using KEY_READ */
int save_lastinx;
+ uint32 int_keytree_version; /* -""- */
+ LIST open_list;
+ IO_CACHE rec_cache; /* When cacheing records */
+ myf lock_wait; /* is 0 or MY_DONT_WAIT */
my_bool was_locked; /* Was locked in panic */
my_bool quick_mode;
my_bool page_changed; /* If info->buff can't be used for rnext */
my_bool buff_used; /* If info->buff has to be reread for rnext */
my_bool use_packed_key; /* For MYISAMMRG */
- TREE *bulk_insert; /* accumulate indexfile changes between mi_write's */
- myf lock_wait; /* is 0 or MY_DONT_WAIT */
- int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
- LIST open_list;
- IO_CACHE rec_cache; /* When cacheing records */
#ifdef THREAD
THR_LOCK_DATA lock;
#endif
diff --git a/myisammrg/myrg_extra.c b/myisammrg/myrg_extra.c
index 315abe0f29e..912eeb1f9e6 100644
--- a/myisammrg/myrg_extra.c
+++ b/myisammrg/myrg_extra.c
@@ -46,3 +46,13 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function)
}
DBUG_RETURN(save_error);
}
+
+void myrg_extrafunc(MYRG_INFO *info, invalidator_by_filename inv)
+{
+ MYRG_TABLE *file;
+
+ DBUG_ENTER("myrg_extrafunc");
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ file->table->s->invalidator = inv;
+ DBUG_VOID_RETURN;
+}
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 87f6ca2717c..330eeeb6f6f 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -252,6 +252,9 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
{
reg1 SEC_LINK *next;
int error=0;
+ DBUG_ENTER("key_cache_read");
+ DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
+ (uint) file, (ulong) filepos, length));
#ifndef THREAD
if (block_length > key_cache_block_size)
@@ -270,14 +273,14 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
if (!(next=find_key_block(file,filepos,&error)))
{
pthread_mutex_unlock(&THR_LOCK_keycache);
- return (byte*) 0; /* Got a fatal error */
+ DBUG_RETURN ((byte*) 0); /* Got a fatal error */
}
if (error)
{ /* Didn't find it in cache */
if (my_pread(file,next->buffer,read_length,filepos,MYF(MY_NABP)))
{
pthread_mutex_unlock(&THR_LOCK_keycache);
- return((byte*) 0);
+ DBUG_RETURN((byte*) 0);
}
_my_cache_read++;
}
@@ -285,7 +288,7 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
if (return_buffer)
{
pthread_mutex_unlock(&THR_LOCK_keycache);
- return (next->buffer);
+ DBUG_RETURN (next->buffer);
}
#endif
if (! (read_length & 511))
@@ -296,13 +299,13 @@ byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
filepos+=read_length;
} while ((length-= read_length));
pthread_mutex_unlock(&THR_LOCK_keycache);
- return(start);
+ DBUG_RETURN(start);
}
_my_cache_r_requests++;
_my_cache_read++;
if (my_pread(file,(byte*) buff,length,filepos,MYF(MY_NABP)))
error=1;
- return (error ? (byte*) 0 : buff);
+ DBUG_RETURN(error ? (byte*) 0 : buff);
} /* key_cache_read */
@@ -316,12 +319,15 @@ int key_cache_write(File file, my_off_t filepos, byte *buff, uint length,
{
reg1 SEC_LINK *next;
int error=0;
+ DBUG_ENTER("key_cache_write");
+ DBUG_PRINT("enter", ("file %u, filepos %lu, length %u",
+ (uint) file, (ulong) filepos, length));
if (!dont_write)
{ /* Forced write of buffer */
_my_cache_write++;
if (my_pwrite(file,buff,length,filepos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
- return(1);
+ DBUG_RETURN(1);
}
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
@@ -367,7 +373,7 @@ end:
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache",test_key_cache("end of key_cache_write",1););
#endif
- return(error);
+ DBUG_RETURN(error);
} /* key_cache_write */
@@ -377,6 +383,9 @@ end:
static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
{
reg1 SEC_LINK *next,**start;
+ DBUG_ENTER("find_key_block");
+ DBUG_PRINT("enter", ("file %u, filepos %lu",
+ (uint) file, (ulong) filepos));
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache2",test_key_cache("start of find_key_block",0););
@@ -461,7 +470,7 @@ static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
DBUG_EXECUTE("check_keycache2",test_key_cache("end of find_key_block",0););
#endif
- return next;
+ DBUG_RETURN(next);
} /* find_key_block */
diff --git a/regex/cclass.h b/regex/cclass.h
index 7d9a7ccc7c2..e0f752f38b8 100644
--- a/regex/cclass.h
+++ b/regex/cclass.h
@@ -15,7 +15,7 @@
#define CCLASS_LAST 12
extern struct cclass {
- char *name;
- char *chars;
- char *multis;
+ const char *name;
+ const char *chars;
+ const char *multis;
} cclasses[];
diff --git a/regex/cname.h b/regex/cname.h
index 2b6a1a8496f..06865f3e102 100644
--- a/regex/cname.h
+++ b/regex/cname.h
@@ -1,7 +1,7 @@
/* character-name table */
static struct cname {
- char *name;
- char code;
+ const char *name;
+ const char code;
} cnames[] = {
{"NUL", '\0'},
{"SOH", '\001'},
diff --git a/regex/main.c b/regex/main.c
index eac7293bf45..7844a4d8384 100644
--- a/regex/main.c
+++ b/regex/main.c
@@ -133,9 +133,9 @@ FILE *in;
int i;
char erbuf[100];
size_t ne;
- char *badpat = "invalid regular expression";
+ const char *badpat = "invalid regular expression";
# define SHORT 10
- char *bpname = "REG_BADPAT";
+ const char *bpname = "REG_BADPAT";
regex_t re;
while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
@@ -152,7 +152,7 @@ FILE *in;
}
for (i = 0; i < nf; i++)
if (strcmp(f[i], "\"\"") == 0)
- f[i] = "";
+ f[i] = (char*) "";
if (nf <= 3)
f[3] = NULL;
if (nf <= 4)
@@ -217,7 +217,7 @@ int opts; /* may not match f1 */
char erbuf[100];
int err;
int len;
- char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
+ const char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
register int i;
char *grump;
char f0copy[1000];
@@ -291,7 +291,7 @@ int opts; /* may not match f1 */
nshould = split(f4, should+1, NSHOULD-1, ",");
if (nshould == 0) {
nshould = 1;
- should[1] = "";
+ should[1] = (char*) "";
}
for (i = 1; i < NSUBS; i++) {
grump = check(f2, subs[i], should[i]);
@@ -317,7 +317,7 @@ char *s;
{
register char *p;
register int o = (type == 'c') ? copts : eopts;
- register char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
+ register const char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
for (p = s; *p != '\0'; p++)
if (strchr(legal, *p) != NULL)
@@ -417,7 +417,7 @@ char *should;
should = NULL;
if (should != NULL && should[0] == '@') {
at = should + 1;
- should = "";
+ should = (char*) "";
}
/* check rm_so and rm_eo for consistency */
@@ -434,7 +434,7 @@ char *should;
if (sub.rm_so == -1 && should == NULL)
return(NULL);
if (sub.rm_so == -1)
- return("did not match");
+ return((char*) "did not match");
/* check for in range */
if ((int) sub.rm_eo > (int) strlen(str)) {
diff --git a/regex/regcomp.c b/regex/regcomp.c
index 688b8ce7464..6f8221a706d 100644
--- a/regex/regcomp.c
+++ b/regex/regcomp.c
@@ -219,7 +219,7 @@ int stop; /* character this ERE should end at */
conc = HERE();
while (MORE() && (c = PEEK()) != '|' && c != stop)
p_ere_exp(p);
- if(REQUIRE(HERE() != conc, REG_EMPTY)); /* require nonempty */
+ if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */
if (!EAT('|'))
break; /* NOTE BREAK OUT */
@@ -266,11 +266,11 @@ register struct parse *p;
pos = HERE();
switch (c) {
case '(':
- if(REQUIRE(MORE(), REG_EPAREN));
+ if(REQUIRE(MORE(), REG_EPAREN)) {}
p->g->nsub++;
subno = (sopno) p->g->nsub;
if (subno < NPAREN)
- p->pbegin[subno] = HERE();
+ p->pbegin[subno] = HERE();
EMIT(OLPAREN, subno);
if (!SEE(')'))
p_ere(p, ')');
@@ -279,7 +279,7 @@ register struct parse *p;
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
- if(MUSTEAT(')', REG_EPAREN));
+ if(MUSTEAT(')', REG_EPAREN)) {}
break;
#ifndef POSIX_MISTAKE
case ')': /* happens only if no current unmatched ( */
@@ -322,12 +322,12 @@ register struct parse *p;
p_bracket(p);
break;
case '\\':
- if(REQUIRE(MORE(), REG_EESCAPE));
+ if(REQUIRE(MORE(), REG_EESCAPE)) {}
c = GETNEXT();
ordinary(p, c);
break;
case '{': /* okay as ordinary except if digit follows */
- if(REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT));
+ if(REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT)) {}
/* FALLTHROUGH */
default:
ordinary(p, c);
@@ -343,7 +343,7 @@ register struct parse *p;
return; /* no repetition, we're done */
NEXT();
- if(REQUIRE(!wascaret, REG_BADRPT));
+ if(REQUIRE(!wascaret, REG_BADRPT)) {}
switch (c) {
case '*': /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */
@@ -370,7 +370,7 @@ register struct parse *p;
if (EAT(',')) {
if (isdigit(PEEK())) {
count2 = p_count(p);
- if(REQUIRE(count <= count2, REG_BADBR));
+ if(REQUIRE(count <= count2, REG_BADBR)) {}
} else /* single number with comma */
count2 = RE_INFINITY;
} else /* just a single number */
@@ -379,7 +379,7 @@ register struct parse *p;
if (!EAT('}')) { /* error heuristics */
while (MORE() && PEEK() != '}')
NEXT();
- if(REQUIRE(MORE(), REG_EBRACE));
+ if(REQUIRE(MORE(), REG_EBRACE)) {}
SETERROR(REG_BADBR);
}
break;
@@ -402,7 +402,7 @@ static void
p_str(p)
register struct parse *p;
{
- if(REQUIRE(MORE(), REG_EMPTY));
+ if(REQUIRE(MORE(), REG_EMPTY)) {}
while (MORE())
ordinary(p, GETNEXT());
}
@@ -445,7 +445,7 @@ register int end2; /* second terminating character */
p->g->neol++;
}
- if(REQUIRE(HERE() != start, REG_EMPTY)); /* require nonempty */
+ if(REQUIRE(HERE() != start, REG_EMPTY)) {} /* require nonempty */
}
/*
@@ -470,7 +470,7 @@ int starordinary; /* is a leading * an ordinary character? */
assert(MORE()); /* caller should have ensured this */
c = GETNEXT();
if (c == '\\') {
- if(REQUIRE(MORE(), REG_EESCAPE));
+ if(REQUIRE(MORE(), REG_EESCAPE)) {}
c = BACKSL | (unsigned char)GETNEXT();
}
switch (c) {
@@ -500,7 +500,7 @@ int starordinary; /* is a leading * an ordinary character? */
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
- if(REQUIRE(EATTWO('\\', ')'), REG_EPAREN));
+ if(REQUIRE(EATTWO('\\', ')'), REG_EPAREN)) {}
break;
case BACKSL|')': /* should not get here -- must be user */
case BACKSL|'}':
@@ -530,7 +530,7 @@ int starordinary; /* is a leading * an ordinary character? */
p->g->backrefs = 1;
break;
case '*':
- if(REQUIRE(starordinary, REG_BADRPT));
+ if(REQUIRE(starordinary, REG_BADRPT)) {}
/* FALLTHROUGH */
default:
ordinary(p, c &~ BACKSL);
@@ -548,7 +548,7 @@ int starordinary; /* is a leading * an ordinary character? */
if (EAT(',')) {
if (MORE() && isdigit(PEEK())) {
count2 = p_count(p);
- if(REQUIRE(count <= count2, REG_BADBR));
+ if(REQUIRE(count <= count2, REG_BADBR)) {}
} else /* single number with comma */
count2 = RE_INFINITY;
} else /* just a single number */
@@ -557,7 +557,7 @@ int starordinary; /* is a leading * an ordinary character? */
if (!EATTWO('\\', '}')) { /* error heuristics */
while (MORE() && !SEETWO('\\', '}'))
NEXT();
- if(REQUIRE(MORE(), REG_EBRACE));
+ if(REQUIRE(MORE(), REG_EBRACE)) {}
SETERROR(REG_BADBR);
}
} else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
@@ -582,7 +582,7 @@ register struct parse *p;
ndigits++;
}
- if(REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR));
+ if(REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR)) {}
return(count);
}
@@ -622,7 +622,7 @@ register struct parse *p;
p_b_term(p, cs);
if (EAT('-'))
CHadd(cs, '-');
- if(MUSTEAT(']', REG_EBRACK));
+ if(MUSTEAT(']', REG_EBRACK)) {}
if (p->error != 0) /* don't mess things up further */
return;
@@ -693,21 +693,21 @@ register cset *cs;
switch (c) {
case ':': /* character class */
NEXT2();
- if(REQUIRE(MORE(), REG_EBRACK));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
c = PEEK();
- if(REQUIRE(c != '-' && c != ']', REG_ECTYPE));
+ if(REQUIRE(c != '-' && c != ']', REG_ECTYPE)) {}
p_b_cclass(p, cs);
- if(REQUIRE(MORE(), REG_EBRACK));
- if(REQUIRE(EATTWO(':', ']'), REG_ECTYPE));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
+ if(REQUIRE(EATTWO(':', ']'), REG_ECTYPE)) {}
break;
case '=': /* equivalence class */
NEXT2();
- if(REQUIRE(MORE(), REG_EBRACK));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
c = PEEK();
- if(REQUIRE(c != '-' && c != ']', REG_ECOLLATE));
+ if(REQUIRE(c != '-' && c != ']', REG_ECOLLATE)) {}
p_b_eclass(p, cs);
- if(REQUIRE(MORE(), REG_EBRACK));
- if(REQUIRE(EATTWO('=', ']'), REG_ECOLLATE));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
+ if(REQUIRE(EATTWO('=', ']'), REG_ECOLLATE)) {}
break;
default: /* symbol, ordinary character, or range */
/* xxx revision needed for multichar stuff */
@@ -722,7 +722,7 @@ register cset *cs;
} else
finish = start;
/* xxx what about signed chars here... */
- if(REQUIRE(start <= finish, REG_ERANGE));
+ if(REQUIRE(start <= finish, REG_ERANGE)) {}
for (i = start; i <= finish; i++)
CHadd(cs, i);
break;
@@ -756,10 +756,10 @@ register cset *cs;
return;
}
- u = cp->chars;
+ u = (char*) cp->chars;
while ((c = *u++) != '\0')
CHadd(cs, c);
- for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+ for (u = (char*) cp->multis; *u != '\0'; u += strlen(u) + 1)
MCadd(p, cs, u);
}
@@ -790,13 +790,13 @@ register struct parse *p;
{
register char value;
- if(REQUIRE(MORE(), REG_EBRACK));
+ if(REQUIRE(MORE(), REG_EBRACK)) {}
if (!EATTWO('[', '.'))
return(GETNEXT());
/* collating symbol */
value = p_b_coll_elem(p, '.');
- if(REQUIRE(EATTWO('.', ']'), REG_ECOLLATE));
+ if(REQUIRE(EATTWO('.', ']'), REG_ECOLLATE)) {}
return(value);
}
@@ -1189,6 +1189,7 @@ register char *cp;
cs->multis[cs->smultis - 1] = '\0';
}
+#ifdef NOT_USED
/*
- mcsub - subtract a collating element from a cset
== static void mcsub(register cset *cs, register char *cp);
@@ -1246,6 +1247,7 @@ register char *cp;
return(p);
return(NULL);
}
+#endif
/*
- mcinvert - invert the list of collating elements in a cset
@@ -1256,8 +1258,8 @@ register char *cp;
*/
static void
mcinvert(p, cs)
-register struct parse *p;
-register cset *cs;
+ register struct parse *p __attribute__((unused));
+ register cset *cs __attribute__((unused));
{
assert(cs->multis == NULL); /* xxx */
}
@@ -1271,8 +1273,8 @@ register cset *cs;
*/
static void
mccase(p, cs)
-register struct parse *p;
-register cset *cs;
+register struct parse *p __attribute__((unused));
+register cset *cs __attribute__((unused));
{
assert(cs->multis == NULL); /* xxx */
}
diff --git a/regex/regcomp.ih b/regex/regcomp.ih
index 0776e7185cd..4ae45bbf4a9 100644
--- a/regex/regcomp.ih
+++ b/regex/regcomp.ih
@@ -28,9 +28,11 @@ static int freezeset(register struct parse *p, register cset *cs);
static int firstch(register struct parse *p, register cset *cs);
static int nch(register struct parse *p, register cset *cs);
static void mcadd(register struct parse *p, register cset *cs, register char *cp);
+#ifdef NOT_USED
static void mcsub(register cset *cs, register char *cp);
static int mcin(register cset *cs, register char *cp);
static char *mcfind(register cset *cs, register char *cp);
+#endif
static void mcinvert(register struct parse *p, register cset *cs);
static void mccase(register struct parse *p, register cset *cs);
static int isinsets(register struct re_guts *g, int c);
diff --git a/regex/regerror.c b/regex/regerror.c
index 4a28f6e9d24..0a7b7c8da2c 100644
--- a/regex/regerror.c
+++ b/regex/regerror.c
@@ -28,8 +28,8 @@
*/
static struct rerr {
int code;
- char *name;
- char *explain;
+ const char *name;
+ const char *explain;
} rerrs[] = {
{REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"},
{REG_BADPAT, "REG_BADPAT", "invalid regular expression"},
@@ -83,7 +83,7 @@ size_t errbuf_size;
assert(strlen(convbuf) < sizeof(convbuf));
s = convbuf;
} else
- s = r->explain;
+ s = (char*) r->explain;
}
len = strlen(s) + 1;
@@ -113,7 +113,7 @@ char *localbuf;
if (strcmp(r->name, preg->re_endp) == 0)
break;
if (r->code == 0)
- return("0");
+ return((char*) "0");
sprintf(localbuf, "%d", r->code);
return(localbuf);
diff --git a/regex/reginit.c b/regex/reginit.c
index 06a48b16243..18647c386fc 100644
--- a/regex/reginit.c
+++ b/regex/reginit.c
@@ -63,7 +63,7 @@ void regex_end()
{
int i;
for (i=0; i < CCLASS_LAST ; i++)
- free(cclasses[i].chars);
+ free((char*) cclasses[i].chars);
regex_inited=0;
}
}
diff --git a/regex/split.c b/regex/split.c
index 188bdb775b9..bd2a53c01e3 100644
--- a/regex/split.c
+++ b/regex/split.c
@@ -27,7 +27,7 @@ char *sep; /* "" white, "c" single char, "ab" [ab]+ */
continue;
p--;
trimtrail = 1;
- sep = " \t"; /* note, code below knows this is 2 long */
+ sep = (char*) " \t"; /* note, code below knows this is 2 long */
sepc = ' ';
} else
trimtrail = 0;
diff --git a/sql-bench/test-connect.sh b/sql-bench/test-connect.sh
index 862161e3a03..2670c7fdf29 100644
--- a/sql-bench/test-connect.sh
+++ b/sql-bench/test-connect.sh
@@ -27,7 +27,7 @@
use DBI;
use Benchmark;
-$opt_loop_count=10000; # Change this to make test harder/easier
+$opt_loop_count=100000; # Change this to make test harder/easier
$str_length=65000; # This is the length of blob strings in PART:5
$max_test=20; # How many times to test if the server is busy
@@ -43,9 +43,10 @@ if ($opt_small_test)
}
$opt_loop_count=min(1000, $opt_loop_count) if ($opt_tcpip);
+$small_loop_count=$opt_loop_count/10; # For connect tests
print "Testing the speed of connecting to the server and sending of data\n";
-print "All tests are done $opt_loop_count times\n\n";
+print "Connect tests are done $opt_small_loop_count and other tests $opt_loop_count times\n\n";
################################# PART:1 ###################################
####
@@ -59,7 +60,7 @@ print "Testing connection/disconnect\n";
$loop_time=new Benchmark;
$errors=0;
-for ($i=0 ; $i < $opt_loop_count ; $i++)
+for ($i=0 ; $i < $small_loop_count ; $i++)
{
print "$i " if (($opt_debug));
for ($j=0; $j < $max_test ; $j++)
@@ -80,27 +81,27 @@ for ($i=0 ; $i < $opt_loop_count ; $i++)
}
$end_time=new Benchmark;
print "Warning: $errors connections didn't work without a time delay\n" if ($errors);
-print "Time to connect ($opt_loop_count): " .
+print "Time to connect ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
################################# PART:2 ###################################
#### Now we shall do first one connect, then simple select
#### (select 1..) and then close connection. This will be
-#### done $opt_loop_count times.
+#### done $small_loop_count times.
if ($limits->{'select_without_from'})
{
print "Test connect/simple select/disconnect\n";
$loop_time=new Benchmark;
- for ($i=0; $i<$opt_loop_count; $i++)
+ for ($i=0; $i < $small_loop_count; $i++)
{
$dbh = DBI->connect($server->{'data_source'}, $opt_user, $opt_password) || die $DBI::errstr;
- $sth = $dbh->do("select 1") or die $DBI::errstr;
+ $sth = $dbh->do("select $i") or die $DBI::errstr;
$dbh->disconnect;
}
$end_time=new Benchmark;
- print "Time for connect+select_simple ($opt_loop_count): " .
+ print "Time for connect+select_simple ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
}
@@ -116,16 +117,33 @@ if ($limits->{'select_without_from'})
{
print "Test simple select\n";
$loop_time=new Benchmark;
- for ($i=0 ; $i<$opt_loop_count ; $i++)
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
{
- $sth = $dbh->do("select 1") or die $DBI::errstr;
+ $sth = $dbh->do("select $i") or die $DBI::errstr;
}
$end_time=new Benchmark;
print "Time for select_simple ($opt_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
}
-################################# PART:4 ###################################
+###########################################################################
+#### The same as the previous test, but always execute the same select
+#### This is done to test the query cache for real simple selects.
+
+if ($limits->{'select_without_from'})
+{
+ print "Test simple select\n";
+ $loop_time=new Benchmark;
+ for ($i=0 ; $i < $opt_loop_count ; $i++)
+ {
+ $sth = $dbh->do("select 10000") or die $DBI::errstr;
+ }
+ $end_time=new Benchmark;
+ print "Time for select_simple_query_cache ($opt_loop_count): " .
+ timestr(timediff($end_time, $loop_time),"all") . "\n\n";
+}
+
+##########################################################################
#### First, we'll create a simple table 'bench1'
#### Then we shall do $opt_loop_count selects from this table.
#### Table will contain very simple data.
@@ -152,7 +170,7 @@ print "Testing connect/select 1 row from table/disconnect\n";
$loop_time=new Benchmark;
$errors=0;
-for ($i=0 ; $i<$opt_loop_count ; $i++)
+for ($i=0 ; $i < $small_loop_count ; $i++)
{
for ($j=0; $j < $max_test ; $j++)
{
@@ -161,14 +179,14 @@ for ($i=0 ; $i<$opt_loop_count ; $i++)
}
die $DBI::errstr if ($j == $max_test);
- $sth = $dbh->do("select * from bench1") #Select * from table with 1 record
+ $sth = $dbh->do("select a,i,s,$i from bench1") # Select * from table with 1 record
or die $DBI::errstr;
$dbh->disconnect;
}
$end_time=new Benchmark;
print "Warning: $errors connections didn't work without a time delay\n" if ($errors);
-print "Time to connect+select_1_row ($opt_loop_count): " .
+print "Time to connect+select_1_row ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
#
@@ -179,9 +197,9 @@ print "Testing select 1 row from table\n";
$dbh = $server->connect();
$loop_time=new Benchmark;
-for ($i=0 ; $i<$opt_loop_count ; $i++)
+for ($i=0 ; $i < $opt_loop_count ; $i++)
{
- $sth = $dbh->do("select * from bench1") # Select * from table with 1 record
+ $sth = $dbh->do("select a,i,s,$i from bench1") # Select * from table with 1 record
or die $DBI::errstr;
}
@@ -199,9 +217,9 @@ $sth = $dbh->do("insert into bench1 values(2,200,'BBB')")
$loop_time=new Benchmark;
-for ($i=0 ; $i<$opt_loop_count ; $i++)
+for ($i=0 ; $i < $opt_loop_count ; $i++)
{
- $sth = $dbh->do("select * from bench1") # Select * from table with 2 record
+ $sth = $dbh->do("select a,i,s,$i from bench1") # Select * from table with 2 record
or die $DBI::errstr;
}
@@ -214,9 +232,9 @@ if ($limits->{'functions'})
print "Test select with aritmetic (+)\n";
$loop_time=new Benchmark;
- for ($i=0; $i<$opt_loop_count; $i++)
+ for ($i=0; $i < $opt_loop_count; $i++)
{
- $sth = $dbh->do("select a+a+a+a+a+a+a+a+a+a from bench1") or die $DBI::errstr;
+ $sth = $dbh->do("select a+a+a+a+a+a+a+a+a+$i from bench1") or die $DBI::errstr;
}
$end_time=new Benchmark;
print "Time for select_column+column ($opt_loop_count): " .
@@ -254,9 +272,9 @@ if ($opt_fast && defined($server->{vacuum}))
$loop_time=new Benchmark;
-for ($i=0 ; $i < $opt_loop_count ; $i++)
+for ($i=0 ; $i < $small_loop_count ; $i++)
{
- $sth = $dbh->prepare("select * from bench1");
+ $sth = $dbh->prepare("select b,$i from bench1");
if (!$sth->execute || !(@row = $sth->fetchrow_array) ||
length($row[0]) != $str_length)
{
@@ -266,7 +284,7 @@ for ($i=0 ; $i < $opt_loop_count ; $i++)
}
$end_time=new Benchmark;
-print "Time to select_big_str ($opt_loop_count): " .
+print "Time to select_big_str ($small_loop_count): " .
timestr(timediff($end_time, $loop_time),"all") . "\n\n";
$sth = $dbh->do("drop table bench1" . $server->{'drop_attr'})
diff --git a/sql-bench/test-transactions.sh b/sql-bench/test-transactions.sh
index adb76e6f68d..b081b89fb69 100644
--- a/sql-bench/test-transactions.sh
+++ b/sql-bench/test-transactions.sh
@@ -23,7 +23,7 @@
use DBI;
use Benchmark;
-use warnings;
+#use warnings;
$opt_groups=27; # Characters are 'A' -> Z
@@ -34,7 +34,8 @@ chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
require "$pwd/bench-init.pl" || die "Can't read Configuration file: $!\n";
# Avoid warnings for variables in bench-init.pl
-our ($opt_small_test, $opt_small_tables, $opt_debug, $opt_force);
+# (Only works with perl 5.6)
+#our ($opt_small_test, $opt_small_tables, $opt_debug, $opt_force);
if ($opt_small_test || $opt_small_tables)
{
diff --git a/sql/convert.cc b/sql/convert.cc
index 3e0fbf18ace..2645690a71f 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -397,19 +397,19 @@ static unsigned char win1251ukr_koi8_ukr[256] = {
****************************************************************************/
-CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251);
+CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251, 1);
#ifdef DEFINE_ALL_CHARACTER_SETS
-CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250);
-CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam);
-CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac);
-CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce);
-CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2);
-CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga);
-CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8);
+CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250, 2);
+CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam, 3);
+CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac, 4);
+CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce, 5);
+CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2, 6);
+CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga, 7);
+CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8, 8);
CONVERT conv_win1251ukr_koi8_ukr("win1251ukr_koi8_ukr", win1251ukr_koi8_ukr,
- koi8_ukr_win1251ukr);
+ koi8_ukr_win1251ukr, 9);
CONVERT conv_koi8_ukr_win1251ukr("koi8_ukr_win1251ukr", koi8_ukr_win1251ukr,
- win1251ukr_koi8_ukr);
+ win1251ukr_koi8_ukr, 10);
#endif /* DEFINE_ALL_CHARACTER_SETS */
CONVERT *convert_tables[]= {
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index d82c202baa3..999d9fe33ef 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -38,10 +38,15 @@ const char **ha_myisammrg::bas_ext() const
int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
{
char name_buff[FN_REFLEN];
+ DBUG_PRINT("info", ("ha_myisammrg::open"));
if (!(file=myrg_open(fn_format(name_buff,name,"","",2 | 4), mode,
test_if_locked)))
+ {
+ DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno));
return (my_errno ? my_errno : -1);
-
+ }
+ DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc..."))
+ myrg_extrafunc(file, &query_cache_invalidate_by_MyISAM_filename);
if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index b97baa0703c..7d696162de0 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -74,4 +74,5 @@ class ha_myisammrg: public handler
enum thr_lock_type lock_type);
void update_create_info(HA_CREATE_INFO *create_info);
void append_create_info(String *packet);
+ MYRG_INFO *myrg_info() { return file; }
};
diff --git a/sql/handler.cc b/sql/handler.cc
index 9bf9b25f76f..d7c6f3fe93c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -258,6 +258,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
error=1;
}
trans->innodb_active_trans=0;
+ if (trans == &thd->transaction.all)
+ query_cache.invalidate(Query_cache_table::INNODB);
}
#endif
if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 55f8bb140a9..5809091275e 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -65,7 +65,9 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
- return new Item_int("CONNECTION_ID()",(longlong) current_thd->thread_id,10);
+ THD *thd=current_thd;
+ thd->safe_to_cache_query=0;
+ return new Item_int("CONNECTION_ID()",(longlong) thd->thread_id,10);
}
Item *create_func_conv(Item* a, Item *b, Item *c)
@@ -131,7 +133,9 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
- return new Item_int("FOUND_ROWS()",(longlong) current_thd->found_rows(),21);
+ THD *thd=current_thd;
+ thd->safe_to_cache_query=0;
+ return new Item_int("FOUND_ROWS()",(longlong) thd->found_rows(),21);
}
Item *create_func_from_days(Item* a)
@@ -141,6 +145,7 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
+ current_thd->safe_to_cache_query=0;
return new Item_func_get_lock(a, b);
}
@@ -279,6 +284,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
+ current_thd->safe_to_cache_query=0;
return new Item_func_release_lock(a);
}
@@ -379,10 +385,12 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
+ current_thd->safe_to_cache_query=0;
return new Item_load_file(a);
}
Item *create_wait_for_master_pos(Item* a, Item* b)
{
+ current_thd->safe_to_cache_query=0;
return new Item_master_pos_wait(a, b);
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index fe68d8f47c2..eeae891b793 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2170,7 +2170,7 @@ bool Item_func_match::eq(const Item *item) const
double Item_func_match::val()
{
- if (ft_handler==NULL)
+ if (ft_handler == NULL)
return -1.0;
if (join_key)
@@ -2184,10 +2184,10 @@ double Item_func_match::val()
if (key == NO_SUCH_KEY)
{
String *a=concat->val_str(&value);
- if (null_value=(a==0))
+ if ((null_value= (a==0)))
return 0;
return ft_handler->please->find_relevance(ft_handler,
- (byte *)a->ptr(), a->length());
+ (byte *)a->ptr(), a->length());
}
else
return ft_handler->please->find_relevance(ft_handler, record, 0);
diff --git a/sql/item_func.h b/sql/item_func.h
index 2bf272f24ed..23cdf7082cf 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -862,18 +862,18 @@ class Item_func_match :public Item_real_func
{
public:
List<Item> fields;
- Item *concat;
String value;
TABLE *table;
- uint key, mode;
- bool join_key;
Item_func_match *master;
FT_INFO * ft_handler;
+ Item *concat;
byte *record;
+ uint key, mode;
+ bool join_key;
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
- fields(a), table(0), join_key(0), master(0), ft_handler(0),
- key(0), concat(0) {}
+ fields(a), table(0), master(0), ft_handler(0),
+ concat(0), key(0), join_key(0) {}
~Item_func_match()
{
if (!master && ft_handler)
diff --git a/sql/lex.h b/sql/lex.h
index 37fe38b76a1..744898d6b9c 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -76,6 +76,7 @@ static SYMBOL symbols[] = {
{ "BOOLEAN", SYM(BOOLEAN_SYM),0,0},
{ "BOTH", SYM(BOTH),0,0},
{ "BY", SYM(BY),0,0},
+ { "CACHE", SYM(CACHE_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0},
{ "CHAR", SYM(CHAR_SYM),0,0},
@@ -114,6 +115,7 @@ static SYMBOL symbols[] = {
{ "DELAYED", SYM(DELAYED_SYM),0,0},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM),0,0},
{ "DELETE", SYM(DELETE_SYM),0,0},
+ { "DEMAND", SYM(DEMAND_SYM),0,0},
{ "DESC", SYM(DESC),0,0},
{ "DESCRIBE", SYM(DESCRIBE),0,0},
{ "DIRECTORY", SYM(DIRECTORY_SYM),0,0},
@@ -248,6 +250,7 @@ static SYMBOL symbols[] = {
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
+ { "OFF", SYM(OFF),0,0},
{ "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
@@ -268,6 +271,7 @@ static SYMBOL symbols[] = {
{ "PROCESS" , SYM(PROCESS),0,0},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM),0,0},
{ "PRIVILEGES", SYM(PRIVILEGES),0,0},
+ { "QUERY", SYM(QUERY_SYM),0,0},
{ "QUICK", SYM(QUICK),0,0},
{ "RAID0", SYM(RAID_0_SYM),0,0},
{ "READ", SYM(READ_SYM),0,0},
@@ -306,12 +310,15 @@ static SYMBOL symbols[] = {
{ "SQL_BIG_SELECTS", SYM(SQL_BIG_SELECTS),0,0},
{ "SQL_BIG_TABLES", SYM(SQL_BIG_TABLES),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
+ { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
{ "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
{ "SQL_LOG_BIN", SYM(SQL_LOG_BIN),0,0},
{ "SQL_LOG_OFF", SYM(SQL_LOG_OFF),0,0},
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
{ "SQL_LOW_PRIORITY_UPDATES", SYM(SQL_LOW_PRIORITY_UPDATES),0,0},
{ "SQL_MAX_JOIN_SIZE",SYM(SQL_MAX_JOIN_SIZE), 0, 0},
+ { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
+ { "SQL_QUERY_CACHE_TYPE",SYM(SQL_QUERY_CACHE_TYPE_SYM), 0, 0},
{ "SQL_QUOTE_SHOW_CREATE",SYM(SQL_QUOTE_SHOW_CREATE), 0, 0},
{ "SQL_SAFE_UPDATES", SYM(SQL_SAFE_UPDATES),0,0},
{ "SQL_SELECT_LIMIT", SYM(SQL_SELECT_LIMIT),0,0},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index e0e85145c52..5830c946372 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -179,6 +179,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define SELECT_NO_UNLOCK (QUERY_NO_GOOD_INDEX_USED*2)
#define TMP_TABLE_ALL_COLUMNS (SELECT_NO_UNLOCK*2)
+#define OPTION_TO_QUERY_CACHE (TMP_TABLE_ALL_COLUMNS*2)
+
#define MODE_REAL_AS_FLOAT 1
#define MODE_PIPES_AS_CONCAT 2
@@ -248,7 +250,7 @@ inline THD *_current_thd(void)
#include "item.h"
#include "sql_class.h"
#include "opt_range.h"
-
+#include "sql_cache.h"
int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -539,6 +541,7 @@ extern ulong select_full_range_join_count,select_full_join_count,
slave_open_temp_tables;
extern uint test_flags,select_errors,ha_open_options;
extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
+extern ulong query_cache_startup_type;
extern time_t start_time;
extern const char *command_name[];
extern I_List<THD> threads;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c4af3366806..1cb06c8a461 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -270,6 +270,7 @@ ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
open_files_limit=0, max_binlog_size, record_rnd_cache_size;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
+ulong query_cache_size=0, query_cache_limit=0, query_cache_startup_type=1;
volatile ulong cached_thread_count=0;
// replication parameters, if master_host is not NULL, we are a slave
@@ -359,6 +360,8 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_binlog_update, LOCK_slave, LOCK_server_id,
LOCK_user_conn, LOCK_slave_list;
+Query_cache query_cache;
+
pthread_cond_t COND_refresh,COND_thread_count,COND_binlog_update,
COND_slave_stopped, COND_slave_start;
pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
@@ -732,7 +735,7 @@ void clean_up(bool print_message)
return; /* purecov: inspected */
acl_free(1);
grant_free();
- sql_cache_free();
+ query_cache.resize(0);
table_cache_free();
hostname_cache_free();
item_user_lock_free();
@@ -1810,7 +1813,8 @@ int main(int argc, char **argv)
server_init();
table_cache_init();
hostname_cache_init();
- sql_cache_init();
+ query_cache.result_size_limit(query_cache_limit);
+ query_cache.resize(query_cache_size);
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
@@ -2953,6 +2957,12 @@ CHANGEABLE_VAR changeable_vars[] = {
0, 0, 65535, 0, 1},
{ "query_buffer_size", (long*) &query_buff_size,
0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
+ { "query_cache_limit", (long*) &query_cache_limit,
+ 1024*1024L, 0, ULONG_MAX, 0, 1},
+ { "query_cache_size", (long*) &query_cache_size,
+ 0, 0, ULONG_MAX, 0, 1},
+ { "query_cache_startup_type",(long*) &query_cache_startup_type,
+ 1, 0, 2, 0, 1},
{ "record_buffer", (long*) &my_default_record_cache_size,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
{ "record_rnd_buffer", (long*) &record_rnd_cache_size,
@@ -3007,7 +3017,7 @@ struct show_var_st init_vars[]= {
{"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG},
{"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG},
{"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG},
- {"ft_boolean_syntax", ft_boolean_syntax, SHOW_CHAR},
+ {"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR},
{"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE},
{"have_innodb", (char*) &have_innodb, SHOW_HAVE},
{"have_isam", (char*) &have_isam, SHOW_HAVE},
@@ -3081,6 +3091,9 @@ struct show_var_st init_vars[]= {
{"record_rnd_buffer", (char*) &record_rnd_cache_size, SHOW_LONG},
{"rpl_recovery_rank", (char*) &rpl_recovery_rank, SHOW_LONG},
{"query_buffer_size", (char*) &query_buff_size, SHOW_LONG},
+ {"query_cache_limit", (char*) &query_cache_limit, SHOW_LONG},
+ {"query_cache_size", (char*) &query_cache_size, SHOW_LONG},
+ {"query_cache_startup_type",(char*) &query_cache_startup_type, SHOW_LONG},
{"safe_show_database", (char*) &opt_safe_show_db, SHOW_BOOL},
{"server_id", (char*) &server_id, SHOW_LONG},
{"slave_net_timeout", (char*) &slave_net_timeout, SHOW_LONG},
@@ -3144,8 +3157,13 @@ struct show_var_st status_vars[]= {
{"Open_streams", (char*) &my_stream_opened, SHOW_INT_CONST},
{"Opened_tables", (char*) &opened_tables, SHOW_LONG},
{"Questions", (char*) 0, SHOW_QUESTION},
- {"Rpl_status", (char*) 0,
- SHOW_RPL_STATUS},
+ {"Qcache_queries", (char*) &query_cache.queries_in_cache,
+ SHOW_LONG},
+ {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG},
+ {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
+ {"Qcache_refused", (char*) &query_cache.refused, SHOW_LONG},
+ {"Qcache_free_memory", (char*) &query_cache.free_memory,SHOW_LONG},
+ {"Rpl_status", (char*) 0, SHOW_RPL_STATUS},
{"Select_full_join", (char*) &select_full_join_count, SHOW_LONG},
{"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG},
{"Select_range", (char*) &select_range_count, SHOW_LONG},
@@ -3160,29 +3178,29 @@ struct show_var_st status_vars[]= {
{"Sort_rows", (char*) &filesort_rows, SHOW_LONG},
{"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG},
#ifdef HAVE_OPENSSL
- {"ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
- {"ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
- {"ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD},
- {"ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
- {"ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
- {"ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS},
- {"ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS},
- {"ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES},
- {"ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS},
- {"ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER},
- {"ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT},
- {"ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL},
- {"ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
- {"ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
- {"ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED},
- {"ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE},
- {"ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH},
- {"ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE},
- {"ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH},
- {"ssl_version", (char*) 0, SHOW_SSL_GET_VERSION},
- {"ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER},
- {"ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST},
- {"ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT},
+ {"ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
+ {"ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
+ {"ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD},
+ {"ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
+ {"ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
+ {"ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS},
+ {"ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS},
+ {"ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES},
+ {"ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS},
+ {"ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER},
+ {"ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT},
+ {"ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL},
+ {"ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
+ {"ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
+ {"ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED},
+ {"ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE},
+ {"ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH},
+ {"ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE},
+ {"ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH},
+ {"ssl_version", (char*) 0, SHOW_SSL_GET_VERSION},
+ {"ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER},
+ {"ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST},
+ {"ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT},
#endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 5e002a0f63e..ac622bca254 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -94,6 +94,7 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a
#ifdef MYSQL_SERVER
extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+extern void query_cache_insert(NET *net, const char *packet, ulong length);
#else
#undef statistic_add
#define statistic_add(A,B,C)
@@ -125,6 +126,7 @@ int my_net_init(NET *net, Vio* vio)
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
+ net->query_cache_query=0;
if (vio != 0) /* If real connection */
{
@@ -341,6 +343,10 @@ net_real_write(NET *net,const char *packet,ulong len)
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
+#ifdef MYSQL_SERVER
+ query_cache_insert(net, packet, len);
+#endif
+
if (net->error == 2)
DBUG_RETURN(-1); /* socket can't be used */
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 09d436c0c9c..38db67ba38f 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -18,81 +18,2503 @@
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
+#include "sql_acl.h"
+#include "ha_myisammrg.h"
+#ifndef MASTER
+#include "../srclib/myisammrg/myrg_def.h"
+#else
+#include "../myisammrg/myrg_def.h"
+#endif
+
+#ifdef EXTRA_DEBUG
+#define MUTEX_LOCK(M) { DBUG_PRINT("info", ("mutex lock 0x%lx", (ulong)(M))); \
+ pthread_mutex_lock(M);}
+#define SEM_LOCK(M) { int val = 0; sem_getvalue (M, &val); \
+ DBUG_PRINT("info", ("sem lock 0x%lx (%d)", (ulong)(M), val)); \
+ sem_wait(M); DBUG_PRINT("info", ("sem lock ok")); }
+#define MUTEX_UNLOCK(M) {DBUG_PRINT("info", ("mutex unlock 0x%lx",\
+ (ulong)(M))); pthread_mutex_unlock(M);}
+#define SEM_UNLOCK(M) {DBUG_PRINT("info", ("sem unlock 0x%lx", (ulong)(M))); \
+ sem_post(M); DBUG_PRINT("info", ("sem unlock ok")); }
+#define STRUCT_LOCK(M) {DBUG_PRINT("info", ("%d struct lock...",__LINE__)); \
+ pthread_mutex_lock(M);DBUG_PRINT("info", ("struct lock OK"));}
+#define STRUCT_UNLOCK(M) { \
+ DBUG_PRINT("info", ("%d struct unlock...",__LINE__)); \
+ pthread_mutex_unlock(M);DBUG_PRINT("info", ("struct unlock OK"));}
+#define BLOCK_LOCK_WR(B) {DBUG_PRINT("info", ("%d LOCK_WR 0x%lx",\
+ __LINE__,(ulong)(B))); \
+ B->query()->lock_writing();}
+#define BLOCK_LOCK_RD(B) {DBUG_PRINT("info", ("%d LOCK_RD 0x%lx",\
+ __LINE__,(ulong)(B))); \
+ B->query()->lock_reading();}
+#define BLOCK_UNLOCK_WR(B) { \
+ DBUG_PRINT("info", ("%d UNLOCK_WR 0x%lx",\
+ __LINE__,(ulong)(B)));B->query()->unlock_writing();}
+#define BLOCK_UNLOCK_RD(B) { \
+ DBUG_PRINT("info", ("%d UNLOCK_RD 0x%lx",\
+ __LINE__,(ulong)(B)));B->query()->unlock_reading();}
+#define DUMP(C) {C->bins_dump();C->cache_dump();\
+ C->queries_dump();C->tables_dump();}
+#else
+#define MUTEX_LOCK(M) pthread_mutex_lock(M)
+#define SEM_LOCK(M) sem_wait(M)
+#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
+#define SEM_UNLOCK(M) sem_post(M)
+#define STRUCT_LOCK(M) pthread_mutex_lock(M)
+#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
+#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
+#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
+#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
+#define BLOCK_UNLOCK_RD(B) B->query()->unlock_reading()
+#define DUMP(C)
+#endif
+
+/*****************************************************************************
+ * Query_cache_block_table method(s)
+ *****************************************************************************/
+
+inline Query_cache_block * Query_cache_block_table::block()
+{
+ return (Query_cache_block *)( ((byte*)this) -
+ ALIGN_SIZE(sizeof(Query_cache_block_table))*n -
+ ALIGN_SIZE(sizeof(Query_cache_block)));
+};
+
+/*****************************************************************************
+ * Query_cache_block method(s)
+ *****************************************************************************/
+
+void Query_cache_block::init(ulong block_length)
+{
+ DBUG_ENTER("Query_cache_block::init");
+ DBUG_PRINT("info", ("init block 0x%lx", (ulong) this));
+ length = block_length;
+ used = 0;
+ type = Query_cache_block::FREE;
+ n_tables = 0;
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache_block::destroy()
+{
+ DBUG_ENTER("Query_cache_block::destroy");
+ DBUG_PRINT("info", ("destroy block 0x%lx, type %d",
+ (ulong)this, type));
+ type = INCOMPLETE;
+ DBUG_VOID_RETURN;
+}
+
+inline uint Query_cache_block::headers_len()
+{
+ return (ALIGN_SIZE(sizeof(Query_cache_block_table))*n_tables +
+ ALIGN_SIZE(sizeof(Query_cache_block)));
+}
+
+inline gptr Query_cache_block::data(void)
+{
+ return (gptr)( ((byte*)this) + headers_len() );
+}
+
+inline Query_cache_query * Query_cache_block::query()
+{
+#ifndef DBUG_OFF
+ if (type != QUERY)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_query *) data();
+}
+
+inline Query_cache_table * Query_cache_block::table()
+{
+#ifndef DBUG_OFF
+ if (type != TABLE)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_table *) data();
+}
+
+inline Query_cache_result * Query_cache_block::result()
+{
+#ifndef DBUG_OFF
+ if (type != RESULT && type != RES_CONT && type != RES_BEG &&
+ type != RES_INCOMPLETE)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_result *) data();
+}
+
+inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
+{
+ return ((Query_cache_block_table *)
+ (((byte*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
+ n*ALIGN_SIZE(sizeof(Query_cache_block_table))));
+}
+
+
+/*****************************************************************************
+ * Query_cache_table method(s)
+ *****************************************************************************/
+
+byte * Query_cache_table::cache_key(const byte *record, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ Query_cache_block* table_block = (Query_cache_block*) record;
+ *length = (table_block->used - table_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+ return (((byte *) table_block->data()) +
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+}
+
+void Query_cache_table::free_cache(void *entry)
+{
+ //NOP
+}
+
+/*****************************************************************************
+ * Query_cache_query methods
+ *****************************************************************************/
+
+void Query_cache_query::init_n_lock()
+{
+ DBUG_ENTER("Query_cache_query::init_n_lock");
+ res=0; wri = 0; len = 0;
+ sem_init(&lock, 0, 1);
+ pthread_mutex_init(&clients_guard,MY_MUTEX_INIT_FAST);
+ clients = 0;
+ lock_writing();
+ DBUG_PRINT("info", ("inited & locked query for block 0x%lx",
+ ((byte*) this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache_query::unlock_n_destroy()
+{
+ DBUG_ENTER("Query_cache_query::unlock_n_destroy");
+ this->unlock_writing();
+ DBUG_PRINT("info", ("destroyed & unlocked query for block 0x%lx",
+ ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ sem_destroy(&lock);
+ pthread_mutex_destroy(&clients_guard);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Following methods work for block rwad/write locking only in this
+ particular case and in interaction with structure_guard_mutex.
+
+ Lock for write prevents any other locking.
+ Lock for read prevents only locking for write.
+*/
+
+void Query_cache_query::lock_writing()
+{
+ SEM_LOCK(&lock);
+}
+
+
+/*
+ Needed for finding queries, that we may delete from cache.
+ We don't want wait while block become unlocked, in addition
+ block locking mean that query now used and we not need to
+ remove it
+*/
+
+my_bool Query_cache_query::try_lock_writing()
+{
+ DBUG_ENTER("Query_cache_block::try_lock_writing");
+ if (sem_trywait(&lock)!=0 || clients != 0)
+ {
+ DBUG_PRINT("info", ("can't lock mutex"));
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("info", ("mutex 'lock' 0x%lx locked", (ulong) &lock));
+ DBUG_RETURN(1);
+}
+
+
+void Query_cache_query::lock_reading()
+{
+ MUTEX_LOCK(&clients_guard);
+ clients++;
+ if (clients == 1) SEM_LOCK(&lock);
+ MUTEX_UNLOCK(&clients_guard);
+}
+
+
+void Query_cache_query::unlock_writing()
+{
+ SEM_UNLOCK(&lock);
+}
+
+
+void Query_cache_query::unlock_reading()
+{
+ MUTEX_LOCK(&clients_guard);
+ clients--;
+ if (clients == 0) SEM_UNLOCK(&lock);
+ MUTEX_UNLOCK(&clients_guard);
+
+}
+
+
+byte * Query_cache_query::cache_key( const byte *record, uint *length,
+ my_bool not_used)
+{
+ Query_cache_block * query_block = (Query_cache_block *) record;
+ *length = (query_block->used - query_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+ return (((byte *)query_block->data()) +
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+}
+
+
+void Query_cache_query::free_cache(void *entry)
+{
+ //NOP
+}
+
+/*****************************************************************************
+ * Query cache store functions
+ *****************************************************************************/
+
+void query_cache_insert(NET *net, const char *packet, ulong length)
+{
+ DBUG_ENTER("query_cache_insert");
+
+#ifndef DBUG_OFF
+ // Debugging method wreck may cause this
+ if (query_cache.query_cache_size == 0)
+ DBUG_VOID_RETURN;
+#endif
+
+ // Quick check on unlocked structure
+ if (net->query_cache_query != 0)
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ if (net->query_cache_query != 0)
+ {
+ Query_cache_block * query_block = (Query_cache_block*)
+ net->query_cache_query;
+ DUMP((&query_cache));
+ BLOCK_LOCK_WR(query_block);
+ DBUG_PRINT("info", ("insert packet %lu bytes long",length));
+ Query_cache_query * header = query_block->query();
+
+ Query_cache_block * result = header->result();
+ /*
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex); will be done by
+ query_cache.append_result_data if success (if no success we need
+ query_cache.structure_guard_mutex locked to free query)
+ */
+ if (!query_cache.append_result_data( result, length, (gptr) packet,
+ query_block, result))
+ {
+ DBUG_PRINT("warning", ("Can't append data"));
+ header->result(result);
+ DBUG_PRINT("info", ("free query 0x%lx", (ulong)query_block));
+ query_cache.free_query(query_block);
+ // append_result_data no success => we need unlock
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+ header->result(result);
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void query_cache_abort(NET *net)
+{
+ DBUG_ENTER("query_cache_abort");
+
+#ifndef DBUG_OFF
+ // debuging method wreck may cause this
+ if (query_cache.query_cache_size == 0)
+ DBUG_VOID_RETURN;
+#endif
+
+ // quick check on unlocked structure
+ if (net->query_cache_query != 0)
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ DUMP((&query_cache));
+ Query_cache_block * query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block)
+ {
+ BLOCK_LOCK_WR(query_block);
+ query_cache.free_query(query_block);
+ net->query_cache_query=0;
+ }
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void query_cache_end_of_result(NET * net)
+{
+ DBUG_ENTER("query_cache_end_of_result");
+
+#ifndef DBUG_OFF
+ // debuging method wreck may couse this
+ if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN;
+#endif
+
+ //quick check on unlocked structure
+ if (net->query_cache_query != 0)
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ if (net->query_cache_query != 0)
+ {
+ Query_cache_block * query_block = (Query_cache_block*)
+ net->query_cache_query;
+ DUMP((&query_cache));
+ BLOCK_LOCK_WR(query_block);
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
+ Query_cache_query * header = query_block->query();
+#ifndef DBUG_OFF
+ if (header->result() != 0)
+ {
+#endif
+ header->found_rows(current_thd->limit_found_rows);
+ header->result()->type = Query_cache_block::RESULT;
+#ifndef DBUG_OFF
+ }
+ else
+ {
+ DBUG_PRINT("error", ("end of data whith no result. query '%s'",
+ header->query()));
+ query_cache.wreck(__LINE__, "");
+ DBUG_VOID_RETURN;
+ }
+#endif
+ net->query_cache_query=0;
+ header->writer(0);
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ {
+ //cache was flushed or resized and query was deleted => do nothing
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ }
+ net->query_cache_query=0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void query_cache_invalidate_by_MyISAM_filename(char * filename)
+{
+ query_cache.invalidate_by_MyISAM_filename(filename);
+}
+
+/*****************************************************************************
+ * Query_cache methods
+ *****************************************************************************/
+
+/*****************************************************************************
+ * interface methods
+ *****************************************************************************/
+
+Query_cache::Query_cache(
+ ulong query_cache_limit,
+ ulong min_allocation_unit,
+ ulong min_result_data_size,
+ uint def_query_hash_size ,
+ uint def_table_hash_size):
+
+ query_cache_size(0),
+ query_cache_limit(query_cache_limit),
+ min_allocation_unit(min_allocation_unit),
+ min_result_data_size(min_result_data_size),
+ def_query_hash_size(def_query_hash_size),
+ def_table_hash_size(def_table_hash_size),
+ queries_in_cache(0), hits(0), inserts(0), refused(0),
+ initialized(0)
+{
+ if (min_allocation_unit < ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_block_table)) +
+ ALIGN_SIZE(sizeof(Query_cache_query)) + 3)
+ {
+ min_allocation_unit=ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_block_table)) +
+ ALIGN_SIZE(sizeof(Query_cache_query)) + 3;
+ }
+ this->min_allocation_unit = min_allocation_unit;
+ if (min_result_data_size < min_allocation_unit)
+ this->min_result_data_size = min_allocation_unit;
+}
+
+ulong Query_cache::resize(ulong query_cache_size)
+{
+ /*
+ TODO: when will be realized pack() optimize case when
+ query_cache_size < this->query_cache_size
+ */
+ /*
+ TODO: try to copy old cache in new mamory
+ */
+ DBUG_ENTER("Query_cache::resize");
+ DBUG_PRINT("info", ("from %lu to %lu",this->query_cache_size,\
+ query_cache_size));
+ free_cache(0);
+ this->query_cache_size=query_cache_size;
+ DBUG_RETURN(init_cache());
+}
+
+void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
+{
+ /*
+ TODO may be better convert keywords to upper case when query
+ stored/compared
+ */
+ DBUG_ENTER("Query_cache::store_query");
+ if (query_cache_size == 0)
+ DBUG_VOID_RETURN;
+
+ LEX * lex = &thd->lex;
+ NET * net = &thd->net;
+
+ TABLE_COUNTER_TYPE tables = 0;
+
+ if ((tables = is_cachable(thd, thd->query_length,
+ thd->query, lex, tables_used))){
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size == 0)
+ DBUG_VOID_RETURN;
-#define SQL_CACHE_LENGTH 30 // 300 crashes apple gcc.
+ DUMP(this);
-HASH sql_cache;
-static LEX lex_array_static[SQL_CACHE_LENGTH];
-LEX * lex_array = lex_array_static;
-int last_lex_array_item = SQL_CACHE_LENGTH - 1;
+ /*
+ prepare flags:
+ most significant bit - CLIENT_LONG_FLAG,
+ other - charset number (0 no charset convertion)
+ */
+ byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ if (thd->convert_set != 0)
+ {
+ flags |= (byte) thd->convert_set->number();
+#ifndef DBUG_OFF
+ if ( (thd->convert_set->number() & QUERY_CACHE_CHARSET_CONVERT_MASK) !=
+ thd->convert_set->number())
+ {
+ wreck(__LINE__,
+ "charset number bigger than QUERY_CACHE_CHARSET_CONVERT_MASK");
+ }
+#endif
+ }
+
+ /* check: Is it another thread who process same query? */
+ thd->query[thd->query_length] = (char)flags;
+ Query_cache_block *competitor = (Query_cache_block *)
+ hash_search(&queries, thd->query, thd->query_length+1);
+ thd->query[thd->query_length] = '\0';
+ DBUG_PRINT("info", ("competitor 0x%lx, flags %x", (ulong)competitor,
+ flags));
+
+ if (competitor == 0)
+ {
+ thd->query[thd->query_length] = (char)flags;
+ Query_cache_block * query_block =
+ write_block_data(thd->query_length+1,
+ (gptr) thd->query,
+ ALIGN_SIZE(sizeof(Query_cache_query)),
+ Query_cache_block::QUERY, tables, 1);
+ thd->query[thd->query_length] = '\0';
+ if (query_block != 0)
+ {
+ DBUG_PRINT("info", ("query block 0x%lx allocated, %lu",
+ (ulong)query_block, query_block->used));
+
+ Query_cache_query * header = query_block->query();
+ header->init_n_lock();
+ if (hash_insert(&queries, (byte*)query_block))
+ {
+ refused++;
+ DBUG_PRINT("info", ("insertion in query hash"));
+ header->unlock_n_destroy();
+ free_memory_block(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+ if (!register_all_tables(query_block, tables_used, tables))
+ {
+ refused++;
+ DBUG_PRINT("warning", ("tables list incliding filed"));
+ hash_delete(&queries, (char *) query_block);
+ header->unlock_n_destroy();
+ free_memory_block(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+ double_linked_list_simple_include(query_block, queries_blocks);
+ inserts++;
+ queries_in_cache++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ net->query_cache_query = (gptr) query_block;
+ header->writer(net);
+ // init_n_lock make query block locked
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ {
+ refused++;
+ // We have not enough memory to store query => do nothing
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_PRINT("warning", ("Can't allocate query"));
+ }
+ }
+ else
+ {
+ refused++;
+ // Another thread already procass same query => do nothing
+ DBUG_PRINT("info", ("Another thread process same query"));
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ }
+ else
+ refused++;
+ DBUG_VOID_RETURN;
+}
-/* Function to return a text string from a LEX struct */
-static byte *cache_key(const byte *record, uint *length, my_bool not_used)
+my_bool Query_cache::send_result_to_client(
+ THD *thd, char *sql, uint query_length)
{
-#ifdef QQ
- LEX *lex=(LEX*) record;
- *length = lex->sql_query_length;
- // *length = strlen(lex->ptr);
- return (byte*) lex->sql_query_text;
- // return (byte*) lex->ptr;
+
+ DBUG_ENTER("Query_cache::send_result_to_client");
+
+ if (query_cache_size == 0 ||
+ /*
+ it is not possible to check has_transactions() function of handler
+ because tables not opened yet
+ */
+ (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) ||
+ thd->query_cache_type == 0)
+
+ {
+ DBUG_PRINT("info", ("query cache disabled on not in autocommit mode"));
+ DBUG_RETURN(1);
+ }
+
+ char *begin = sql;
+ while(*begin == ' ' || *begin == '\t') begin++;
+ if ( toupper(begin[0])!='S' ||
+ toupper(begin[1])!='E' ||
+ toupper(begin[2])!='L')
+ {
+ DBUG_PRINT("info", ("Not look like SELECT"));
+ DBUG_RETURN(1);
+ }
+ if (thd->temporary_tables != 0 || !thd->safe_to_cache_query )
+ {
+ DBUG_PRINT("info", ("SELECT is non-cachable"));
+ DBUG_RETURN(1);
+ }
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size == 0)
+ {
+ DBUG_PRINT("info", ("query cache disabled on not in autocommit mode"));
+ DBUG_RETURN(1);
+ }
+ DBUG_PRINT("info", (" sql %u '%s'", query_length, sql));
+ Query_cache_block *query_block = 0;
+
+ /*
+ prepare flags:
+ most significant bit - CLIENT_LONG_FLAG,
+ other - charset number (0 no charset convertion)
+ */
+ byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ if (thd->convert_set != 0)
+ {
+ flags |= (byte) thd->convert_set->number();
+#ifndef DBUG_OFF
+ if ( (thd->convert_set->number() & QUERY_CACHE_CHARSET_CONVERT_MASK) !=
+ thd->convert_set->number())
+ {
+ wreck(__LINE__,
+ "charset number bigger than QUERY_CACHE_CHARSET_CONVERT_MASK");
+ }
#endif
- return 0;
+ }
+
+ sql[query_length] = (char) flags;
+ query_block = (Query_cache_block *)
+ hash_search(&queries, sql, query_length+1);
+ sql[query_length] = '\0';
+
+ /*quick abort on unlocked data*/
+ if (query_block == 0 ||
+ query_block->query()->result() == 0 ||
+ query_block->query()->result()->type != Query_cache_block::RESULT)
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_PRINT("info", ("No query in query hash or no results"));
+ DBUG_RETURN(1);
+ }
+ DBUG_PRINT("info", ("Query in query hash 0x%lx", (ulong)query_block));
+
+ /* now lock and test that nothing changed while blocks was unlocked */
+ BLOCK_LOCK_RD(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ Query_cache_query * query = query_block->query();
+ Query_cache_block * first_result_block = query->result();
+ Query_cache_block * result_block = first_result_block;
+ if (result_block == 0 ||
+ result_block->type != Query_cache_block::RESULT)
+ {
+ DBUG_PRINT("info", ("query found, but no data or data incomplete"));
+ DBUG_RETURN(1); //no data in query
+ }
+ DBUG_PRINT("info", ("Query have result 0x%lx", (ulong)query));
+
+ //check access;
+ TABLE_COUNTER_TYPE t = 0;
+ for(; t < query_block->n_tables; t++)
+ {
+ TABLE_LIST table_list;
+ table_list.next = 0;
+ table_list.use_index = table_list.ignore_index = 0;
+ table_list.table = 0;
+ table_list.grant.grant_table = 0;
+ table_list.grant.version = table_list.grant.privilege =
+ table_list.grant.want_privilege = 0;
+ table_list.outer_join = 0;
+ table_list.straight = 0;
+ table_list.updating = 0;
+ table_list.shared = 0;
+
+ Query_cache_table * table = query_block->table(t)->parent;
+ table_list.db = table->db();
+ table_list.name = table_list.real_name = table->table();
+ if (check_table_access(thd,SELECT_ACL,&table_list))
+ {
+ DBUG_PRINT("info",
+ ("probably no SELECT access to %s.%s =>\
+ return to normal processing",
+ table_list.db, table_list.name));
+ DBUG_RETURN(1); //no access
+ }
+ }
+
+ move_to_query_list_end(query_block);
+
+ hits++;
+ do
+ {
+ DBUG_PRINT("info", ("Results (len %lu, used %lu, headers %lu)",
+ result_block->length, result_block->used,
+ result_block->headers_len()+
+ ALIGN_SIZE(sizeof(Query_cache_result))));
+
+ Query_cache_result * result = result_block->result();
+ net_real_write(&thd->net, result->data(),
+ result_block->used -
+ result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ result_block = result_block->next;
+ } while (result_block != first_result_block);
+
+ thd->limit_found_rows = query->found_rows();
+
+ BLOCK_UNLOCK_RD(query_block);
+
+ DBUG_RETURN(0);
+}
+
+void Query_cache::invalidate(TABLE_LIST *tables_used)
+{
+ DBUG_ENTER("Query_cache::invalidate (table list)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ for ( ; tables_used; tables_used=tables_used->next)
+ invalidate_table(tables_used);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
}
-/* At the moment we do not really want to do anything upon delete */
-static void free_cache_entry(void *entry)
+void Query_cache::invalidate(TABLE *table)
{
+ DBUG_ENTER("Query_cache::invalidate (table)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ invalidate_table(table);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
}
-/* Initialization of the SQL cache hash -- should be called during
- the bootstrap stage */
-bool sql_cache_init(void)
+void Query_cache::invalidate(Query_cache_table::query_cache_table_type type)
{
- if (query_buff_size)
+ DBUG_ENTER("Query_cache::invalidate (type)");
+ if (query_cache_size > 0)
{
- VOID(hash_init(&sql_cache, 4096, 0, 0,
- cache_key,
- (void (*)(void*)) free_cache_entry,
- 0));
+ STRUCT_LOCK(&structure_guard_mutex);
+ DUMP(this);
+ if (query_cache_size > 0 && tables_blocks[type] != 0)
+ {
+ Query_cache_block *table_block = tables_blocks[type];
+ do
+ {
+ /*
+ store next block address defore deletetion of current block
+ */
+ Query_cache_block *next = table_block->next;
+
+ invalidate_table(table_block);
+
+ if (next == table_block)
+ break;
+
+ table_block = next;
+ } while (table_block != tables_blocks[type]);
+
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
}
- return 0;
+ DBUG_VOID_RETURN;
}
-/* Clearing the SQL cache hash -- during shutdown */
-void sql_cache_free(void)
+void Query_cache::invalidate(char *db)
+{
+ DBUG_ENTER("Query_cache::invalidate (db)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ int i = 0;
+ for(; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ if (tables_blocks[i] != 0) //cache not empty
+ {
+ Query_cache_block *table_block = tables_blocks[i];
+ do
+ {
+ /*
+ store next block address defore deletetion of current block
+ */
+ Query_cache_block *next = table_block->next;
+
+ invalidate_table_in_db(table_block, db);
+
+ if (table_block == next)
+ break;
+
+ table_block = next;
+ } while (table_block != tables_blocks[i]);
+ }
+ }
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::invalidate_by_MyISAM_filename(char * filename)
+{
+ DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length =
+ Query_cache::filename_2_table_key(key, filename);
+
+ Query_cache_block *table_block;
+ if ((table_block = (Query_cache_block*)
+ hash_search(&tables, key, key_length)))
+ invalidate_table(table_block);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+void Query_cache::flush()
{
- hash_free(&sql_cache);
+ DBUG_ENTER("Query_cache::flush");
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ STRUCT_LOCK(&structure_guard_mutex);
+ flush_cache();
+ DUMP(this);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
}
-/* Finds whether the SQL command is already in the cache, at any case
- establishes correct LEX structure in the THD (either from
- cache or a new one) */
+void Query_cache::pack(ulong join_limit, uint iteration_limit)
+{
+ DBUG_ENTER("Query_cache::pack");
+ uint i = 0;
+ do
+ {
+ pack_cache();
+ } while ((++i < iteration_limit) && join_results(join_limit));
+ DBUG_VOID_RETURN;
+}
-int sql_cache_hit(THD *thd, char *sql, uint length)
+void Query_cache::destroy()
{
-#ifdef QQ
- LEX *ptr;
- ptr = (LEX *)hash_search(&sql_cache, sql, length);
- if (ptr) {
- fprintf(stderr, "Query `%s' -- hit in the cache (%p)\n", ptr->sql_query_text, ptr);
- thd->lex_ptr = ptr;
- ptr->thd = thd;
- } else {
- thd->lex_ptr = ptr = lex_array + last_lex_array_item--;
+ DBUG_ENTER("Query_cache::destroy");
+ free_cache(1);
+ pthread_mutex_destroy(&structure_guard_mutex);
+ initialized = 0;
+ DBUG_VOID_RETURN;
+}
+
+#ifndef DBUG_OFF
- lex_start(thd, (uchar *)sql, length);
+void Query_cache::wreck(uint line, const char * message)
+{
+ DBUG_ENTER("Query_cache::wreck");
+ query_cache_size = 0;
+ DBUG_PRINT("error", (" %s", message));
+ DBUG_PRINT("warning", ("=================================="));
+ DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
+ DBUG_PRINT("warning", ("=================================="));
+ current_thd->killed = 1;
+ bins_dump();
+ cache_dump();
+ DBUG_VOID_RETURN;
+}
- if (hash_insert(&sql_cache, (const byte *)ptr)) {
- fprintf(stderr, "Out of memory during hash_insert?\n");
+void Query_cache::bins_dump()
+{
+ DBUG_PRINT("info", ("mem_bin_num=%u, mem_bin_steps=%u",
+ mem_bin_num, mem_bin_steps));
+ DBUG_PRINT("info", ("-------------------------"));
+ DBUG_PRINT("info", (" size idx step"));
+ DBUG_PRINT("info", ("-------------------------"));
+ uint i = 0;
+ for(; i < mem_bin_steps; i++)
+ {
+ DBUG_PRINT("info", ("%10lu %3d %10lu", steps[i].size, steps[i].idx,
+ steps[i].increment));
+ }
+ DBUG_PRINT("info", ("-------------------------"));
+ DBUG_PRINT("info", (" size num"));
+ DBUG_PRINT("info", ("-------------------------"));
+ i = 0;
+ for(; i < mem_bin_num; i++)
+ {
+ DBUG_PRINT("info", ("%10lu %3d 0x%lx", bins[i].size, bins[i].number,
+ (ulong)&(bins[i])));
+ if (bins[i].free_blocks)
+ {
+ Query_cache_block * block = bins[i].free_blocks;
+ do{
+ DBUG_PRINT("info", ("\\-- %lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ block->length, (ulong)block,
+ (ulong)block->next, (ulong)block->prev,
+ (ulong)block->pnext, (ulong)block->pprev));
+ block = block->next;
+ } while ( block != bins[i].free_blocks );
}
- fprintf(stderr, "Query `%s' not found in the cache -- insert %p from slot %d\n", thd->lex_ptr->ptr, ptr, last_lex_array_item+1);
- if (!hash_search(&sql_cache, sql, length)) {
- fprintf(stderr, "I just enterred a hash key but it's not where -- what's that?\n");
- } else {
- fprintf(stderr, "Inserted to cache\n");
+ }
+ DBUG_PRINT("info", ("-------------------------"));
+}
+
+void Query_cache::cache_dump()
+{
+ DBUG_PRINT("info", ("-------------------------------------"));
+ DBUG_PRINT("info", (" length used t nt"));
+ DBUG_PRINT("info", ("-------------------------------------"));
+ Query_cache_block * i = first_block;
+ do
+ {
+ DBUG_PRINT("info",
+ ("%10lu %10lu %1d %2d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ i->length, i->used, (int)i->type,
+ i->n_tables, (ulong)i,
+ (ulong)i->next, (ulong)i->prev, (ulong)i->pnext,
+ (ulong)i->pprev));
+ i = i->pnext;
+ } while ( i != first_block );
+ DBUG_PRINT("info", ("-------------------------------------"));
+}
+void Query_cache::queries_dump()
+{
+ DBUG_PRINT("info", ("------------------"));
+ DBUG_PRINT("info", (" QUERIES"));
+ DBUG_PRINT("info", ("------------------"));
+ if (queries_blocks != 0)
+ {
+ Query_cache_block * i = queries_blocks;
+ do
+ {
+ uint len;
+ char * str = (char*) Query_cache_query::cache_key((byte*) i, &len, 0);
+ byte flags = (byte) str[len-1];
+ str[len-1] = 0; //safe only under structure_guard_mutex locked
+ DBUG_PRINT("info", ("%u (%u,%u) %s",len,
+ ((flags & QUERY_CACHE_CLIENT_LONG_FLAG_MASK)?1:0),
+ (flags & QUERY_CACHE_CHARSET_CONVERT_MASK), str));
+ str[len-1] = (char)flags;
+ DBUG_PRINT("info", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong)i,
+ (ulong)i->next, (ulong)i->prev, (ulong)i->pnext,
+ (ulong)i->pprev));
+ TABLE_COUNTER_TYPE t = 0;
+ for (; t < i->n_tables; t++)
+ {
+ Query_cache_table * table = i->table(t)->parent;
+ DBUG_PRINT("info", ("-t- '%s' '%s'", table->db(), table->table()));
+ }
+ Query_cache_query * header = i->query();
+ if (header->result())
+ {
+ Query_cache_block * result_block = header->result();
+ Query_cache_block * result_beg = result_block;
+ do
+ {
+ DBUG_PRINT("info", ("-r- %u %lu/%lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ (uint) result_block->type,
+ result_block->length, result_block->used,
+ (ulong) result_block,
+ (ulong) result_block->next,
+ (ulong) result_block->prev,
+ (ulong) result_block->pnext,
+ (ulong) result_block->pprev));
+ result_block = result_block->next;
+ } while ( result_block != result_beg );
+ }
+ i = i->next;
+ } while ( i != queries_blocks );
+ }
+ else
+ {
+ DBUG_PRINT("info", ("no queries in list"));
+ }
+ DBUG_PRINT("info", ("------------------"));
+}
+
+void Query_cache::tables_dump()
+{
+ DBUG_PRINT("info", ("--------------------"));
+ DBUG_PRINT("info", ("TABLES"));
+ DBUG_PRINT("info", ("--------------------"));
+ int i = 0;
+ for(; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ DBUG_PRINT("info", ("--- type %u", i));
+ if (tables_blocks[i] != 0)
+ {
+ Query_cache_block * table_block = tables_blocks[i];
+ do
+ {
+ Query_cache_table * table = table_block->table();
+ DBUG_PRINT("info", ("'%s' '%s'", table->db(), table->table()));
+ table_block = table_block->next;
+ } while ( table_block != tables_blocks[i]);
}
- return 0;
+ else
+ DBUG_PRINT("info", ("no tables in list"));
}
+ DBUG_PRINT("info", ("--------------------"));
+}
+
#endif
- return 1;
+
+/*****************************************************************************
+ * init/destroy
+ *****************************************************************************/
+
+void Query_cache::init()
+{
+ DBUG_ENTER("Query_cache::init");
+ pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
+ initialized = 1;
+ DBUG_VOID_RETURN;
+}
+
+ulong Query_cache::init_cache()
+{
+ DBUG_ENTER("Query_cache::init_cache");
+ if (!initialized)
+ {
+ DBUG_PRINT("info", ("first time init"));
+ init();
+ }
+ ulong additional_data_size = 0,
+ approx_additional_data_size = sizeof(Query_cache) +
+ sizeof(gptr)*(def_query_hash_size+def_query_hash_size);
+
+ ulong max_mem_bin_size = 0;
+ if (query_cache_size < approx_additional_data_size)
+ {
+ additional_data_size = 0;
+ approx_additional_data_size = 0;
+ make_disabled();
+ }
+ else
+ {
+ query_cache_size -= approx_additional_data_size;
+
+ //Count memory bins number.
+
+ /*
+ The idea is inherited from GNU malloc with some add-ons.
+ Free memory blocks are stored in bins according to their sizes.
+ The bins are stored in size-descending order.
+ The bins are approximately logarithmically separated by size.
+
+ Opposite to GNU malloc bin splitting is not fixed but calculated
+ depending on cache size. Spliting calculating stored in cache and
+ then used for bin finding.
+
+ For example:
+ query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 = 100,
+ min_allocation_unit = 17,
+ QUERY_CACHE_MEM_BIN_STEP_PWR2 = 1,
+ QUERY_CACHE_MEM_BIN_PARTS_INC = 1,
+ QUERY_CACHE_MEM_BIN_PARTS_MUL = 1
+ (in followed picture showed right (low) bound of bin):
+
+ | 100>>1 50>>1 |25>>1|
+ | | | | | |
+ | 100 75 50 41 33 25 21 18 15| 12 | - bins right (low) bounds
+ |\---/\-----/\--------/\--------|---/ |
+ | 0 1 2 3 | | - steps
+ \-----------------------------/ \---/
+ bins that we store in cache this bin showed for example only
+ */
+ max_mem_bin_size =
+ query_cache_size >> QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2;
+ uint mem_bin_count = 1 + QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ mem_bin_num = 1;
+ mem_bin_steps = 1;
+ ulong mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ ulong prev_size = 0;
+ while (mem_bin_size > min_allocation_unit)
+ {
+ mem_bin_num += mem_bin_count;
+ prev_size = mem_bin_size;
+ mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ mem_bin_steps++;
+ mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+
+ //prevent too small bins spacing
+ if (mem_bin_count > (mem_bin_size>>QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
+ mem_bin_count=(mem_bin_size>>QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
+ }
+ ulong inc = (prev_size - mem_bin_size) / mem_bin_count;
+ mem_bin_num += (mem_bin_count - (min_allocation_unit - mem_bin_size)/inc);
+ mem_bin_steps++;
+ additional_data_size = mem_bin_num *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin))+
+ mem_bin_steps * ALIGN_SIZE(sizeof(Query_cache_memory_bin_step));
+ }
+ if (query_cache_size < additional_data_size)
+ {
+ additional_data_size = 0;
+ approx_additional_data_size = 0;
+ make_disabled();
+ }
+ else
+ query_cache_size -= additional_data_size;
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size <= min_allocation_unit)
+ {
+ DBUG_PRINT("info",
+ (" query_cache_size <= min_allocation_unit => cache disabled"));
+ make_disabled();
+ }
+ else
+ {
+ if ( (cache = (byte *)
+ my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))==0 )
+ {
+ DBUG_PRINT("warning",
+ ("can't allocate query cache memory => cache disabled"));
+ make_disabled();
+ }
+ else
+ {
+ DBUG_PRINT("info",
+ ("cache length %lu, min unit %lu, %u bins",
+ query_cache_size, min_allocation_unit, mem_bin_num));
+
+ steps = (Query_cache_memory_bin_step *) cache;
+ bins = (Query_cache_memory_bin *)
+ (cache +
+ mem_bin_steps * ALIGN_SIZE(sizeof(Query_cache_memory_bin_step)));
+
+ first_block = (Query_cache_block *) (cache + additional_data_size);
+ first_block->init(query_cache_size);
+ first_block->pnext=first_block->pprev=first_block;
+ first_block->next=first_block->prev=first_block;
+
+ free_memory = query_cache_size;
+
+ /* prepare bins */
+
+ bins[0].init(max_mem_bin_size);
+ steps[0].init(max_mem_bin_size,0,0);
+ uint mem_bin_count = 1 + QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ uint num = 1;
+ ulong mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ uint step = 1;
+ while (mem_bin_size > min_allocation_unit)
+ {
+ ulong inc = (steps[step-1].size - mem_bin_size) / mem_bin_count;
+
+ unsigned long size = mem_bin_size;
+ uint i = mem_bin_count;
+ for(; i > 0; i--)
+ {
+ bins[num+i-1].init(size);
+ size += inc;
+ }
+ num += mem_bin_count;
+ steps[step].init(mem_bin_size, num-1, inc);
+ mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ step++;
+ mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ if (mem_bin_count > (mem_bin_size>>QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
+ mem_bin_count=(mem_bin_size>>QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
+ }
+ ulong inc = (steps[step-1].size - mem_bin_size) / mem_bin_count;
+ /*
+ num + mem_bin_count > mem_bin_num, but index never be > mem_bin_num
+ because block with size < min_allocated_unit never will be requested
+ */
+ steps[step].init(mem_bin_size, num + mem_bin_count - 1, inc);
+ uint skiped = (min_allocation_unit - mem_bin_size)/inc;
+ ulong size = mem_bin_size + inc*skiped;
+ uint i = mem_bin_count - skiped;
+ for(; i > 0; i--)
+ {
+ bins[num+i-1].init(size);
+ size += inc;
+ }
+
+ insert_into_free_memory_list(first_block);
+
+ DUMP(this);
+
+ VOID(hash_init(&queries,def_query_hash_size, 0, 0,
+ Query_cache_query::cache_key,
+ (void (*)(void*))Query_cache_query::free_cache,
+ 0));
+ VOID(hash_init(&tables,def_table_hash_size, 0, 0,
+ Query_cache_table::cache_key,
+ (void (*)(void*))Query_cache_table::free_cache,
+ 0));
+ }
+ }
+ queries_in_cache = 0;
+ queries_blocks = 0;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(query_cache_size +
+ additional_data_size + approx_additional_data_size);
+}
+
+void Query_cache::make_disabled()
+{
+ DBUG_ENTER("Query_cache::make_disabled");
+ query_cache_size = 0;
+ free_memory = 0;
+ bins = 0;
+ steps = 0;
+ cache = 0;
+ mem_bin_num = mem_bin_steps = 0;
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::free_cache(my_bool destruction)
+{
+ DBUG_ENTER("Query_cache::free_cache");
+ if (query_cache_size > 0)
+ {
+ if (!destruction)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ flush_cache();
+#ifndef DBUG_OFF
+ if (bins[0].free_blocks == 0)
+ {
+ wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
+ }
+#endif
+
+ bins[0].free_blocks->destroy(); /* all cache memory must be
+ in one this block */
+ DBUG_PRINT("info", ("free memory %lu (should be %lu)",
+ free_memory , query_cache_size));
+ free_memory = 0;
+
+ my_free((gptr)cache, MYF(MY_ALLOW_ZERO_PTR));
+ first_block = 0;
+ bins = 0;
+ cache = 0;
+ query_cache_size = 0;
+ hash_free(&queries);
+ hash_free(&tables);
+ queries_in_cache = 0;
+ if (!destruction)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ * free block data
+ *****************************************************************************/
+
+void Query_cache::flush_cache()
+{
+ while(queries_blocks != 0){
+ BLOCK_LOCK_WR(queries_blocks);
+ free_query(queries_blocks);
+ }
+}
+
+my_bool Query_cache::free_old_query()
+{
+ DBUG_ENTER("Query_cache::free_old_query");
+ if (queries_blocks == 0)
+ {
+ DBUG_RETURN(0);
+ }
+ /*
+ try_lock_writing used to prevent clinch because
+ here lock sequence is breached, also we don't need remove
+ locked queries at this point
+ */
+ Query_cache_block *query_block = 0;
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *i = queries_blocks;
+ do
+ {
+ Query_cache_query * header = i->query();
+ if (header->result() != 0 &&
+ header->result()->type == Query_cache_block::RESULT &&
+ i->query()->try_lock_writing())
+ {
+ query_block = i;
+ break;
+ }
+ i = i->next;
+ } while ( i != queries_blocks );
+ }
+
+ if (query_block != 0)
+ {
+ free_query(query_block);
+ DBUG_RETURN(1);
+ }
+ else
+ DBUG_RETURN(0);
+}
+
+/* query_block must be lock_writing() */
+void Query_cache::free_query(Query_cache_block * query_block)
+{
+ DBUG_ENTER("Query_cache::free_query");
+ DBUG_PRINT("info", ("free query 0x%lx %lu bytes result",
+ (ulong)query_block,
+ query_block->query()->length() ));
+ queries_in_cache--;
+ hash_delete(&queries,(byte *) query_block);
+
+ Query_cache_query * query = query_block->query();
+ if (query->writer() != 0)
+ {
+ query->writer()->query_cache_query = 0;
+ query->writer(0);
+ }
+ double_linked_list_exclude(query_block, queries_blocks);
+ TABLE_COUNTER_TYPE i = 0;
+ for(; i < query_block->n_tables; i++)
+ {
+ unlink_table(query_block->table(i));
+ }
+ Query_cache_block *result_block = query->result();
+ if (result_block != 0)
+ {
+ Query_cache_block * block = result_block;
+ do
+ {
+ Query_cache_block * current = block;
+ block = block->next;
+ free_memory_block(current);
+ } while (block != result_block);
+ }
+
+ query->unlock_n_destroy();
+ free_memory_block(query_block);
+
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ * query data creation
+ *****************************************************************************/
+
+Query_cache_block *
+Query_cache::write_block_data(ulong data_len, gptr data,
+ ulong header_len,
+ Query_cache_block::block_type type,
+ TABLE_COUNTER_TYPE ntab,
+ my_bool under_guard)
+{
+ DBUG_ENTER("Query_cache::write_block_data");
+ ulong all_headers_len = ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ntab*ALIGN_SIZE(sizeof(Query_cache_block_table)) +
+ header_len;
+ DBUG_PRINT("info", ("data: %ld, header: %ld, all header: %ld",
+ data_len, header_len, all_headers_len));
+ ulong len = data_len + all_headers_len;
+ Query_cache_block * block = allocate_block(max(len, min_allocation_unit),
+ 1, 0, under_guard);
+ if (block != 0)
+ {
+ block->type = type;
+ block->n_tables = ntab;
+ block->used = len;
+
+ memcpy((void*)(((byte *) block)+
+ all_headers_len),
+ (void*)data,
+ data_len);
+ }
+ DBUG_RETURN(block);
+}
+
+my_bool
+Query_cache::append_result_data(Query_cache_block * &result,
+ ulong data_len, gptr data,
+ Query_cache_block * query_block,
+ Query_cache_block * first_data_block)
+{
+ DBUG_ENTER("Query_cache::uppend_result_data");
+ DBUG_PRINT("info", ("append %lu bytes to 0x%lx query"));
+ if (query_block->query()->add(data_len) > query_cache_limit)
+ {
+ DBUG_PRINT("info", ("size limit reached %lu > %lu",
+ query_block->query()->length(),
+ query_cache_limit));
+ result=0;
+ DBUG_RETURN(0);
+ }
+ if (first_data_block == 0)
+ {
+ DBUG_PRINT("info", ("allocated first result data block 0x%xl", data_len));
+ /*
+ STRUCT_UNLOCK(&structure_guard_mutex); will be done by
+ query_cache.append_result_data if success;
+ */
+ DBUG_RETURN(write_result_data(result, data_len, data, query_block,
+ Query_cache_block::RES_BEG));
+ }
+ else
+ {
+ result = first_data_block;
+ }
+ Query_cache_block * last_block = first_data_block->prev;
+
+ DBUG_PRINT("info", ("lastblock 0x%lx len %lu used %lu",
+ (ulong)last_block, last_block->length,
+ last_block->used));
+ my_bool success = 1;
+
+ ulong last_block_free_space = last_block->length - last_block->used;
+
+ //write 'tail' of data, that can't be appended to last block
+
+ //try join blocks if physicaly next block is free...
+ if (last_block_free_space < data_len &&
+ append_next_free_block(last_block,
+ max(data_len - last_block_free_space,
+ QUERY_CACHE_MIN_RESULT_DATA_SIZE)))
+ last_block_free_space = last_block->length - last_block->used;
+ //if no space in last block (even after join) allocate new block
+ if (last_block_free_space < data_len)
+ {
+ //TODO try get memory from next free block (if exist) (is it needed?)
+ DBUG_PRINT("info", ("allocate new block for %lu bytes",
+ data_len-last_block_free_space));
+ Query_cache_block *new_block = 0;
+ /*
+ STRUCT_UNLOCK(&structure_guard_mutex); will be done by
+ query_cache.append_result_data
+ */
+ success = write_result_data(new_block, data_len-last_block_free_space,
+ (gptr)(((byte*)data)+last_block_free_space),
+ query_block,
+ Query_cache_block::RES_CONT);
+ /*
+ new_block may be not 0 even !success (if write_result_data
+ allocate small block but filed allocate continue
+ */
+ if (new_block != 0)
+ double_linked_list_join(last_block, new_block);
+ }
+ else
+ //it is success (nobody can prevent us write data)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ // append last block (if it is possible)
+ if (last_block_free_space > 0)
+ {
+ ulong to_copy = min(data_len,last_block_free_space);
+ DBUG_PRINT("info", ("use free space %lub at block 0x%lx to copy %lub",
+ last_block_free_space, (ulong)last_block, to_copy));
+ memcpy((void*)(((byte*)last_block)+last_block->used),
+ (void*)data,to_copy);
+ last_block->used+=to_copy;
+ }
+
+ DBUG_RETURN(success);
+}
+
+my_bool Query_cache::write_result_data(Query_cache_block * &result_block,
+ ulong data_len, gptr data,
+ Query_cache_block * query_block,
+ Query_cache_block::block_type type)
+{
+ DBUG_ENTER("Query_cache::write_result_data");
+ DBUG_PRINT("info", ("data_len %lu",data_len));
+
+ //reserve block(s) for filling
+ my_bool success = allocate_data_chain(result_block, data_len, query_block);
+ if (success)
+ {
+ //it is success (nobody can prevent us write data)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ byte * rest = (byte*) data;
+ Query_cache_block * block = result_block;
+ uint headers_len = ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result));
+ // now fill list of blocks that created by allocate_data_chain
+ do
+ {
+ block->type = type;
+ ulong length = block->used - headers_len;
+ DBUG_PRINT("info", ("write %lu byte in block 0x%lx",length,
+ (ulong)block));
+ memcpy((void*)(((byte*)block)+headers_len),
+ (void*)rest,length);
+
+ rest += length;
+ block = block->next;
+ type = Query_cache_block::RES_CONT;
+ } while (block != result_block);
+ }
+ else
+ {
+ if (result_block != 0)
+ {
+ // destroy list of blocks that created & locked by lock_result_data
+ Query_cache_block * block = result_block;
+ do
+ {
+ Query_cache_block * current = block;
+ block = block->next;
+ free_memory_block(current);
+ } while (block != result_block);
+ result_block = 0;
+ /*
+ it is not success => not unlock structure_guard_mutex (we need it to
+ free query)
+ */
+ }
+ }
+ DBUG_PRINT("info", ("success %d", (int) success));
+ DBUG_RETURN(success);
+}
+
+my_bool Query_cache::allocate_data_chain(Query_cache_block * &result_block,
+ ulong data_len,
+ Query_cache_block * query_block)
+{
+ DBUG_ENTER("Query_cache::allocate_data_chain");
+
+ ulong all_headers_len = ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result));
+ ulong len = data_len + all_headers_len;
+ DBUG_PRINT("info", ("data_len %lu, all_headers_len %lu",
+ data_len, all_headers_len));
+
+ result_block = allocate_block(max(min_result_data_size,len),
+ min_result_data_size == 0,
+ all_headers_len + min_result_data_size,
+ 1);
+ my_bool success = (result_block != 0);
+ if (success)
+ {
+ result_block->n_tables = 0;
+ result_block->used = 0;
+ result_block->type = Query_cache_block::RES_INCOMPLETE;
+ result_block->next = result_block->prev = result_block;
+ Query_cache_result * header = result_block->result();
+ header->parent(query_block);
+
+ Query_cache_block * next_block = 0;
+ if (result_block->length < len)
+ {
+ /*
+ allocated less memory then we need (no big memory blocks) =>
+ to be continue
+ */
+ Query_cache_block * next_block;
+ if ((success = allocate_data_chain(next_block,
+ len - result_block->length,
+ query_block)))
+ double_linked_list_join(result_block, next_block);
+ }
+ if (success)
+ {
+ result_block->used = min(len, result_block->length);
+
+ DBUG_PRINT("info", ("Block len %lu used %lu",
+ result_block->length, result_block->used));
+ }
+ else
+ DBUG_PRINT("warning", ("Can't allocate block for continue"));
+ }
+ else
+ DBUG_PRINT("warning", ("Can't allocate block for results"));
+ DBUG_RETURN(success);
+}
+
+/*****************************************************************************
+ * tables management
+ *****************************************************************************/
+
+void Query_cache::invalidate_table(TABLE_LIST *table_list)
+{
+ if (table_list->table != 0)
+ invalidate_table(table_list->table);
+ else
+ {
+ char key[MAX_DBKEY_LENGTH], *key_ptr;
+ uint key_length;
+ Query_cache_block *table_block;
+ key_length=(uint) (strmov(strmov(key,table_list->db)+1,
+ table_list->real_name) -key)+ 1;
+ key_ptr = key;
+
+ // we dont store temporary tables => no key_length+=4 ...
+ if ((table_block = (Query_cache_block*)
+ hash_search(&tables,key_ptr,key_length)))
+ invalidate_table(table_block);
+ }
+}
+
+void Query_cache::invalidate_table(TABLE *table)
+{
+ Query_cache_block *table_block;
+ if ((table_block = (Query_cache_block*)
+ hash_search(&tables,table->table_cache_key,table->key_length)))
+ invalidate_table(table_block);
+}
+
+void Query_cache::invalidate_table_in_db(Query_cache_block *table_block,
+ char * db)
+{
+ /*
+ table key consist of data_base_name + '\0' + table_name +'\0'...
+ => we may use strcmp.
+ */
+ if (strcmp(db, (char*)(table_block->table()->db()))==0)
+ {
+ invalidate_table(table_block);
+ }
+}
+
+void Query_cache::invalidate_table(Query_cache_block *table_block)
+{
+ Query_cache_block_table * list_root = table_block->table(0);
+ while(list_root->next != list_root)
+ {
+ Query_cache_block * query_block = list_root->next->block();
+ BLOCK_LOCK_WR(query_block);
+ free_query(query_block);
+ }
+}
+
+my_bool Query_cache::register_all_tables(Query_cache_block * block,
+ TABLE_LIST * tables_used,
+ TABLE_COUNTER_TYPE tables)
+{
+ DBUG_PRINT("info", ("register tables block 0x%lx, n %d, header %x",
+ (ulong)block, (int) tables,
+ (int)ALIGN_SIZE(sizeof(Query_cache_block)) ));
+
+ TABLE_COUNTER_TYPE n = 0;
+ TABLE_LIST * i = tables_used;
+ for(; i != 0; i=i->next, n++)
+ {
+ DBUG_PRINT("info",
+ ("table %s, db %s, openinfo at 0x%lx, keylen %u, key at 0x%lx",
+ i->real_name, i->db, (ulong) i->table,
+ i->table->key_length,
+ (ulong) i->table->table_cache_key));
+ Query_cache_block_table * block_table = block->table(n);
+ block_table->n=n;
+ if (!insert_table(i->table->key_length,
+ i->table->table_cache_key, block_table,
+ Query_cache_table::type_convertion(i->table->db_type)))
+ break;
+ if (i->table->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ ha_myisammrg * handler = (ha_myisammrg *)i->table->file;
+ MYRG_INFO *file = handler->myrg_info();
+ MYRG_TABLE *table = file->open_tables;
+ for(;table != file->end_table ; table++)
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length =
+ Query_cache::filename_2_table_key(key, table->table->filename);
+ n++;
+ Query_cache_block_table * block_table = block->table(n);
+ block_table->n=n;
+ if (!insert_table(key_length, key, block_table,
+ Query_cache_table::type_convertion(DB_TYPE_MYISAM)))
+ goto err;
+ }
+ }
+ }
+err:
+ if (i != 0)
+ {
+ n--;
+ DBUG_PRINT("info", ("filed at table %d", (int)n));
+ TABLE_COUNTER_TYPE idx = 0;
+ for(i = tables_used;
+ idx < n;
+ idx++)
+ {
+ unlink_table(block->table(n));
+ }
+ }
+ return(i == 0);
+}
+
+my_bool Query_cache::insert_table(uint key_len, char * key,
+ Query_cache_block_table * node,
+ Query_cache_table::query_cache_table_type
+ type)
+{
+ DBUG_ENTER("Query_cache::insert_table");
+ DBUG_PRINT("info", ("insert table node 0x%lx, len %d",
+ (ulong)node, key_len));
+ Query_cache_block *table_block = (Query_cache_block *)
+ hash_search(&tables, key, key_len);
+
+ if (table_block == 0)
+ {
+ DBUG_PRINT("info", ("new table block from 0x%lx (%u)",
+ (ulong)key, (int) key_len));
+ table_block = write_block_data(key_len, (gptr) key,
+ ALIGN_SIZE(sizeof(Query_cache_table)),
+ Query_cache_block::TABLE,
+ 1, 1);
+ if (table_block == 0)
+ {
+ DBUG_PRINT("info", ("Can't write table name to cache"));
+ DBUG_RETURN(0);
+ }
+ Query_cache_table * header = table_block->table();
+ header->type(type);
+ double_linked_list_simple_include(table_block,
+ tables_blocks[type]);
+ Query_cache_block_table * list_root = table_block->table(0);
+ list_root->n = 0;
+ list_root->next = list_root->prev = list_root;
+ if (hash_insert(&tables, (const byte *)table_block))
+ {
+ DBUG_PRINT("info", ("Can't insert table to hash"));
+ // write_block_data return locked block
+ free_memory_block(table_block);
+ DBUG_RETURN(0);
+ }
+ char * db = header->db();
+ header->table(db + strlen(db) + 1);
+ }
+
+ Query_cache_block_table * list_root = table_block->table(0);
+ node->next = list_root->next; list_root->next = node;
+ node->next->prev = node; node->prev = list_root;
+ node->parent = table_block->table();
+ DBUG_RETURN(1);
+}
+
+void Query_cache::unlink_table(Query_cache_block_table * node)
+{
+ node->prev->next = node->next; node->next->prev = node->prev;
+ Query_cache_block_table * neighbour = node->next;
+ if (neighbour->next == neighbour)
+ {
+ // list is empty (neighbour is root of list)
+ Query_cache_block * table_block = neighbour->block();
+ double_linked_list_exclude(table_block,
+ tables_blocks[table_block->table()->type()]);
+ hash_delete(&tables,(byte *) table_block);
+ free_memory_block(table_block);
+ }
+}
+
+/*****************************************************************************
+ * free memory management
+ *****************************************************************************/
+
+Query_cache_block * Query_cache::allocate_block(ulong len,
+ my_bool not_less,
+ ulong min,
+ my_bool under_guard)
+{
+ DBUG_ENTER("Query_cache::allocate_n_lock_block");
+ DBUG_PRINT("info", ("len %lu, not less %d, min %lu, uder_guard %d",
+ len, not_less,min,under_guard));
+
+ if (len >= min(query_cache_size, query_cache_limit))
+ {
+ DBUG_PRINT("info", ("Query cache hase only %lu memory and limit %lu",
+ query_cache_size, query_cache_limit));
+ DBUG_RETURN(0); // in any case we don't have such piece of memory
+ }
+
+ if (!under_guard){STRUCT_LOCK(&structure_guard_mutex);};
+
+ Query_cache_block *block = get_free_block(len, not_less, min);
+ while( block == 0 && free_old_query())
+ {
+ block = get_free_block(len, not_less, min);
+ }
+
+ if (block!=0)
+ {
+ if (block->length > ALIGN_SIZE(len) + min_allocation_unit)
+ split_block(block,ALIGN_SIZE(len));
+ }
+
+ if (!under_guard){STRUCT_UNLOCK(&structure_guard_mutex);};
+ DBUG_RETURN(block);
+}
+
+Query_cache_block * Query_cache::get_free_block (ulong len,
+ my_bool not_less,
+ ulong min)
+{
+ DBUG_ENTER("Query_cache::get_free_block");
+ Query_cache_block *block = 0, *first = 0;
+ DBUG_PRINT("info",("length %lu, not_less %d, min %lu", len,
+ (int)not_less, min));
+
+ /* find block with minimal size > len */
+
+ uint start = find_bin(len);
+ // try matching bin
+ if (bins[start].number != 0)
+ {
+ Query_cache_block * list = bins[start].free_blocks;
+ first = list;
+ while(first->next != list && first->length < len)
+ {
+ first=first->next;
+ }
+ if (first->length >= len)
+ block=first;
+ }
+ if (block == 0 && start > 0)
+ {
+ DBUG_PRINT("info",("try bins whith more bigger blocks"));
+ //try more big bins
+ int i = start - 1;
+ while(i > 0 && bins[i].number == 0)
+ i--;
+ if (bins[i].number > 0)
+ block = bins[i].free_blocks;
+ }
+ // if no big blocks => try less size (if it is possible)
+ if (block == 0 && ! not_less)
+ {
+ DBUG_PRINT("info",("try smaller blocks"));
+ if (first != 0 && first->length > min)
+ block = first;
+ else
+ {
+ uint i = start + 1;
+ while( i < mem_bin_num && bins[i].number == 0)
+ i++;
+ if (i < mem_bin_num && bins[i].number > 0 &&
+ bins[i].free_blocks->prev->length >= min)
+ block = bins[i].free_blocks->prev;
+ }
+ }
+ if (block != 0)
+ exclude_from_free_memory_list(block);
+
+ DBUG_PRINT("info",("getting block 0x%lx", (ulong) block));
+ DBUG_RETURN(block);
+}
+
+void Query_cache::free_memory_block(Query_cache_block * block)
+{
+ DBUG_ENTER("Query_cache::free_n_unlock_memory_block");
+ block->used=0;
+ DBUG_PRINT("info",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
+ (ulong) first_block, (ulong) block,block->pnext,
+ (ulong) block->pprev));
+ if (block->pnext != first_block && block->pnext->is_free())
+ {
+ block = join_free_blocks(block, block->pnext);
+ }
+ if (block != first_block && block->pprev->is_free())
+ {
+ block = join_free_blocks(block->pprev, block->pprev);
+ }
+ insert_into_free_memory_list(block);
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::split_block(Query_cache_block * block,ulong len)
+{
+ DBUG_ENTER("Query_cache::split_block");
+ Query_cache_block * new_block = (Query_cache_block *)(((byte*)block)+len);
+
+ new_block->init(block->length - len);
+ block->length=len;
+ new_block->pnext = block->pnext; block->pnext = new_block;
+ new_block->pprev = block; new_block->pnext->pprev = new_block;
+
+ insert_into_free_memory_list(new_block);
+
+ DBUG_PRINT("info", ("split 0x%lx (%lu) new 0x%lx",
+ (ulong) block, len, (ulong) new_block));
+ DBUG_VOID_RETURN;
+}
+
+Query_cache_block *
+Query_cache::join_free_blocks(Query_cache_block *first_block,
+ Query_cache_block * block_in_list)
+{
+ DBUG_ENTER("Query_cache::join_free_blocks");
+ DBUG_PRINT("info",
+ ("join first 0x%lx, pnext 0x%lx, in list 0x%lx",
+ (ulong) first_block, (ulong) first_block->pnext,
+ (ulong) block_in_list));
+ exclude_from_free_memory_list(block_in_list);
+
+ Query_cache_block * second_block = first_block->pnext;
+ // may be was not free block
+ second_block->type = Query_cache_block::FREE;second_block->used=0;
+ second_block->destroy();
+
+ first_block->length += second_block->length;
+ first_block->pnext = second_block->pnext;
+ second_block->pnext->pprev = first_block;
+
+ DBUG_RETURN(first_block);
+}
+
+my_bool Query_cache::append_next_free_block(Query_cache_block * block,
+ ulong add_size)
+{
+ DBUG_ENTER("Query_cache::append_next_free_block");
+ DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
+ add_size));
+ Query_cache_block * next_block = block->pnext;
+ if (next_block->is_free())
+ {
+ exclude_from_free_memory_list(next_block);
+ ulong old_len = block->length;
+
+ next_block->destroy();
+
+ block->length += next_block->length;
+ block->pnext = next_block->pnext;
+ next_block->pnext->pprev = block;
+
+ if (block->length >
+ ALIGN_SIZE(old_len + add_size) + min_allocation_unit)
+ split_block(block,ALIGN_SIZE(old_len + add_size));
+ DBUG_PRINT("exit", ("block was appended"));
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("exit", ("block was not appended"));
+ DBUG_RETURN(0);
+ }
+}
+
+void Query_cache::exclude_from_free_memory_list(Query_cache_block * free_block)
+{
+ DBUG_ENTER("Query_cache::exclude_from_free_memory_list");
+ Query_cache_memory_bin * bin = *((Query_cache_memory_bin **)
+ free_block->data());
+ double_linked_list_exclude(free_block ,bin->free_blocks);
+ bin->number--;
+ free_memory-=free_block->length;
+ DBUG_PRINT("info",("exclude block 0x%lx, bin 0x%lx", (ulong) free_block,
+ (ulong)bin));
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::insert_into_free_memory_list(Query_cache_block * free_block)
+{
+ DBUG_ENTER("Query_cache::insert_into_free_memory_list");
+ uint idx = find_bin(free_block->length);
+ insert_into_free_memory_sorted_list(free_block, bins[idx].free_blocks);
+ /*
+ we have enough memory in block for storing bin reference due to
+ min_allocation_unit choice
+ */
+ Query_cache_memory_bin * *bin_ptr = (Query_cache_memory_bin**)
+ free_block->data();
+ *bin_ptr = &(bins[idx]);
+ bins[idx].number++;
+ DBUG_PRINT("info",("insert block 0x%lx, bin[%d] 0x%lx",
+ (ulong) free_block, idx,
+ (ulong) &(bins[idx])));
+ DBUG_VOID_RETURN;
+}
+
+uint Query_cache::find_bin(ulong size)
+{
+ DBUG_ENTER("Query_cache::find_bin");
+ //begin small blocks to big (small blocks frequently asked)
+ int i = mem_bin_steps - 1;
+ for(; i > 0 && steps[i-1].size < size; i--);
+ if (i == 0)
+ {
+ // first bin not subordinate of common rules
+ DBUG_PRINT("info", ("first bin (# 0), size %lu",size));
+ DBUG_RETURN(0);
+ }
+ uint bin = steps[i].idx - (uint)((size - steps[i].size)/steps[i].increment);
+ DBUG_PRINT("info", ("bin %u step %u, size %lu", bin, i, size));
+ DBUG_RETURN(bin);
+}
+
+/*****************************************************************************
+ * lists management
+ *****************************************************************************/
+
+void Query_cache::move_to_query_list_end(Query_cache_block * query_block)
+{
+ DBUG_ENTER("Query_cache::move_to_query_list_end");
+ double_linked_list_exclude(query_block, queries_blocks);
+ double_linked_list_simple_include(query_block, queries_blocks);
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::insert_into_free_memory_sorted_list(Query_cache_block *
+ new_block,
+ Query_cache_block *
+ &list)
+{
+ DBUG_ENTER("Query_cache::insert_into_free_memory_sorted_list");
+ /*
+ list sorted by size in ascendant order, because we need small blocks
+ frequently than big one
+ */
+
+ new_block->used = 0;
+ new_block->n_tables = 0;
+ new_block->type = Query_cache_block::FREE;
+
+ if (list == 0)
+ {
+ list = new_block->next=new_block->prev=new_block;
+ DBUG_PRINT("info", ("inserted into empty list"));
+ }
+ else
+ {
+ Query_cache_block *point = list;
+ if (point->length >= new_block->length)
+ {
+ point = point->prev;
+ list = new_block;
+ }
+ else
+ {
+ while(point->next != list &&
+ point->next->length < new_block->length)
+ {
+ point=point->next;
+ }
+ }
+ new_block->prev = point; new_block->next = point->next;
+ new_block->next->prev = new_block; point->next = new_block;
+ }
+ free_memory+=new_block->length;
+ DBUG_VOID_RETURN;
+}
+
+
+void
+Query_cache::double_linked_list_simple_include(Query_cache_block * point,
+ Query_cache_block *
+ &list_pointer)
+{
+ DBUG_ENTER("Query_cache::double_linked_list_simple_include");
+ DBUG_PRINT("info", ("including block 0x%lx", (ulong) point));
+ if (list_pointer == 0)
+ list_pointer=point->next=point->prev=point;
+ else
+ {
+ point->next = list_pointer;
+ point->prev = list_pointer->prev;
+ point->prev->next = point;
+ list_pointer->prev = point;
+ list_pointer = point;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void
+Query_cache::double_linked_list_exclude(Query_cache_block *point,
+ Query_cache_block * &list_pointer)
+{
+ DBUG_ENTER("Query_cache::double_linked_list_exclude");
+ DBUG_PRINT("info", ("excluding block 0x%lx, list 0x%lx",
+ (ulong) point, (ulong) list_pointer));
+ if (point->next == point)
+ list_pointer = 0; // empty list
+ else
+ {
+ point->next->prev = point->prev;
+ point->prev->next = point->next;
+ if (point == list_pointer) list_pointer = point->next;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
+ Query_cache_block *tail_head)
+{
+ Query_cache_block *head_head = head_tail->next,
+ *tail_tail = tail_head->prev;
+ head_head->prev = tail_tail;
+ head_tail->next = tail_head;
+ tail_head->prev = head_tail;
+ tail_tail->next = head_head;
+}
+
+/*****************************************************************************
+ * query
+ *****************************************************************************/
+
+/*
+ if query is cachable return numder tables in query
+ (query whithout tables tot chached)
+*/
+TABLE_COUNTER_TYPE Query_cache::is_cachable(THD *thd,
+ uint query_len, char *query,
+ LEX *lex, TABLE_LIST* tables_used)
+{
+ TABLE_COUNTER_TYPE tables = 0;
+ DBUG_ENTER("Query_cache::is_cachable");
+ if (lex->sql_command == SQLCOM_SELECT &&
+ thd->temporary_tables == 0 &&
+ (thd->query_cache_type == 1 || (thd->query_cache_type == 2 &&
+ (lex->select->options &
+ OPTION_TO_QUERY_CACHE))) &&
+ thd->safe_to_cache_query)
+ {
+ DBUG_PRINT("info", ("options %lx %lx, type %u",
+ OPTION_TO_QUERY_CACHE,
+ lex->select->options,
+ (int) thd->query_cache_type));
+ my_bool has_transactions = 0;
+ TABLE_LIST * i = tables_used;
+ for(; i != 0; i=i->next)
+ {
+ tables++;
+ DBUG_PRINT("info", ("table %s, db %s, type %u", i->real_name,
+ i->db, i->table->db_type));
+ has_transactions = (has_transactions ||
+ i->table->file->has_transactions());
+ if (i->table->db_type == DB_TYPE_MRG_ISAM)
+ {
+ DBUG_PRINT("info", ("select not cachable: used MRG_ISAM table(s)"));
+ DBUG_RETURN(0);
+ }
+ if (i->table->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ ha_myisammrg * handler = (ha_myisammrg *)i->table->file;
+ MYRG_INFO *file = handler->myrg_info();
+ MYRG_TABLE *table = file->open_tables;
+ for(;table != file->end_table ; table++)
+ {
+ tables++;
+ DBUG_PRINT("loop", (" + 1 table (mrg_MyISAM)"));
+ }
+ }
+ }
+
+ if ((thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) &&
+ has_transactions)
+ {
+ DBUG_PRINT("info", ("not in autocommin mode"));
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("select have %d tables", tables));
+ DBUG_RETURN(tables);
+ }
+ }
+ DBUG_PRINT("info",
+ ("not interest query: %d or not cachable, \
+options %lx %lx, type %u",
+ (int) lex->sql_command,
+ OPTION_TO_QUERY_CACHE,
+ lex->select->options,
+ (int) thd->query_cache_type));
+ DBUG_RETURN(0);
+}
+
+/*****************************************************************************
+ * packing
+ *****************************************************************************/
+
+void Query_cache::pack_cache()
+{
+ DBUG_ENTER("Query_cache::pack_cache");
+ STRUCT_LOCK(&structure_guard_mutex);
+ DUMP(this);
+ byte * border = 0;
+ Query_cache_block * before = 0;
+ ulong gap = 0;
+ my_bool ok = 1;
+ Query_cache_block * i = first_block;
+ do
+ {
+ ok = move_by_type(border, before, gap, i);
+ i = i->pnext;
+ } while (ok && i != first_block);
+ if (border != 0)
+ {
+ Query_cache_block * new_block = (Query_cache_block *) border;
+ new_block->init(gap);
+ new_block->pnext = before->pnext; before->pnext = new_block;
+ new_block->pprev = before; new_block->pnext->pprev = new_block;
+ insert_into_free_memory_list(new_block);
+ }
+ DUMP(this);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+}
+
+my_bool Query_cache::move_by_type(byte * &border,
+ Query_cache_block * &before, ulong &gap, Query_cache_block * i)
+{
+ DBUG_ENTER("Query_cache::move_by_type");
+ my_bool ok = 1;
+ switch(i->type)
+ {
+ case Query_cache_block::FREE:
+ {
+ DBUG_PRINT("info", ("block 0x%lx FREE", (ulong) i));
+ if (border == 0)
+ {
+ border = (byte *) i;
+ before = i->pprev;
+ DBUG_PRINT("info", ("gap begining here"));
+ }
+ exclude_from_free_memory_list(i);
+ gap +=i->length;
+ i->pprev->pnext=i->pnext;
+ i->pnext->pprev=i->pprev;
+ i->destroy();
+ DBUG_PRINT("info", ("added to gap (%lu)", gap));
+ break;
+ }
+ case Query_cache_block::TABLE:
+ {
+ DBUG_PRINT("info", ("block 0x%lx TABLE", (ulong) i));
+ if (border == 0) break;
+ ulong len = i->length,
+ used = i->used;
+ Query_cache_block_table * list_root = i->table(0);
+ Query_cache_block_table
+ *tprev = list_root->prev,
+ *tnext = list_root->next;
+ Query_cache_block
+ *prev = i->prev,
+ *next = i->next,
+ *pprev = i->pprev,
+ *pnext = i->pnext,
+ *new_block =(Query_cache_block *) border;
+ char * data = (char*)i->data();
+ hash_delete(&tables, (byte *)i);
+ i->destroy();
+ new_block->init(len);
+ new_block->type=Query_cache_block::TABLE;
+ new_block->used=used;
+ new_block->n_tables=1;
+ memcpy((char*)new_block->data(), data,
+ len-new_block->headers_len());
+ relink(i, new_block, next, prev, pnext, pprev);
+ if (tables_blocks[new_block->table()->type()] == i)
+ {
+ tables_blocks[new_block->table()->type()] = new_block;
+ }
+ Query_cache_block_table * nlist_root = new_block->table(0);
+ nlist_root->n = 0;
+ nlist_root->next = (tnext==list_root?nlist_root:tnext);
+ nlist_root->prev = (tprev==list_root?nlist_root:tnext);
+ tnext->prev = list_root;
+ tprev->next = list_root;
+ border += len;
+ before = new_block;
+ hash_insert(&tables, (const byte *)new_block);
+ DBUG_PRINT("info", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) border));
+ break;
+ }
+ case Query_cache_block::QUERY:
+ {
+ DBUG_PRINT("info", ("block 0x%lx QUERY", (ulong) i));
+ if (border == 0) break;
+ BLOCK_LOCK_WR(i);
+ ulong len = i->length,
+ used = i->used;
+ TABLE_COUNTER_TYPE n_tables = i->n_tables;
+ Query_cache_block
+ *prev = i->prev,
+ *next = i->next,
+ *pprev = i->pprev,
+ *pnext = i->pnext,
+ *new_block =(Query_cache_block *) border;
+ char * data = (char*)i->data();
+ Query_cache_block * first_result_block = ((Query_cache_query *)
+ i->data())->result();
+ hash_delete(&queries, (byte *)i);
+ memcpy((char*)new_block->table(0), (char*)i->table(0),
+ n_tables * ALIGN_SIZE(sizeof(Query_cache_block_table)));
+ i->query()->unlock_n_destroy();
+ i->destroy();
+ new_block->init(len);
+ new_block->type=Query_cache_block::QUERY;
+ new_block->used=used;
+ new_block->n_tables=n_tables;
+ memcpy((char*)new_block->data(), data,
+ len - new_block->headers_len());
+ relink(i, new_block, next, prev, pnext, pprev);
+ if (queries_blocks == i)
+ queries_blocks = new_block;
+ TABLE_COUNTER_TYPE j=0;
+ for(; j< n_tables; j++)
+ {
+ Query_cache_block_table * block_table = new_block->table(j);
+ block_table->next->prev = block_table;
+ block_table->prev->next = block_table;
+ }
+ DBUG_PRINT("info", ("after cicle tt"));
+ border += len;
+ before = new_block;
+ new_block->query()->result(first_result_block);
+ if (first_result_block != 0)
+ {
+ Query_cache_block * result_block = first_result_block;
+ do
+ {
+ result_block->result()->parent(new_block);
+ result_block = result_block->next;
+ } while ( result_block != first_result_block );
+ }
+ NET * net = new_block->query()->writer();
+ if (net != 0)
+ {
+ net->query_cache_query = (gptr) new_block;
+ }
+ hash_insert(&queries, (const byte *)new_block);
+ DBUG_PRINT("info", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) border));
+ break;
+ }
+ case Query_cache_block::RES_INCOMPLETE:
+ case Query_cache_block::RES_BEG:
+ case Query_cache_block::RES_CONT:
+ case Query_cache_block::RESULT:
+ {
+ DBUG_PRINT("info", ("block 0x%lx RES* (%d)", (ulong) i, (int)i->type));
+ if (border == 0) break;
+ Query_cache_block
+ *query_block = i->result()->parent(),
+ *next = i->next,
+ *prev = i->prev;
+ Query_cache_block::block_type type = i->type;
+ BLOCK_LOCK_WR(query_block);
+ ulong len = i->length,
+ used = i->used;
+ Query_cache_block
+ *pprev = i->pprev,
+ *pnext = i->pnext,
+ *new_block =(Query_cache_block *) border;
+ char * data = (char*)i->data();
+ i->destroy();
+ new_block->init(len);
+ new_block->type=type;
+ new_block->used=used;
+ memcpy((char*)new_block->data(), data,
+ len - new_block->headers_len());
+ relink(i, new_block, next, prev, pnext, pprev);
+ new_block->result()->parent(query_block);
+ Query_cache_query * query = query_block->query();
+ if (query->result() == i)
+ query->result(new_block);
+ border += len;
+ before = new_block;
+ /* if result writing complete && we have free space in block */
+ ulong free_space = new_block->length - new_block->used;
+ if (query->result()->type == Query_cache_block::RESULT &&
+ new_block->length > new_block->used &&
+ gap + free_space > min_allocation_unit &&
+ new_block->length - free_space > min_allocation_unit)
+ {
+ border -= free_space;
+ gap += free_space;
+ new_block->length -= free_space;
+ }
+ BLOCK_UNLOCK_WR(query_block);
+ DBUG_PRINT("info", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) border));
+ break;
+ }
+ default:
+ DBUG_PRINT("error", ("unexpectet block type %d, block 0x%lx",
+ (int)i->type, (ulong) i));
+ ok = 0;
+ }
+ DBUG_RETURN(ok);
+}
+
+void Query_cache::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)
+{
+ nblock->prev = (prev==oblock?nblock:prev); //check pointer to himself
+ nblock->next = (next==oblock?nblock:next);
+ prev->next=nblock;
+ next->prev=nblock;
+ nblock->pprev = pprev; //physical pointer to himself have only 1 free block
+ nblock->pnext = pnext;
+ pprev->pnext=nblock;
+ pnext->pprev=nblock;
+}
+
+my_bool Query_cache::join_results(ulong join_limit)
+{
+ //TODO
+ DBUG_ENTER("Query_cache::join_results");
+ my_bool has_moving = 0;
+ Query_cache_block *query_block = 0;
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *i = queries_blocks;
+ do
+ {
+ Query_cache_query * header = i->query();
+ if (header->result() != 0 &&
+ header->result()->type == Query_cache_block::RESULT &&
+ header->length() > join_limit)
+ {
+ Query_cache_block *new_result_block =
+ get_free_block(header->length() +
+ ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)), 1, 0);
+ if (new_result_block != 0)
+ {
+ has_moving = 1;
+ Query_cache_block *first_result = header->result();
+ ulong new_len = header->length() +
+ ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result));
+ if (new_result_block->length >
+ ALIGN_SIZE(new_len) + min_allocation_unit)
+ split_block(new_result_block,ALIGN_SIZE(new_len));
+ BLOCK_LOCK_WR(i);
+ header->result(new_result_block);
+ new_result_block->type = Query_cache_block::RESULT;
+ new_result_block->n_tables = 0;
+ new_result_block->used = new_len;
+
+ new_result_block->next = new_result_block->prev = new_result_block;
+ DBUG_PRINT("info", ("new block %lu/%lu (%lu)",
+ new_result_block->length,
+ new_result_block->used,
+ header->length()));
+
+ Query_cache_result *new_result = new_result_block->result();
+ new_result->parent(i);
+ byte *write_to = (byte*) new_result->data();
+ Query_cache_block *result_block = first_result;
+ do
+ {
+ ulong len = result_block->used - result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result));
+ DBUG_PRINT("loop", ("add block %lu/%lu (%lu)",
+ result_block->length,
+ result_block->used,
+ len));
+ memcpy((char *) write_to,
+ (char*) result_block->result()->data(),
+ len);
+ write_to += len;
+ Query_cache_block * old_result_block = result_block;
+ result_block = result_block->next;
+ free_memory_block(old_result_block);
+ } while (result_block != first_result);
+ BLOCK_UNLOCK_WR(i);
+ }
+ }
+ i = i->next;
+ } while ( i != queries_blocks );
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(has_moving);
+}
+
+uint Query_cache::filename_2_table_key (char * key, char *filename)
+{
+ DBUG_ENTER("Query_cache::filename_2_table_key");
+ char tablename[FN_REFLEN];
+ char dbbuff[FN_REFLEN];
+ char *dbname;
+ Query_cache_block *table_block;
+ fn_format(tablename,filename,"","",3);
+
+ int path_len = (strrchr(filename, '/') - filename);
+ strncpy(dbbuff, filename, path_len);
+ dbbuff[path_len] = '\0';
+ dbname = strrchr(dbbuff, '/') + 1;
+
+ DBUG_PRINT("info", ("table %s.%s", dbname, tablename));
+
+ DBUG_RETURN( (uint) (strmov(strmov(key, dbname) + 1,
+ tablename) -key) + 1);
}
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
new file mode 100644
index 00000000000..0b786fb1560
--- /dev/null
+++ b/sql/sql_cache.h
@@ -0,0 +1,402 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SQL_CACHE_H
+#define _SQL_CACHE_H
+
+#include <semaphore.h>
+
+/* Query cache */
+
+/*
+ Can't create new free memory block if unused memory in block less
+ then QUERY_CACHE_MIN_ALLOCATION_UNIT.
+ if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then
+ QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly
+*/
+#define QUERY_CACHE_MIN_ALLOCATION_UNIT 0
+
+/* inittial size of hashes */
+#define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024
+#define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024
+
+/* minimal result data size when data allocated */
+#define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024
+
+/* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */
+#define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4
+#define QUERY_CACHE_MEM_BIN_STEP_PWR2 2
+#define QUERY_CACHE_MEM_BIN_PARTS_INC 1
+#define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2
+#define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3
+
+/* query flags masks */
+#define QUERY_CACHE_CLIENT_LONG_FLAG_MASK 0x80
+#define QUERY_CACHE_CHARSET_CONVERT_MASK 0x7F
+
+/* packing parameters */
+#define QUERY_CACHE_PACK_ITERATION 2
+#define QUERY_CACHE_PACK_LIMIT (512*1024L)
+
+#define TABLE_COUNTER_TYPE uint8
+
+struct Query_cache_block;
+struct Query_cache_block_table;
+struct Query_cache_table;
+struct Query_cache_query;
+struct Query_cache_result;
+class Query_cache;
+
+
+struct Query_cache_block_table
+{
+ TABLE_COUNTER_TYPE n; // numbr in table (from 0)
+ Query_cache_block_table *next, *prev;
+ Query_cache_table *parent;
+ inline Query_cache_block * block();
+};
+
+
+struct Query_cache_block
+{
+ enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG,
+ RES_INCOMPLETE, TABLE, INCOMPLETE};
+
+ ulong length; // length of all block
+ ulong used; // length of data
+ /*
+ Not used **pprev, **prev because really needed access to pervious block:
+ *pprev to join free blocks
+ *prev to access to opposite side of list in cyclic sorted list
+ */
+ Query_cache_block
+ *pnext,*pprev, // physical next/previous block
+ *next,*prev; // logical next/previous block
+ block_type type;
+ TABLE_COUNTER_TYPE n_tables; // number of tables in query
+
+ inline my_bool is_free(void) { return type == FREE; }
+
+ void init(ulong length);
+ void destroy();
+ inline uint headers_len();
+ inline gptr data(void);
+ inline Query_cache_query * query();
+ inline Query_cache_table * table();
+ inline Query_cache_result * result();
+ inline Query_cache_block_table * table(TABLE_COUNTER_TYPE n);
+};
+
+
+struct Query_cache_query
+{
+ ulonglong limit_found_rows;
+ Query_cache_block * res;
+ NET * wri;
+ ulong len;
+ sem_t lock; // R/W lock of block
+ pthread_mutex_t clients_guard;
+ uint clients;
+
+ inline void init_n_lock();
+ void unlock_n_destroy();
+ inline ulonglong found_rows() { return limit_found_rows; }
+ inline void found_rows(ulonglong rows) { limit_found_rows = rows; }
+ inline Query_cache_block * result() { return res; }
+ inline void result(Query_cache_block *p) { res=p; }
+ inline NET * writer() { return wri; }
+ inline void writer(NET *p) { wri=p; }
+ inline ulong length() { return len; }
+ inline ulong add(ulong packet_len) { return(len += packet_len); }
+ inline void length(ulong length) { len = length; }
+ inline gptr query()
+ {
+ return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+ }
+ void lock_writing();
+ void lock_reading();
+ my_bool try_lock_writing();
+ void unlock_writing();
+ void unlock_reading();
+ static byte * cache_key(const byte *record, uint *length,
+ my_bool not_used);
+ static void free_cache(void *entry);
+};
+
+
+struct Query_cache_table
+{
+ enum query_cache_table_type {OTHER=0, INNODB=1, TYPES_NUMBER=2};
+ inline static query_cache_table_type type_convertion(db_type type)
+ {
+ return (type == DB_TYPE_INNODB ? INNODB : OTHER);
+ }
+
+ char * tbl;
+ query_cache_table_type tp;
+
+ inline query_cache_table_type type() { return tp; }
+ inline void type(query_cache_table_type t) { tp = t;}
+ inline char * db() { return (char *) data(); }
+ inline char * table() { return tbl; }
+ inline void table(char * table) { tbl = table; }
+ inline gptr data()
+ {
+ return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+ }
+
+ static byte * cache_key(const byte *record, uint *length,
+ my_bool not_used);
+ static void free_cache(void *entry);
+};
+
+
+struct Query_cache_result
+{
+ Query_cache_block *query;
+
+ inline gptr data(){return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_result)));}
+
+ /* data_continue (if not whole packet contained by this block) */
+ inline Query_cache_block * parent() { return query; }
+ inline void parent (Query_cache_block *p) { query=p; }
+};
+
+
+extern "C" {
+ void query_cache_insert(THD *thd, const char *packet, ulong length);
+ void query_cache_end_of_result(THD *thd);
+ void query_cache_abort(THD *thd);
+ void query_cache_invalidate_by_MyISAM_filename(char* filename);
+}
+
+struct Query_cache_memory_bin
+{
+#ifndef DBUG_OFF
+ ulong size;
+#endif
+ uint number;
+ Query_cache_block * free_blocks;
+
+ inline void init(ulong size)
+ {
+#ifndef DBUG_OFF
+ this->size = size;
+#endif
+ number = 0;
+ free_blocks = 0;
+ }
+};
+
+struct Query_cache_memory_bin_step
+{
+ ulong size;
+ ulong increment;
+ uint idx;
+ inline void init(ulong size, uint idx, ulong increment)
+ {
+ this->size = size;
+ this->idx = idx;
+ this->increment = increment;
+ }
+};
+
+class Query_cache
+{
+ protected:
+ byte * cache; // cache memory
+ Query_cache_block *first_block; // physical location block list
+ Query_cache_block *queries_blocks; // query list (LIFO)
+ Query_cache_block *tables_blocks[Query_cache_table::TYPES_NUMBER];
+
+ Query_cache_memory_bin * bins; // free block lists
+ Query_cache_memory_bin_step * steps; // bins spacing info
+ uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin
+
+ /* options */
+ ulong query_cache_size, query_cache_limit,
+ min_allocation_unit, min_result_data_size;
+ uint def_query_hash_size, def_table_hash_size;
+
+ /* statistics */
+public:
+ ulong free_memory, queries_in_cache, hits, inserts, refused;
+protected:
+ my_bool initialized;
+
+ /*
+ Locked when searched or changed global query or
+ tables lists or hashes. When operate inside
+ query structure locked own query block mutex
+ LOCK SEQUENCE (to prevent clinch):
+ 1. structure_guard_mutex
+ 2. query block / table block / free block
+ 3. results blocks (only when must become free).
+ */
+ pthread_mutex_t structure_guard_mutex;
+
+ HASH queries, tables;
+
+ /* Exclude/include from cyclic double linked list */
+ static void double_linked_list_exclude(Query_cache_block * point,
+ Query_cache_block * &list_pointer);
+ static void double_linked_list_simple_include(Query_cache_block * point,
+ Query_cache_block *
+ &list_pointer);
+ static void double_linked_list_join(Query_cache_block *head_tail,
+ Query_cache_block *tail_head);
+
+ /* Table key generation */
+ static uint filename_2_table_key (char * key, char *filename);
+
+ /* Following function work properly only when structure_guard_mutex locked */
+ void flush_cache();
+ my_bool free_old_query();
+ void free_query(Query_cache_block * point);
+ my_bool allocate_data_chain(Query_cache_block * &result_block,
+ ulong data_len,
+ Query_cache_block * query_block);
+ void invalidate_table(TABLE_LIST *table);
+ void invalidate_table(TABLE *table);
+ void invalidate_table_in_db(Query_cache_block *table_block,
+ char * db);
+ void invalidate_table(Query_cache_block *table_block);
+ my_bool register_all_tables(Query_cache_block * block,
+ TABLE_LIST * tables_used,
+ TABLE_COUNTER_TYPE tables);
+ my_bool insert_table(uint key_len, char * key,
+ Query_cache_block_table * node,
+ Query_cache_table::query_cache_table_type type);
+ void unlink_table(Query_cache_block_table * node);
+ Query_cache_block * get_free_block (ulong len, my_bool not_less,
+ ulong min);
+ void free_memory_block(Query_cache_block * point);
+ void split_block(Query_cache_block *block, ulong len);
+ Query_cache_block * join_free_blocks(Query_cache_block *first_block,
+ Query_cache_block * block_in_list);
+ my_bool append_next_free_block(Query_cache_block * block,
+ ulong add_size);
+ void exclude_from_free_memory_list(Query_cache_block * free_block);
+ void insert_into_free_memory_list(Query_cache_block * new_block);
+ my_bool move_by_type(byte * &border, Query_cache_block * &before,
+ ulong &gap, Query_cache_block * i);
+ uint find_bin(ulong size);
+ void move_to_query_list_end(Query_cache_block * block);
+ void insert_into_free_memory_sorted_list(Query_cache_block * new_block,
+ Query_cache_block * &list);
+ void pack_cache();
+ void 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);
+ my_bool join_results(ulong join_limit);
+
+ /*
+ Following function control structure_guard_mutex
+ by themself or don't need structure_guard_mutex
+ */
+ void init();
+ ulong init_cache();
+ void make_disabled();
+ void free_cache(my_bool destruction);
+ Query_cache_block * write_block_data(ulong data_len, gptr data,
+ ulong header_len,
+ Query_cache_block::block_type type,
+ TABLE_COUNTER_TYPE ntab = 0,
+ my_bool under_guard=0);
+ my_bool append_result_data(Query_cache_block * &result,
+ ulong data_len, gptr data,
+ Query_cache_block * parent,
+ Query_cache_block * first_data_block);
+ my_bool write_result_data(Query_cache_block * &result,
+ ulong data_len, gptr data,
+ Query_cache_block * parent,
+ Query_cache_block::block_type
+ type=Query_cache_block::RESULT);
+ Query_cache_block * allocate_block(ulong len, my_bool not_less,
+ ulong min,
+ my_bool under_guard=0);
+ /*
+ If query is cachable return numder tables in query
+ (query without tables not cached)
+ */
+ TABLE_COUNTER_TYPE is_cachable(THD *thd, uint query_len, char *query,
+ LEX *lex,
+ TABLE_LIST *tables_used);
+ public:
+
+ Query_cache(ulong query_cache_limit = ULONG_MAX,
+ ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT,
+ ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE,
+ uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE,
+ uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE
+ );
+
+ /* resize query cache (return real query size, 0 if disabled) */
+ ulong resize(ulong query_cache_size);
+ inline void result_size_limit(ulong limit){query_cache_limit=limit;}
+
+ /* register query in cache */
+ void store_query(THD *thd, TABLE_LIST *used_tables);
+
+ /*
+ Check if the query is in the cache and if this is true send the
+ data to client.
+ */
+ my_bool send_result_to_client(THD *thd, char *query, uint query_length);
+
+ /* Remove all queries that uses any of the listed following tables */
+ void invalidate(TABLE_LIST *tables_used);
+ void invalidate(TABLE *table);
+
+ /* Remove all queries that uses tables of pointed type*/
+ void invalidate(Query_cache_table::query_cache_table_type type);
+
+ /* Remove all queries that uses any of the tables in following database */
+ void invalidate(char * db);
+
+ /* Remove all queries that uses any of the listed following table */
+ void invalidate_by_MyISAM_filename(char * filename);
+
+ /* Remove all queries from cache */
+ void flush();
+
+ /* Join result in cache in 1 block (if result length > join_limit) */
+ void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT,
+ uint iteration_limit = QUERY_CACHE_PACK_ITERATION);
+
+ void destroy();
+
+#ifndef DBUG_OFF
+ void wreck(uint line, const char * message);
+ void bins_dump();
+ void cache_dump();
+ void queries_dump();
+ void tables_dump();
+#endif
+ friend void query_cache_insert(NET *net, const char *packet, ulong length);
+ friend void query_cache_end_of_result(NET *net);
+ friend void query_cache_abort(NET *net);
+};
+
+extern Query_cache query_cache;
+
+#endif
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d76461b6faf..0b596c01f9d 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -84,7 +84,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
host=user=priv_user=db=query=ip=0;
host_or_ip="unknown ip";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
- query_start_used=0;
+ query_start_used=safe_to_cache_query=0;
query_length=col_access=0;
query_error=0;
next_insert_id=last_insert_id=0;
@@ -122,6 +122,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
server_status=SERVER_STATUS_AUTOCOMMIT;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
options=thd_startup_options;
+ query_cache_type = (byte)query_cache_startup_type;
sql_mode=(uint) opt_sql_mode;
inactive_timeout=net_wait_timeout;
open_options=ha_open_options;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 698a90c1a28..e036da982f0 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -126,14 +126,16 @@ class CONVERT
void convert_array(const uchar *mapping,uchar *buff,uint length);
public:
const char *name;
- CONVERT(const char *name_par,uchar *from_par,uchar *to_par)
- :from_map(from_par),to_map(to_par),name(name_par) {}
+ uint numb;
+ CONVERT(const char *name_par,uchar *from_par,uchar *to_par, uint number)
+ :from_map(from_par),to_map(to_par),name(name_par),numb(number) {}
friend CONVERT *get_convert_set(const char *name_ptr);
inline void convert(char *a,uint length)
{
convert_array(from_map, (uchar*) a,length);
}
bool store(String *, const char *,uint);
+ inline uint number() { return numb; }
};
typedef struct st_copy_info {
@@ -292,7 +294,10 @@ public:
bool query_start_used,last_insert_id_used,insert_id_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
+ bool safe_to_cache_query;
bool volatile killed;
+ //type of query cache processing
+ byte query_cache_type;
LOG_INFO* current_linfo;
// if we do a purge of binary logs, log index info of the threads
// that are currently reading it needs to be adjusted. To do that
@@ -324,10 +329,10 @@ public:
{
pthread_mutex_lock(&active_vio_lock);
if(active_vio)
- {
- vio_close(active_vio);
- active_vio = 0;
- }
+ {
+ vio_close(active_vio);
+ active_vio = 0;
+ }
pthread_mutex_unlock(&active_vio_lock);
}
#endif
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 3158c8cbf7b..b7f078e7b2b 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -159,6 +159,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if ((deleted=mysql_rm_known_files(thd, dirp, db, path,0)) >= 0 && thd)
{
ha_drop_database(path);
+ query_cache.invalidate(db);
if (!silent)
{
if (!thd->query)
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 63e003178c2..bb04712aaee 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -183,6 +183,8 @@ cleanup:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (deleted)
+ query_cache.invalidate(table_list);
delete select;
if (error >= 0) // Fatal error
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
@@ -539,6 +541,7 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
close_temporary(table,0);
*fn_ext(path)=0; // Remove the .frm extension
ha_create_table(path, &create_info,1);
+ // We don't need to call invalidate() because this table is not in cache
if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
table_list->real_name, 1))))
(void) rm_temporary_table(table_type, path);
@@ -570,6 +573,7 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
bzero((char*) &create_info,sizeof(create_info));
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1) ? -1 : 0;
+ query_cache.invalidate(table_list);
if (!dont_send_ok)
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 70cc5f412a1..5c43cacd85b 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -310,6 +310,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
}
thd->proc_info="end";
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table_list);
table->time_stamp=save_time_stamp; // Restore auto timestamp ptr
table->next_number_field=0;
thd->count_cuted_fields=0;
@@ -1335,6 +1337,8 @@ void select_insert::send_error(uint errcode,const char *err)
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd);
ha_rollback(thd);
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table);
}
@@ -1346,6 +1350,8 @@ bool select_insert::send_eof()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
error=error2;
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table);
if (error)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 96185a174b5..ef06eaf9145 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1164,7 +1164,10 @@ mysql_execute_command(void)
}
if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ query_cache.store_query(thd, tables);
res=handle_select(thd, lex, result);
+ }
else
delete result;
break;
@@ -1420,6 +1423,7 @@ mysql_execute_command(void)
if (end_active_trans(thd))
res= -1;
else
+ {
res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
tables, lex->create_list,
@@ -1427,6 +1431,8 @@ mysql_execute_command(void)
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
lex->alter_keys_onoff, lex->simple_alter);
+ query_cache.invalidate(tables);
+ }
break;
}
#endif
@@ -1455,6 +1461,7 @@ mysql_execute_command(void)
goto error;
}
}
+ query_cache.invalidate(tables);
if (end_active_trans(thd))
res= -1;
else if (mysql_rename_tables(thd,tables))
@@ -1493,6 +1500,7 @@ mysql_execute_command(void)
check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
goto error; /* purecov: inspected */
res = mysql_repair_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
break;
}
case SQLCOM_CHECK:
@@ -1501,6 +1509,7 @@ mysql_execute_command(void)
check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
goto error; /* purecov: inspected */
res = mysql_check_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
break;
}
case SQLCOM_ANALYZE:
@@ -2152,13 +2161,17 @@ mysql_execute_command(void)
even if there is a problem with the OPTION_AUTO_COMMIT flag
(Which of course should never happen...)
*/
+ {
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
+ {
send_ok(&thd->net);
+ }
else
res= -1;
break;
+ }
case SQLCOM_ROLLBACK:
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
@@ -2451,12 +2464,21 @@ mysql_parse(THD *thd,char *inBuf,uint length)
mysql_init_query(thd);
thd->query_length = length;
- LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
- mysql_execute_command();
- thd->proc_info="freeing items";
- free_items(thd); /* Free strings used by items */
- lex_end(lex);
+ if (query_cache.send_result_to_client(thd, inBuf, length))
+ {
+ thd->safe_to_cache_query=1;
+ LEX *lex=lex_start(thd, (uchar*) inBuf, length);
+ if (!yyparse() && ! thd->fatal_error)
+ {
+ mysql_execute_command();
+ query_cache_end_of_result(&thd->net);
+ }
+ else
+ query_cache_abort(&thd->net);
+ thd->proc_info="freeing items";
+ free_items(thd); /* Free strings used by items */
+ lex_end(lex);
+ }
DBUG_VOID_RETURN;
}
@@ -2982,6 +3004,15 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (ha_flush_logs())
result=1;
}
+ if (options & REFRESH_QUERY_CACHE_FREE)
+ {
+ query_cache.pack();
+ options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
+ }
+ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
+ {
+ query_cache.flush();
+ }
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
if ((options & REFRESH_READ_LOCK) && thd)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 660702d4117..2673c746bbc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3159,6 +3159,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
(thd->options & OPTION_AUTO_IS_NULL) &&
thd->insert_id())
{
+ query_cache_abort(&thd->net);
COND *new_cond;
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 049fb1c182c..ae450680fbb 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -158,13 +158,17 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
wrong_tables.append(String(table->real_name));
}
}
- if (some_tables_deleted && !dont_log_query)
+ if (some_tables_deleted)
{
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
+ query_cache.invalidate(tables);
+ if (!dont_log_query)
{
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
+ mysql_update_log.write(thd, thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
}
}
@@ -1708,6 +1712,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
+ table_list->table=0; // Table is closed
+ query_cache.invalidate(table_list);
end_temporary:
sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted),
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 0422d9664b6..4cf5366a8ba 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -321,6 +321,8 @@ int mysql_update(THD *thd,
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (updated)
+ query_cache.invalidate(table_list);
delete select;
if (error >= 0)
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 01ba468175e..ab74ee74171 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -153,6 +153,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BOOLEAN_SYM
%token BOTH
%token BY
+%token CACHE_SYM
%token CASCADE
%token CHECKSUM_SYM
%token CHECK_SYM
@@ -167,6 +168,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token DEFAULT
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
+%token DEMAND_SYM
%token DESC
%token DESCRIBE
%token DIRECTORY_SYM
@@ -246,6 +248,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NO_SYM
%token NULL_SYM
%token NUM
+%token OFF
%token ON
%token OPEN_SYM
%token OPTION
@@ -262,6 +265,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token PRIVILEGES
%token PROCESS
%token PROCESSLIST_SYM
+%token QUERY_SYM
%token RAID_0_SYM
%token RAID_STRIPED_SYM
%token RAID_TYPE
@@ -285,6 +289,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SHUTDOWN
+%token SQL_CACHE_SYM
+%token SQL_NO_CACHE_SYM
%token SSL_SYM
%token STARTING
%token STATUS_SYM
@@ -452,6 +458,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_WARNINGS
%token SQL_AUTO_IS_NULL
%token SQL_SAFE_UPDATES
+%token SQL_QUERY_CACHE_TYPE_SYM
%token SQL_QUOTE_SHOW_CREATE
%token SQL_SLAVE_SKIP_COUNTER
@@ -1341,7 +1348,7 @@ table_to_table:
select:
- SELECT_SYM select_part2 {Select->braces=false;} union
+ SELECT_SYM select_part2 { Select->braces=false; } union
|
'(' SELECT_SYM select_part2 ')' {Select->braces=true;} union_opt
@@ -1379,14 +1386,16 @@ select_option:
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
| SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
| SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
+ | SQL_NO_CACHE_SYM { current_thd->safe_to_cache_query=0; }
+ | SQL_CACHE_SYM { Select->options |= OPTION_TO_QUERY_CACHE; }
| ALL {}
select_lock_type:
/* empty */
| FOR_SYM UPDATE_SYM
- { Lex->lock_option= TL_WRITE; }
+ { Lex->lock_option= TL_WRITE; current_thd->safe_to_cache_query=0; }
| IN_SYM SHARE_SYM MODE_SYM
- { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; }
+ { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; current_thd->safe_to_cache_query=0; }
select_item_list:
select_item_list ',' select_item
@@ -1554,9 +1563,18 @@ no_and_expr:
simple_expr:
simple_ident
| literal
- | '@' ident_or_text SET_VAR expr { $$= new Item_func_set_user_var($2,$4); }
- | '@' ident_or_text { $$= new Item_func_get_user_var($2); }
- | '@' '@' ident_or_text { if (!($$= get_system_var($3))) YYABORT; }
+ | '@' ident_or_text SET_VAR expr
+ { $$= new Item_func_set_user_var($2,$4);
+ current_thd->safe_to_cache_query=0;
+ }
+ | '@' ident_or_text
+ { $$= new Item_func_get_user_var($2);
+ current_thd->safe_to_cache_query=0;
+ }
+ | '@' '@' ident_or_text
+ { if (!($$= get_system_var($3))) YYABORT;
+ current_thd->safe_to_cache_query=0;
+ }
| sum_expr
| '-' expr %prec NEG { $$= new Item_func_neg($2); }
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
@@ -1594,22 +1612,32 @@ simple_expr:
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
| CURDATE optional_braces
- { $$= new Item_func_curdate(); }
+ { $$= new Item_func_curdate(); current_thd->safe_to_cache_query=0; }
| CURTIME optional_braces
- { $$= new Item_func_curtime(); }
+ { $$= new Item_func_curtime(); current_thd->safe_to_cache_query=0; }
| CURTIME '(' expr ')'
- { $$= new Item_func_curtime($3); }
+ {
+ $$= new Item_func_curtime($3);
+ current_thd->safe_to_cache_query=0;
+ }
| DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,0); }
| DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,1); }
| DATABASE '(' ')'
- { $$= new Item_func_database(); }
+ {
+ $$= new Item_func_database();
+ current_thd->safe_to_cache_query=0;
+ }
| ELT_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_elt($3, *$5); }
| MAKE_SET_SYM '(' expr ',' expr_list ')'
{ $$= new Item_func_make_set($3, *$5); }
- | ENCRYPT '(' expr ')' { $$= new Item_func_encrypt($3); }
+ | ENCRYPT '(' expr ')'
+ {
+ $$= new Item_func_encrypt($3);
+ current_thd->safe_to_cache_query=0;
+ }
| ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_encrypt($3,$5); }
| DECODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_decode($3,$5.str); }
@@ -1633,7 +1661,7 @@ simple_expr:
{ $$= new Item_func_from_unixtime($3); }
| FROM_UNIXTIME '(' expr ',' expr ')'
{
- $$= new Item_func_date_format(new Item_func_from_unixtime($3),$5,0);
+ $$= new Item_func_date_format (new Item_func_from_unixtime($3),$5,0);
}
| FIELD_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_field($3, *$5); }
@@ -1652,10 +1680,12 @@ simple_expr:
{
$$= new Item_int((char*) "last_insert_id()",
current_thd->insert_id(),21);
+ current_thd->safe_to_cache_query=0;
}
| LAST_INSERT_ID '(' expr ')'
{
$$= new Item_func_set_last_insert_id($3);
+ current_thd->safe_to_cache_query=0;
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
@@ -1672,14 +1702,19 @@ simple_expr:
| MONTH_SYM '(' expr ')'
{ $$= new Item_func_month($3); }
| NOW_SYM optional_braces
- { $$= new Item_func_now(); }
+ { $$= new Item_func_now(); current_thd->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
- { $$= new Item_func_now($3); }
- | PASSWORD '(' expr ')' { $$= new Item_func_password($3); }
+ { $$= new Item_func_now($3); current_thd->safe_to_cache_query=0;}
+ | PASSWORD '(' expr ')'
+ {
+ $$= new Item_func_password($3);
+ }
| POSITION_SYM '(' no_in_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
- | RAND '(' expr ')' { $$= new Item_func_rand($3); }
- | RAND '(' ')' { $$= new Item_func_rand(); }
+ | RAND '(' expr ')'
+ { $$= new Item_func_rand($3); current_thd->safe_to_cache_query=0;}
+ | RAND '(' ')'
+ { $$= new Item_func_rand(); current_thd->safe_to_cache_query=0;}
| REPLACE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_replace($3,$5,$7); }
| RIGHT '(' expr ',' expr ')'
@@ -1717,6 +1752,7 @@ simple_expr:
$$ = new Item_sum_udf_str($1, *$3);
else
$$ = new Item_sum_udf_str($1);
+ current_thd->safe_to_cache_query=0;
}
| UDA_FLOAT_SUM '(' udf_expr_list ')'
{
@@ -1724,6 +1760,7 @@ simple_expr:
$$ = new Item_sum_udf_float($1, *$3);
else
$$ = new Item_sum_udf_float($1);
+ current_thd->safe_to_cache_query=0;
}
| UDA_INT_SUM '(' udf_expr_list ')'
{
@@ -1738,6 +1775,7 @@ simple_expr:
$$ = new Item_func_udf_str($1, *$3);
else
$$ = new Item_func_udf_str($1);
+ current_thd->safe_to_cache_query=0;
}
| UDF_FLOAT_FUNC '(' udf_expr_list ')'
{
@@ -1745,6 +1783,7 @@ simple_expr:
$$ = new Item_func_udf_float($1, *$3);
else
$$ = new Item_func_udf_float($1);
+ current_thd->safe_to_cache_query=0;
}
| UDF_INT_FUNC '(' udf_expr_list ')'
{
@@ -1752,15 +1791,21 @@ simple_expr:
$$ = new Item_func_udf_int($1, *$3);
else
$$ = new Item_func_udf_int($1);
+ current_thd->safe_to_cache_query=0;
}
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
- { $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9); }
+ {
+ $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
+ }
| UNIX_TIMESTAMP '(' ')'
- { $$= new Item_func_unix_timestamp(); }
+ {
+ $$= new Item_func_unix_timestamp();
+ current_thd->safe_to_cache_query=0;
+ }
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); }
+ { $$= new Item_func_user(); current_thd->safe_to_cache_query=0; }
| WEEK_SYM '(' expr ')'
{ $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); }
| WEEK_SYM '(' expr ',' expr ')'
@@ -1772,7 +1817,10 @@ simple_expr:
| YEARWEEK '(' expr ',' expr ')'
{ $$= new Item_func_yearweek($3, $5); }
| BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
- { $$=new Item_func_benchmark($3,$5); }
+ {
+ $$=new Item_func_benchmark($3,$5);
+ current_thd->safe_to_cache_query=0;
+ }
| EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new Item_extract( $3, $5); }
@@ -2101,6 +2149,7 @@ procedure_clause:
lex->proc_list.next= (byte**) &lex->proc_list.first;
if (add_proc_to_list(new Item_field(NULL,NULL,$2.str)))
YYABORT;
+ current_thd->safe_to_cache_query=0;
}
'(' procedure_list ')'
@@ -2580,6 +2629,7 @@ flush_options:
flush_option:
table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list
| TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
+ | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; }
| HOSTS_SYM { Lex->type|= REFRESH_HOSTS; }
| PRIVILEGES { Lex->type|= REFRESH_GRANT; }
| LOGS_SYM { Lex->type|= REFRESH_LOG; }
@@ -2602,8 +2652,9 @@ reset_options:
| reset_option
reset_option:
- SLAVE { Lex->type|= REFRESH_SLAVE; }
- | MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ SLAVE { Lex->type|= REFRESH_SLAVE; }
+ | MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;}
purge:
PURGE
@@ -2851,6 +2902,7 @@ keyword:
| BIT_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
+ | CACHE_SYM {}
| CHANGED {}
| CHECKSUM_SYM {}
| CHECK_SYM {}
@@ -2867,6 +2919,7 @@ keyword:
| DAY_SYM {}
| DIRECTORY_SYM {}
| DELAY_KEY_WRITE_SYM {}
+ | DEMAND_SYM {}
| DISABLE_SYM {}
| DUMPFILE {}
| DYNAMIC_SYM {}
@@ -2922,12 +2975,14 @@ keyword:
| NEXT_SYM {}
| NEW_SYM {}
| NO_SYM {}
+ | OFF {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PASSWORD {}
| PREV_SYM {}
| PROCESS {}
| PROCESSLIST_SYM {}
+ | QUERY_SYM {}
| QUICK {}
| RAID_0_SYM {}
| RAID_CHUNKS {}
@@ -2949,6 +3004,9 @@ keyword:
| SHARE_SYM {}
| SHUTDOWN {}
| SLAVE {}
+ | SQL_CACHE_SYM {}
+ | SQL_NO_CACHE_SYM {}
+ | SQL_QUERY_CACHE_TYPE_SYM {}
| START_SYM {}
| STATUS_SYM {}
| STOP_SYM {}
@@ -3072,6 +3130,7 @@ option_value:
$3->user.str,$5))
YYABORT;
}
+ | SQL_QUERY_CACHE_TYPE_SYM equal query_cache_type
| '@' ident_or_text equal expr
{
Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
@@ -3112,6 +3171,13 @@ option_value:
item));
}
+query_cache_type:
+ '0' { current_thd->query_cache_type = 0; }
+ | OFF { current_thd->query_cache_type = 0; }
+ | '1' { current_thd->query_cache_type = 1; }
+ | ON { current_thd->query_cache_type = 1; }
+ | '2' { current_thd->query_cache_type = 2; }
+ | DEMAND_SYM { current_thd->query_cache_type = 2; }
text_or_password:
TEXT_STRING { $$=$1.str;}