diff options
-rw-r--r-- | Docs/manual.texi | 9 | ||||
-rw-r--r-- | Docs/section.Comparisons.texi | 7 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 4 | ||||
-rw-r--r-- | client/mysqltest.c | 132 | ||||
-rw-r--r-- | include/config-win.h | 1 | ||||
-rw-r--r-- | include/my_pthread.h | 9 | ||||
-rw-r--r-- | include/my_semaphore.h | 51 | ||||
-rw-r--r-- | include/my_sys.h | 8 | ||||
-rw-r--r-- | libmysql/libmysql.c | 2 | ||||
-rw-r--r-- | myisam/ft_boolean_search.c | 15 | ||||
-rw-r--r-- | myisam/ft_nlq_search.c | 7 | ||||
-rw-r--r-- | myisam/ft_update.c | 3 | ||||
-rw-r--r-- | mysql-test/r/query_cache.result | 264 | ||||
-rw-r--r-- | mysql-test/t/query_cache-master.opt | 2 | ||||
-rw-r--r-- | mysql-test/t/query_cache.test | 159 | ||||
-rw-r--r-- | mysys/Makefile.am | 3 | ||||
-rw-r--r-- | mysys/my_new.cc | 49 | ||||
-rw-r--r-- | mysys/my_winsem.c | 432 | ||||
-rw-r--r-- | sql/filesort.cc | 16 | ||||
-rw-r--r-- | sql/item_func.cc | 4 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/mysqld.cc | 10 | ||||
-rw-r--r-- | sql/slave.cc | 423 | ||||
-rw-r--r-- | sql/sql_cache.cc | 126 | ||||
-rw-r--r-- | sql/sql_cache.h | 7 | ||||
-rw-r--r-- | sql/sql_repl.cc | 10 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 |
27 files changed, 1366 insertions, 394 deletions
diff --git a/Docs/manual.texi b/Docs/manual.texi index 2de4680b307..ae2f1248458 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -18506,9 +18506,12 @@ If this is 0, the query cache is disabled (default). @item @code{query_cache_startup_type} This may be set (only numeric) to -0 (OFF, don't cache or retrieve results), -1 (ON, cache all results except @code{SELECT SQL_NO_CACHE ...} queries) or -2 (DEMAND, cache only @code{SELECT SQL_CACHE ...} queries). +@multitable @columnfractions .1 .2 .7 +@item @strong{Value} @tab @strong{Alias} @tab @strong{Comment} +@item 0 @tab OFF @tab Don't cache or retrieve results. +@item 1 @tab ON @tab Cache all results except @code{SELECT SQL_NO_CACHE ...} queries. +@item 2 @tab DEMAND @tab Cache only @code{SELECT SQL_CACHE ...} queries. +@end multitable @item @code{safe_show_databases} Don't show databases for which the user doesn't have any database or diff --git a/Docs/section.Comparisons.texi b/Docs/section.Comparisons.texi index 3d62d452b8d..a6dfa744aa0 100644 --- a/Docs/section.Comparisons.texi +++ b/Docs/section.Comparisons.texi @@ -34,6 +34,7 @@ see the @code{crash-me} web page at @node Compare mSQL, Compare PostgreSQL, Comparisons, Comparisons @subsection How MySQL Compares to @code{mSQL} +@cindex mSQL, MySQL vs mSQL, overview @table @strong @item Performance @@ -301,7 +302,7 @@ multiple connections to the server from the same process. @subsubsection How @code{mSQL} and MySQL Client/Server Communications Protocols Differ @cindex communications protocols -@cindex mSQL vs. MySQL +@cindex mSQL vs. MySQL, protocol There are enough differences that it is impossible (or at least not easy) to support both. @@ -557,7 +558,6 @@ satisfies your application. If you need raw speed, MySQL is probably your best choice. If you need some of the extra features that only PostgreSQL can offer, you should use @code{PostgreSQL}. -@cindex PostgreSQL/MySQL, strategies @menu * MySQL-PostgreSQL goals:: MySQL and PostgreSQL development strategies * MySQL-PostgreSQL features:: Featurewise Comparison of MySQL and PostgreSQL @@ -568,6 +568,7 @@ can offer, you should use @code{PostgreSQL}. @node MySQL-PostgreSQL goals, MySQL-PostgreSQL features, Compare PostgreSQL, Compare PostgreSQL @subsubsection MySQL and PostgreSQL development strategies +@cindex PostgreSQL vs. MySQL, strategies When adding things to MySQL we take pride to do an optimal, definite solution. The code should be so good that we shouldn't have any need to change it in the foreseeable future. We also do not like to sacrifice @@ -609,7 +610,7 @@ code, we are better able to coordinate new features and releases. @node MySQL-PostgreSQL features, MySQL-PostgreSQL benchmarks, MySQL-PostgreSQL goals, Compare PostgreSQL @subsubsection Featurewise Comparison of MySQL and PostgreSQL -@cindex PostgreSQL/MySQL, features +@cindex PostgreSQL vs. MySQL, features On the crash-me page (@uref{http://www.mysql.com/information/crash-me.php}) diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 4e30f847254..c7244e07e8c 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -385,9 +385,9 @@ static void dump_remote_log_entries(const char* logname) } } -static int check_header (IO_CACHE* file) +static int check_header(IO_CACHE* file) { - char buf[PROBE_HEADER_LEN]; + byte buf[PROBE_HEADER_LEN]; int old_format; my_off_t pos = my_b_tell(file); diff --git a/client/mysqltest.c b/client/mysqltest.c index 4498f56a5d3..d17d2730229 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -43,7 +43,7 @@ **********************************************************************/ -#define MTEST_VERSION "1.11" +#define MTEST_VERSION "1.12" #include <my_global.h> #include <mysql_embed.h> @@ -138,16 +138,16 @@ MYSQL_RES *last_result=0; PARSER parser; MASTER_POS master_pos; -int* block_ok; /* set to 0 if the current block should not be executed */ +int *block_ok; /* set to 0 if the current block should not be executed */ int false_block_depth = 0; -const char* result_file = 0; /* if set, all results are concated and - compared against this file*/ +/* if set, all results are concated and compared against this file */ +const char *result_file = 0; typedef struct { - char* name; + char *name; int name_len; - char* str_val; + char *str_val; int str_val_len; int int_val; int alloced_len; @@ -158,7 +158,7 @@ typedef struct VAR var_reg[10]; /*Perl/shell-like variable registers */ HASH var_hash; -int disable_query_log=0; +int disable_query_log=0, disable_result_log=0; struct connection cons[MAX_CONS]; struct connection* cur_con, *next_con, *cons_end; @@ -181,6 +181,7 @@ Q_PING, Q_EVAL, Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, +Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -215,6 +216,7 @@ const char *command_names[] = { "rpl_probe", "enable_rpl_parse", "disable_rpl_parse", "eval_result", "enable_query_log", "disable_query_log", + "enable_result_log", "disable_result_log", "server_start", "server_stop", "require_manager", 0 @@ -224,22 +226,22 @@ TYPELIB command_typelib= {array_elements(command_names),"", command_names}; DYNAMIC_STRING ds_res; -static void die(const char* fmt, ...); +static void die(const char *fmt, ...); static void init_var_hash(); static byte* get_var_key(const byte* rec, uint* len, my_bool __attribute__((unused)) t); -static VAR* var_init(VAR* v, const char* name, int name_len, const char* val, +static VAR* var_init(VAR* v, const char *name, int name_len, const char *val, int val_len); static void var_free(void* v); -int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname); -void reject_dump(const char* record_file, char* buf, int size); +int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); +void reject_dump(const char *record_file, char *buf, int size); int close_connection(struct st_query* q); -VAR* var_get(const char* var_name, const char** var_name_end, int raw); -int eval_expr(VAR* v, const char* p, const char** p_end); -static int read_server_arguments(const char* name); +VAR* var_get(const char *var_name, const char** var_name_end, int raw); +int eval_expr(VAR* v, const char *p, const char** p_end); +static int read_server_arguments(const char *name); /* Definitions for replace */ @@ -259,9 +261,9 @@ static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); void free_pointer_array(POINTER_ARRAY *pa); static int initialize_replace_buffer(void); static void free_replace_buffer(void); -static void do_eval(DYNAMIC_STRING* query_eval, const char* query); -void str_to_file(const char* fname, char* str, int size); -int do_server_op(struct st_query* q,const char* op); +static void do_eval(DYNAMIC_STRING* query_eval, const char *query); +void str_to_file(const char *fname, char *str, int size); +int do_server_op(struct st_query* q,const char *op); struct st_replace *glob_replace; static char *out_buff; @@ -1960,20 +1962,20 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) int query_len; DBUG_ENTER("run_query"); - if(q->type != Q_EVAL) - { - query = q->query; - query_len = strlen(query); - } + if (q->type != Q_EVAL) + { + query = q->query; + query_len = strlen(query); + } else - { - init_dynamic_string(&eval_query, "", 16384, 65536); - do_eval(&eval_query, q->query); - query = eval_query.str; - query_len = eval_query.length; - } + { + init_dynamic_string(&eval_query, "", 16384, 65536); + do_eval(&eval_query, q->query); + query = eval_query.str; + query_len = eval_query.length; + } - if ( q->record_file[0]) + if (q->record_file[0]) { init_dynamic_string(&ds_tmp, "", 16384, 65536); ds = &ds_tmp; @@ -2060,44 +2062,45 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) goto end; } - if (!res) goto end; - - fields = mysql_fetch_fields(res); - num_fields = mysql_num_fields(res); - for( i = 0; i < num_fields; i++) - { - if (i) - dynstr_append_mem(ds, "\t", 1); - dynstr_append(ds, fields[i].name); - } - - dynstr_append_mem(ds, "\n", 1); - + if (!res) + goto end; - while((row = mysql_fetch_row(res))) + if (!disable_result_log) { - lengths = mysql_fetch_lengths(res); - for(i = 0; i < num_fields; i++) + fields = mysql_fetch_fields(res); + num_fields = mysql_num_fields(res); + for (i = 0; i < num_fields; i++) { - val = (char*)row[i]; - len = lengths[i]; - - if (!val) - { - val = (char*)"NULL"; - len = 4; - } - if (i) dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); + dynstr_append(ds, fields[i].name); } dynstr_append_mem(ds, "\n", 1); - } - if (glob_replace) - free_replace(); + while ((row = mysql_fetch_row(res))) + { + lengths = mysql_fetch_lengths(res); + for(i = 0; i < num_fields; i++) + { + val = (char*)row[i]; + len = lengths[i]; + + if (!val) + { + val = (char*)"NULL"; + len = 4; + } + + if (i) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, len); + } + dynstr_append_mem(ds, "\n", 1); + } + if (glob_replace) + free_replace(); + } if (record) { if (!q->record_file[0] && !result_file) @@ -2111,7 +2114,8 @@ int run_query(MYSQL* mysql, struct st_query* q, int flags) } end: - if (res) mysql_free_result(res); + if (res) + mysql_free_result(res); last_result=0; if (ds == &ds_tmp) dynstr_free(&ds_tmp); @@ -2288,10 +2292,12 @@ int main(int argc, char** argv) case Q_DIRTY_CLOSE: close_connection(q); break; case Q_RPL_PROBE: do_rpl_probe(q); break; - case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; - case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; - case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; - case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; + case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; + case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; + case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; + case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; + case Q_ENABLE_RESULT_LOG: disable_result_log=0; break; + case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; case Q_SOURCE: do_source(q); break; case Q_SLEEP: do_sleep(q); break; case Q_REQUIRE_MANAGER: do_require_manager(q); break; diff --git a/include/config-win.h b/include/config-win.h index 28d1652ca0c..ea7b290a12a 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -253,6 +253,7 @@ inline double ulonglong2double(ulonglong value) #define HAVE_STRPBRK #define HAVE_STRSTR #define HAVE_COMPRESS +#define HAVE_CREATESEMAPHORE #ifdef NOT_USED #define HAVE_SNPRINTF /* Gave link error */ diff --git a/include/my_pthread.h b/include/my_pthread.h index 1fb36afb6d4..df42ebeadd0 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -132,16 +132,17 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #define pthread_equal(A,B) ((A) == (B)) #ifdef OS2 -int pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); -int pthread_mutex_lock (pthread_mutex_t *); -int pthread_mutex_unlock (pthread_mutex_t *); -int pthread_mutex_destroy (pthread_mutex_t *); +extern int pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); +extern int pthread_mutex_lock (pthread_mutex_t *); +extern int pthread_mutex_unlock (pthread_mutex_t *); +extern int pthread_mutex_destroy (pthread_mutex_t *); #define my_pthread_setprio(A,B) DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE, B, A) #define pthread_kill(A,B) raise(B) #define pthread_exit(A) pthread_dummy() #else #define pthread_mutex_init(A,B) InitializeCriticalSection(A) #define pthread_mutex_lock(A) (EnterCriticalSection(A),0) +#define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) #define pthread_mutex_unlock(A) LeaveCriticalSection(A) #define pthread_mutex_destroy(A) DeleteCriticalSection(A) #define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B)) diff --git a/include/my_semaphore.h b/include/my_semaphore.h new file mode 100644 index 00000000000..484423150f7 --- /dev/null +++ b/include/my_semaphore.h @@ -0,0 +1,51 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA + */ + +/* This is hacked by Monty to be included in mysys library */ + +#ifndef _my_semaphore_h_ +#define _my_semaphore_h_ + +#ifndef __WIN__ +#include <semaphore.h> +#else + +C_MODE_START + +typedef HANDLE sem_t; +int sem_init (sem_t * sem, int pshared, unsigned int value); +int sem_destroy (sem_t * sem); +int sem_trywait (sem_t * sem); +int sem_wait (sem_t * sem); +int sem_post (sem_t * sem); +int sem_post_multiple (sem_t * sem,int count); +int sem_getvalue (sem_t * sem, int * sval); + +C_MODE_END +#endif /* __WIN__ */ +#endif /* !_my_semaphore_h_ */ diff --git a/include/my_sys.h b/include/my_sys.h index 5534306a881..5e2afcc78f6 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -16,9 +16,7 @@ #ifndef _my_sys_h #define _my_sys_h -#ifdef __cplusplus -extern "C" { -#endif +C_MODE_START #ifdef HAVE_AIOWAIT #include <sys/asynch.h> /* Used by record-cache */ @@ -649,8 +647,6 @@ extern void sleep(int sec); extern my_bool have_tcpip; /* Is set if tcpip is used */ #endif -#ifdef __cplusplus -} -#endif +C_MODE_END #include "raid.h" #endif /* _my_sys_h */ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 11fca745c5f..a48fb400aa6 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2397,6 +2397,8 @@ mysql_fetch_row(MYSQL_RES *res) DBUG_PRINT("info",("end of data")); res->eof=1; res->handle->status=MYSQL_STATUS_READY; + /* Don't clear handle in mysql_free_results */ + res->handle=0; } } DBUG_RETURN((MYSQL_ROW) NULL); diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index ea9a8ab15e0..c41c699bf5b 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -112,11 +112,13 @@ void _ftb_parse_query(FTB *ftb, byte **start, byte *end, while ((res=ft_get_word(start,end,&w,¶m))) { byte r=param.plusminus; - float weight=(param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)]; + float weight= (float) (param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)]; switch (res) { case 1: /* word found */ ftbw=(FTB_WORD *)alloc_root(&ftb->mem_root, - sizeof(FTB_WORD) + (param.trunc ? MI_MAX_KEY_BUFF : w.len+extra)); + sizeof(FTB_WORD) + + (param.trunc ? MI_MAX_KEY_BUFF : + w.len+extra)); ftbw->len=w.len+1; ftbw->yesno=param.yesno; ftbw->trunc=param.trunc; /* 0 or 1 */ @@ -216,7 +218,8 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftb->queue.root=(byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*)); reinit_queue(& ftb->queue, res, 0, 0, FTB_WORD_cmp, ftb); ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR)); - ftbe->weight=ftbe->yesno=ftbe->nos=1; + ftbe->weight=1; + ftbe->yesno=ftbe->nos=1; ftbe->up=0; ftbe->ythresh=0; ftbe->docid=HA_POS_ERROR; @@ -236,7 +239,8 @@ void _ftb_climb_the_tree(FTB_WORD *ftbw, my_off_t curdoc) { if (ftbe->docid != curdoc) { - ftbe->cur_weight=ftbe->yesses=ftbe->nos=0; + ftbe->cur_weight=0; + ftbe->yesses=ftbe->nos=0; ftbe->docid=curdoc; } if (ftbe->nos) @@ -373,7 +377,8 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) { if (ftbe->docid != HA_POS_ERROR) { - ftbe->cur_weight=ftbe->yesses=ftbe->nos=0; + ftbe->cur_weight=0; + ftbe->yesses=ftbe->nos=0; ftbe->docid=HA_POS_ERROR; } else diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 5bb2ffab939..ac9fa5a9a8c 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -248,7 +248,8 @@ int ft_nlq_read_next(FT_INFO *handler, char *record) } float ft_nlq_find_relevance(FT_INFO *handler, - byte *record __attribute__((unused)), uint length __attribute__((unused))) + byte *record __attribute__((unused)), + uint length __attribute__((unused))) { int a,b,c; FT_DOC *docs=handler->doc; @@ -267,7 +268,7 @@ float ft_nlq_find_relevance(FT_INFO *handler, a=c; } if (docs[a].dpos == docid) - return docs[a].weight; + return (float) docs[a].weight; else return 0.0; } @@ -279,7 +280,7 @@ void ft_nlq_close_search(FT_INFO *handler) float ft_nlq_get_relevance(FT_INFO *handler) { - return handler->doc[handler->curdoc].weight; + return (float) handler->doc[handler->curdoc].weight; } void ft_nlq_reinit_search(FT_INFO *handler) diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 3d394eeacac..e83f0a21491 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -19,6 +19,7 @@ /* functions to work with full-text indices */ #include "ftdefs.h" +#include <math.h> /************************************************************** This is to make ft-code to ignore keyseg.length at all * @@ -186,7 +187,7 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, cmp=_mi_compare_text(default_charset_info, (uchar*) old_word->pos,old_word->len, (uchar*) new_word->pos,new_word->len,0); - cmp2= cmp ? 0 : (abs(old_word->weight - new_word->weight) > 1.e-5); + cmp2= cmp ? 0 : (fabs(old_word->weight - new_word->weight) > 1.e-5); if (cmp < 0 || cmp2) { diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index ac6962bfd9d..f16c72d148a 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1,6 +1,6 @@ reset query cache; flush status; -drop table if exists t1; +drop table if exists t1,t2,t3; create table t1 (a int not null); insert into t1 values (1),(2),(3); select * from t1; @@ -36,3 +36,265 @@ drop table t1; show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a int not null); +insert into t2 values (4),(5),(6); +create table t3 (a int not null) type=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST; +select * from t3; +a +1 +2 +3 +4 +5 +6 +select * from t3; +a +1 +2 +3 +4 +5 +6 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +insert into t2 values (7); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1; +a +1 +2 +3 +select * from t1; +a +1 +2 +3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +insert into t3 values (8); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t3; +a +1 +2 +3 +8 +4 +5 +6 +7 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +update t2 set a=9 where a=7; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1; +a +1 +2 +3 +8 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +update t3 set a=10 where a=1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t3; +a +10 +2 +3 +8 +4 +5 +6 +9 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +delete from t2 where a=9; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1; +a +10 +2 +3 +8 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +delete from t3 where a=10; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +drop table t1, t2, t3; +set autocommit=0; +create table t1 (a int not null) type=innodb; +insert into t1 values (1),(2),(3); +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +drop table t1; +commit; +set autocommit=1; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a int not null); +insert into t2 values (1),(2),(3); +select * from t1; +a +1 +2 +3 +select * from t2; +a +1 +2 +3 +insert into t1 values (4); +show status like "Qcache_free_blocks"; +Variable_name Value +Qcache_free_blocks 2 +flush query cache; +show status like "Qcache_free_blocks"; +Variable_name Value +Qcache_free_blocks 1 +drop table t1, t2; +set sql_query_cache_type=demand; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +select * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select sql_cache * from t1; +a +1 +2 +3 +set sql_query_cache_type=2; +select sql_cache * from t1; +a +1 +2 +3 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +set sql_query_cache_type=on; +reset query cache; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select sql_no_cache * from t1; +a +1 +2 +3 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +drop table t1; +create table t1 (a text not null); +select CONNECTION_ID() from t1; +CONNECTION_ID() +select FOUND_ROWS(); +FOUND_ROWS() +0 +select NOW() from t1; +NOW() +select CURDATE() from t1; +CURDATE() +select CURTIME() from t1; +CURTIME() +select DATABASE() from t1; +DATABASE() +select ENCRYPT("test") from t1; +ENCRYPT("test") +select LAST_INSERT_ID() from t1; +last_insert_id() +select RAND() from t1; +RAND() +select UNIX_TIMESTAMP() from t1; +UNIX_TIMESTAMP() +select USER() from t1; +USER() +select benchmark(1,1) from t1; +benchmark(1,1) +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +create table t2 (a text not null); +insert into t1 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +drop table t2; +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +select a as a1, a as a2 from t1; +select a as a2, a as a3 from t1; +select a as a3, a as a4 from t1; +select a as a1, a as a2 from t1; +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 4 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +reset query cache; +show variables like "query_cache_size"; +Variable_name Value +query_cache_size 1039700 +show status like "Qcache_free_memory"; +Variable_name Value +Qcache_free_memory 1039700 +drop table t1; diff --git a/mysql-test/t/query_cache-master.opt b/mysql-test/t/query_cache-master.opt index 7ff962c2216..5f0ebff98f6 100644 --- a/mysql-test/t/query_cache-master.opt +++ b/mysql-test/t/query_cache-master.opt @@ -1 +1 @@ ---set-variable=query_cache_size=2M +--set-variable=query_cache_size=1M diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 3d1aa70d8b2..e9e138c9b61 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1,3 +1,5 @@ +-- source include/have_innodb.inc + # # Tests with query cache # @@ -6,7 +8,12 @@ reset query cache; flush status; -drop table if exists t1; +drop table if exists t1,t2,t3; + +# +# First simple test +# + create table t1 (a int not null); insert into t1 values (1),(2),(3); select * from t1; @@ -24,3 +31,153 @@ show status like "Qcache_hits"; drop table t1; show status like "Qcache_queries_in_cache"; + +# +# MERGE TABLES with INSERT/UPDATE and DELETE +# +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a int not null); +insert into t2 values (4),(5),(6); +create table t3 (a int not null) type=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST; +# insert +select * from t3; +select * from t3; +show status like "Qcache_hits"; +show status like "Qcache_queries_in_cache"; +insert into t2 values (7); +show status like "Qcache_queries_in_cache"; +select * from t1; +select * from t1; +show status like "Qcache_hits"; +show status like "Qcache_queries_in_cache"; +insert into t3 values (8); +show status like "Qcache_queries_in_cache"; +# update +select * from t3; +show status like "Qcache_queries_in_cache"; +update t2 set a=9 where a=7; +show status like "Qcache_queries_in_cache"; +select * from t1; +show status like "Qcache_queries_in_cache"; +update t3 set a=10 where a=1; +show status like "Qcache_queries_in_cache"; +#delete +select * from t3; +show status like "Qcache_queries_in_cache"; +delete from t2 where a=9; +show status like "Qcache_queries_in_cache"; +select * from t1; +show status like "Qcache_queries_in_cache"; +delete from t3 where a=10; +show status like "Qcache_queries_in_cache"; +drop table t1, t2, t3; +# +# Without auto_commit. +# +set autocommit=0; +create table t1 (a int not null) type=innodb; +insert into t1 values (1),(2),(3); +select * from t1; +show status like "Qcache_queries_in_cache"; +drop table t1; +commit; +set autocommit=1; +# +# FLUSH QUERY CACHE +# +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a int not null); +insert into t2 values (1),(2),(3); +select * from t1; +select * from t2; +insert into t1 values (4); +show status like "Qcache_free_blocks"; +flush query cache; +show status like "Qcache_free_blocks"; +drop table t1, t2; +# +# SELECT SQL_CACHE ... +# +set sql_query_cache_type=demand; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +select * from t1; +show status like "Qcache_queries_in_cache"; +select sql_cache * from t1; +set sql_query_cache_type=2; +select sql_cache * from t1; +show status like "Qcache_hits"; +show status like "Qcache_queries_in_cache"; +set sql_query_cache_type=on; +# +# RESET QUERY CACHE +# +reset query cache; +show status like "Qcache_queries_in_cache"; +# +# SELECT SQL_NO_CACHE +# +select sql_no_cache * from t1; +show status like "Qcache_queries_in_cache"; +drop table t1; +# +# Check that queries that uses NOW(), LAST_INSERT_ID()... are not cached. +# +create table t1 (a text not null); +select CONNECTION_ID() from t1; +#GET_LOCK +#RELEASE_LOCK +#LOAD_FILE +select FOUND_ROWS(); +select NOW() from t1; +select CURDATE() from t1; +select CURTIME() from t1; +select DATABASE() from t1; +select ENCRYPT("test") from t1; +select LAST_INSERT_ID() from t1; +select RAND() from t1; +select UNIX_TIMESTAMP() from t1; +select USER() from t1; +select benchmark(1,1) from t1; +show status like "Qcache_queries_in_cache"; +# +# Tests when the cache is filled +# +create table t2 (a text not null); +insert into t1 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t1; +insert into t1 select * from t2; # 2 +insert into t2 select * from t1; # 3 +insert into t1 select * from t2; # 5 +insert into t2 select * from t1; # 8 +insert into t1 select * from t2; # 13 +insert into t2 select * from t1; # 21 +insert into t1 select * from t2; # 34 +insert into t2 select * from t1; # 55 +insert into t1 select * from t2; # 89 +insert into t2 select * from t1; # 144 +insert into t1 select * from t2; # 233 +insert into t2 select * from t1; # 357 +insert into t1 select * from t2; # 610 +insert into t2 select * from t1; # 987 +insert into t1 select * from t2; # 1597 +insert into t2 select * from t1; # 2584 +insert into t1 select * from t2; # 4181 +drop table t2; + +show status like "Qcache_hits"; +disable_result_log; +select a as a1, a as a2 from t1; +select a as a2, a as a3 from t1; +select a as a3, a as a4 from t1; +# next query must be out of 1Mb cache +select a as a1, a as a2 from t1; +enable_result_log; +show status like "Qcache_hits"; +show status like "Qcache_queries_in_cache"; +reset query cache; +show variables like "query_cache_size"; +show status like "Qcache_free_memory"; +drop table t1; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index d28ef1364c6..97f065bc7e2 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -30,7 +30,8 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \ my_lock.c mf_brkhant.c my_alarm.c \ my_malloc.c my_realloc.c my_once.c mulalloc.c \ - my_alloc.c safemalloc.c my_fopen.c my_fstream.c \ + my_alloc.c safemalloc.c my_new.cc \ + my_fopen.c my_fstream.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ diff --git a/mysys/my_new.cc b/mysys/my_new.cc new file mode 100644 index 00000000000..5cc291af9aa --- /dev/null +++ b/mysys/my_new.cc @@ -0,0 +1,49 @@ +/* Copyright (C) 2000 MySQL 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 */ + +/* + This is a replacement of new/delete operators to be used when compiling + with gcc 3.0.x to avoid including libstdc++ +*/ + +#include "mysys_priv.h" + +#ifdef USE_MYSYS_NEW + +void *operator new (size_t sz) +{ + return (void *) malloc (sz ? sz+1 : sz); +} + +void *operator new[] (size_t sz) +{ + return (void *) malloc (sz ? sz+1 : sz); +} + +void operator delete (void *ptr) +{ + if (ptr) + free(ptr); +} + +void operator delete[] (void *ptr) throw () +{ + if (ptr) + free(ptr); +} + +#endif /* USE_MYSYS_NEW */ + diff --git a/mysys/my_winsem.c b/mysys/my_winsem.c new file mode 100644 index 00000000000..d45b43a4473 --- /dev/null +++ b/mysys/my_winsem.c @@ -0,0 +1,432 @@ +/* + * ------------------------------------------------------------- + * + * Module: my_semaphore.c (Original: semaphore.c from pthreads library) + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright (C) 1998 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA + */ + +/* + NEED_SEM is not used in MySQL and should only be needed under + Windows CE. + + The big changes compared to the original version was to not allocate + any additional memory in sem_init() but to instead store everthing + we need in sem_t. + + TODO: + To get HAVE_CREATESEMAPHORE we have to define the struct + in my_semaphore.h +*/ + +#include "mysys_priv.h" +#ifdef __WIN__ +#include "my_semaphore.h" +#include <errno.h> + +/* + DOCPUBLIC + This function initializes an unnamed semaphore. the + initial value of the semaphore is 'value' + + PARAMETERS + sem + pointer to an instance of sem_t + + pshared + if zero, this semaphore may only be shared between + threads in the same process. + if nonzero, the semaphore can be shared between + processes + + value + initial value of the semaphore counter + + DESCRIPTION + This function initializes an unnamed semaphore. The + initial value of the semaphore is set to 'value'. + + RESULTS + 0 successfully created semaphore, + -1 failed, error in errno + ERRNO + EINVAL 'sem' is not a valid semaphore, + ENOSPC a required resource has been exhausted, + ENOSYS semaphores are not supported, + EPERM the process lacks appropriate privilege + +*/ + +int +sem_init (sem_t *sem, int pshared, unsigned int value) +{ + int result = 0; + + if (pshared != 0) + { + /* + We don't support creating a semaphore that can be shared between + processes + */ + result = EPERM; + } + else + { +#ifndef HAVE_CREATESEMAPHORE + sem->value = value; + sem->event = CreateEvent(NULL, + FALSE, /* manual reset */ + FALSE, /* initial state */ + NULL); + if (!sem->event) + result = ENOSPC; + else + { + if (value) + SetEvent(sem->event); + InitializeCriticalSection(&sem->sem_lock_cs); + } +#else /* HAVE_CREATESEMAPHORE */ + *sem = CreateSemaphore (NULL, /* Always NULL */ + value, /* Initial value */ + 0x7FFFFFFFL, /* Maximum value */ + NULL); /* Name */ + if (!*sem) + result = ENOSPC; +#endif /* HAVE_CREATESEMAPHORE */ + } + if (result != 0) + { + errno = result; + return -1; + } + return 0; +} /* sem_init */ + + +/* + DOCPUBLIC + This function destroys an unnamed semaphore. + + PARAMETERS + sem + pointer to an instance of sem_t + + DESCRIPTION + This function destroys an unnamed semaphore. + + RESULTS + 0 successfully destroyed semaphore, + -1 failed, error in errno + ERRNO + EINVAL 'sem' is not a valid semaphore, + ENOSYS semaphores are not supported, + EBUSY threads (or processes) are currently + blocked on 'sem' +*/ + +int +sem_destroy (sem_t * sem) +{ + int result = 0; + +#ifdef EXTRA_DEBUG + if (sem == NULL || *sem == NULL) + { + errno=EINVAL; + return; + } +#endif /* EXTRA_DEBUG */ + +#ifndef HAVE_CREATESEMAPHORE + if (! CloseHandle(sem->event)) + result = EINVAL; + else + DeleteCriticalSection(&sem->sem_lock_cs); +#else /* HAVE_CREATESEMAPHORE */ + if (!CloseHandle(*sem)) + result = EINVAL; +#endif /* HAVE_CREATESEMAPHORE */ + if (result) + { + errno = result; + return -1; + } + *sem=0; /* Safety */ + return 0; +} /* sem_destroy */ + + +/* + DOCPUBLIC + This function tries to wait on a semaphore. + + PARAMETERS + sem + pointer to an instance of sem_t + + DESCRIPTION + This function tries to wait on a semaphore. If the + semaphore value is greater than zero, it decreases + its value by one. If the semaphore value is zero, then + this function returns immediately with the error EAGAIN + + RESULTS + 0 successfully decreased semaphore, + -1 failed, error in errno + ERRNO + EAGAIN the semaphore was already locked, + EINVAL 'sem' is not a valid semaphore, + ENOSYS semaphores are not supported, + EINTR the function was interrupted by a signal, + EDEADLK a deadlock condition was detected. +*/ + +int +sem_trywait(sem_t * sem) +{ +#ifndef HAVE_CREATESEMAPHORE + /* not yet implemented! */ + int errno = EINVAL; + return -1; +#else /* HAVE_CREATESEMAPHORE */ +#ifdef EXTRA_DEBUG + if (sem == NULL || *sem == NULL) + { + errno=EINVAL; + return -1; + } +#endif /* EXTRA_DEBUG */ + if (WaitForSingleObject (*sem, 0) == WAIT_TIMEOUT) + { + errno= EAGAIN; + return -1; + } + return 0; +#endif /* HAVE_CREATESEMAPHORE */ + +} /* sem_trywait */ + + +#ifndef HAVE_CREATESEMAPHORE + +static void +ptw32_decrease_semaphore(sem_t * sem) +{ + EnterCriticalSection(&sem->sem_lock_cs); + DBUG_ASSERT(sem->value != 0); + sem->value--; + if (sem->value != 0) + SetEvent(sem->event); + LeaveCriticalSection(&sem->sem_lock_cs); +} + +static BOOL +ptw32_increase_semaphore(sem_t * sem, unsigned int n) +{ + BOOL result=FALSE; + + EnterCriticalSection(&sem->sem_lock_cs); + if (sem->value + n > sem->value) + { + sem->value += n; + SetEvent(sem->event); + result = TRUE; + } + LeaveCriticalSection(&sem->sem_lock_cs); + return result; +} + +#endif /* HAVE_CREATESEMAPHORE */ + + +/* + ------------------------------------------------------ + DOCPUBLIC + This function waits on a semaphore. + + PARAMETERS + sem + pointer to an instance of sem_t + + DESCRIPTION + This function waits on a semaphore. If the + semaphore value is greater than zero, it decreases + its value by one. If the semaphore value is zero, then + the calling thread (or process) is blocked until it can + successfully decrease the value or until interrupted by + a signal. + + RESULTS + 0 successfully decreased semaphore, + -1 failed, error in errno + ERRNO + EINVAL 'sem' is not a valid semaphore, + ENOSYS semaphores are not supported, + EINTR the function was interrupted by a signal, + EDEADLK a deadlock condition was detected. + +*/ + +int +sem_wait(sem_t *sem) +{ + int result; + +#ifdef EXTRA_DEBUG + if (sem == NULL || *sem == NULL) + { + errno=EINVAL; + return -1; + } +#endif /* EXTRA_DEBUG */ + +#ifndef HAVE_CREATESEMAPHORE + result=WaitForSingleObject(sem->event, INFINITE); +#else + result=WaitForSingleObject(*sem, INFINITE); +#endif + if (result == WAIT_FAILED || result == WAIT_ABANDONED_0) + result = EINVAL; + else if (result == WAIT_TIMEOUT) + result = ETIMEDOUT; + else + result=0; + if (result) + { + errno = result; + return -1; + } +#ifndef HAVE_CREATESEMAPHORE + ptw32_decrease_semaphore(sem); +#endif /* HAVE_CREATESEMAPHORE */ + return 0; +} + + +/* + ------------------------------------------------------ + DOCPUBLIC + This function posts a wakeup to a semaphore. + + PARAMETERS + sem + pointer to an instance of sem_t + + DESCRIPTION + This function posts a wakeup to a semaphore. If there + are waiting threads (or processes), one is awakened; + otherwise, the semaphore value is incremented by one. + + RESULTS + 0 successfully posted semaphore, + -1 failed, error in errno + ERRNO + EINVAL 'sem' is not a valid semaphore, + ENOSYS semaphores are not supported, + +*/ + +int +sem_post (sem_t * sem) +{ +#ifdef EXTRA_DEBUG + if (sem == NULL || *sem == NULL) + { + errno=EINVAL; + return -1; + } +#endif /* EXTRA_DEBUG */ + +#ifndef HAVE_CREATESEMAPHORE + if (! ptw32_increase_semaphore(sem, 1)) +#else /* HAVE_CREATESEMAPHORE */ + if (! ReleaseSemaphore(*sem, 1, 0)) +#endif /* HAVE_CREATESEMAPHORE */ + { + errno=EINVAL; + return -1; + } + return 0; +} + + +/* + ------------------------------------------------------ + DOCPUBLIC + This function posts multiple wakeups to a semaphore. + + PARAMETERS + sem + pointer to an instance of sem_t + + count + counter, must be greater than zero. + + DESCRIPTION + This function posts multiple wakeups to a semaphore. If there + are waiting threads (or processes), n <= count are awakened; + the semaphore value is incremented by count - n. + + RESULTS + 0 successfully posted semaphore, + -1 failed, error in errno + ERRNO + EINVAL 'sem' is not a valid semaphore + or count is less than or equal to zero. +*/ + +int +sem_post_multiple (sem_t * sem, int count ) +{ +#ifdef EXTRA_DEBUG + if (sem == NULL || *sem == NULL || count <= 0) + { + errno=EINVAL; + return -1; + } +#endif /* EXTRA_DEBUG */ +#ifndef HAVE_CREATESEMAPHORE + if (! ptw32_increase_semaphore (sem, count)) +#else /* HAVE_CREATESEMAPHORE */ + if (! ReleaseSemaphore(*sem, count, 0)) +#endif /* HAVE_CREATESEMAPHORE */ + { + errno = EINVAL; + return -1; + } + return 0; +} + +int +sem_getvalue (sem_t *sem, int *sval) +{ + errno = ENOSYS; + return -1; +} /* sem_getvalue */ + +#endif /* __WIN__ */ diff --git a/sql/filesort.cc b/sql/filesort.cc index ce46f1c461c..a5f42d5731e 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -69,7 +69,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, { int error; ulong memavl; - uint maxbuffer,skr; + uint maxbuffer; BUFFPEK *buffpek; ha_rows records; uchar **sort_keys; @@ -163,7 +163,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, &tempfile, selected_records_file)) == HA_POS_ERROR) goto err; - maxbuffer= my_b_tell(&buffpek_pointers)/sizeof(*buffpek); + maxbuffer= (uint) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek)); if (maxbuffer == 0) // The whole set is in memory { @@ -267,7 +267,7 @@ static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count) if (tmp) { if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) || - my_b_read(buffpek_pointers, (char*) tmp, length)) + my_b_read(buffpek_pointers, (byte*) tmp, length)) { my_free((char*) tmp, MYF(0)); tmp=0; @@ -398,10 +398,12 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, /* Skriver en buffert med nycklar till filen */ -static int write_keys(SORTPARAM *param, register uchar **sort_keys, uint count, - IO_CACHE *buffpek_pointers, IO_CACHE *tempfile) +static int +write_keys(SORTPARAM *param, register uchar **sort_keys, uint count, + IO_CACHE *buffpek_pointers, IO_CACHE *tempfile) { uint sort_length; + uchar **end; BUFFPEK buffpek; DBUG_ENTER("write_keys"); @@ -419,10 +421,10 @@ static int write_keys(SORTPARAM *param, register uchar **sort_keys, uint count, if ((ha_rows) count > param->max_rows) count=(uint) param->max_rows; /* purecov: inspected */ buffpek.count=(ha_rows) count; - for (uchar **end=sort_keys+count ; sort_keys != end ; sort_keys++) + for (end=sort_keys+count ; sort_keys != end ; sort_keys++) if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length)) goto err; - if (my_b_write(buffpek_pointers, (char*) &buffpek, sizeof(buffpek))) + if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek))) goto err; DBUG_RETURN(0); diff --git a/sql/item_func.cc b/sql/item_func.cc index 652896bb1e4..5b4fb816404 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2019,7 +2019,9 @@ void Item_func_match::init_search(bool no_order) } ft_handler=table->file->ft_init_ext(mode, key, - ft_tmp->ptr(), ft_tmp->length(), join_key && !no_order); + (byte*) ft_tmp->ptr(), + ft_tmp->length(), + join_key && !no_order); if (join_key) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 72953cad8e8..afd2395805d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -149,7 +149,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #define SELECT_SMALL_RESULT 8 #define SELECT_BIG_RESULT 16 #define OPTION_FOUND_ROWS 32 -#define SELECT_HIGH_PRIORITY 64 /* Intern */ +#define OPTION_TO_QUERY_CACHE 64 #define SELECT_NO_JOIN_CACHE 256 /* Intern */ #define OPTION_BIG_TABLES 512 /* for SQL OPTION */ @@ -179,7 +179,6 @@ 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 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8290e659a25..78f7351b0c8 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3157,12 +3157,16 @@ 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}, - {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, - SHOW_LONG}, + {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST}, {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG}, {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG}, {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG}, - {"Qcache_free_memory", (char*) &query_cache.free_memory,SHOW_LONG}, + {"Qcache_free_memory", (char*) &query_cache.free_memory, + SHOW_LONG_CONST}, + {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, + SHOW_LONG_CONST}, + {"Qcache_total_blocks", (char*) &query_cache.total_blocks, + SHOW_LONG_CONST}, {"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}, diff --git a/sql/slave.cc b/sql/slave.cc index 0d463b04a4a..7a603ec0827 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -35,11 +35,14 @@ bool do_table_inited = 0, ignore_table_inited = 0; bool wild_do_table_inited = 0, wild_ignore_table_inited = 0; bool table_rules_on = 0; uint32 slave_skip_counter = 0; + +/* + When slave thread exits, we need to remember the temporary tables so we + can re-use them on slave start +*/ static TABLE* save_temporary_tables = 0; -THD* slave_thd = 0; -// when slave thread exits, we need to remember the temporary tables so we -// can re-use them on slave start +THD* slave_thd = 0; int last_slave_errno = 0; char last_slave_error[MAX_SLAVE_ERRMSG] = ""; #ifndef DBUG_OFF @@ -98,14 +101,14 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len) uint i; const char* key_end = key + len; - for(i = 0; i < a->elements; i++) - { - TABLE_RULE_ENT* e ; - get_dynamic(a, (gptr)&e, i); - if(!wild_case_compare(key, key_end, (const char*)e->db, - (const char*)(e->db + e->key_len),'\\')) - return e; - } + for (i = 0; i < a->elements; i++) + { + TABLE_RULE_ENT* e ; + get_dynamic(a, (gptr)&e, i); + if (!wild_case_compare(key, key_end, (const char*)e->db, + (const char*)(e->db + e->key_len),'\\')) + return e; + } return 0; } @@ -114,10 +117,10 @@ int tables_ok(THD* thd, TABLE_LIST* tables) { for (; tables; tables = tables->next) { - if (!tables->updating) - continue; char hash_key[2*NAME_LEN+2]; char* p; + if (!tables->updating) + continue; p = strmov(hash_key, tables->db ? tables->db : thd->db); *p++ = '.'; uint len = strmov(p, tables->real_name) - hash_key ; @@ -139,9 +142,10 @@ int tables_ok(THD* thd, TABLE_LIST* tables) return 0; } - // if no explicit rule found - // and there was a do list, do not replicate. If there was - // no do list, go ahead + /* + If no explicit rule found and there was a do list, do not replicate. + If there was no do list, go ahead + */ return !do_table_inited && !wild_do_table_inited; } @@ -149,12 +153,14 @@ int tables_ok(THD* thd, TABLE_LIST* tables) int add_table_rule(HASH* h, const char* table_spec) { const char* dot = strchr(table_spec, '.'); - if(!dot) return 1; + if (!dot) + return 1; // len is always > 0 because we know the there exists a '.' uint len = (uint)strlen(table_spec); TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME)); - if(!e) return 1; + if (!e) + return 1; e->db = (char*)e + sizeof(TABLE_RULE_ENT); e->tbl_name = e->db + (dot - table_spec) + 1; e->key_len = len; @@ -166,11 +172,12 @@ int add_table_rule(HASH* h, const char* table_spec) int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) { const char* dot = strchr(table_spec, '.'); - if(!dot) return 1; + if (!dot) return 1; uint len = (uint)strlen(table_spec); TABLE_RULE_ENT* e = (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME)); - if(!e) return 1; + if (!e) + return 1; e->db = (char*)e + sizeof(TABLE_RULE_ENT); e->tbl_name = e->db + (dot - table_spec) + 1; e->key_len = len; @@ -182,12 +189,12 @@ int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) static void free_string_array(DYNAMIC_ARRAY *a) { uint i; - for(i = 0; i < a->elements; i++) - { - char* p; - get_dynamic(a, (gptr) &p, i); - my_free(p, MYF(MY_WME)); - } + for (i = 0; i < a->elements; i++) + { + char* p; + get_dynamic(a, (gptr) &p, i); + my_free(p, MYF(MY_WME)); + } delete_dynamic(a); } @@ -207,13 +214,13 @@ void end_slave() pthread_mutex_unlock(&LOCK_slave); end_master_info(&glob_mi); - if(do_table_inited) + if (do_table_inited) hash_free(&replicate_do_table); - if(ignore_table_inited) + if (ignore_table_inited) hash_free(&replicate_ignore_table); - if(wild_do_table_inited) + if (wild_do_table_inited) free_string_array(&replicate_wild_do_table); - if(wild_ignore_table_inited) + if (wild_ignore_table_inited) free_string_array(&replicate_wild_ignore_table); } @@ -241,13 +248,13 @@ void skip_load_data_infile(NET* net) char* rewrite_db(char* db) { - if(replicate_rewrite_db.is_empty() || !db) return db; + if (replicate_rewrite_db.is_empty() || !db) return db; I_List_iterator<i_string_pair> it(replicate_rewrite_db); i_string_pair* tmp; while((tmp=it++)) { - if(!strcmp(tmp->key, db)) + if (!strcmp(tmp->key, db)) return tmp->val; } @@ -257,39 +264,39 @@ char* rewrite_db(char* db) int db_ok(const char* db, I_List<i_string> &do_list, I_List<i_string> &ignore_list ) { - if(do_list.is_empty() && ignore_list.is_empty()) + if (do_list.is_empty() && ignore_list.is_empty()) return 1; // ok to replicate if the user puts no constraints // if the user has specified restrictions on which databases to replicate // and db was not selected, do not replicate - if(!db) + if (!db) return 0; - if(!do_list.is_empty()) // if the do's are not empty - { - I_List_iterator<i_string> it(do_list); - i_string* tmp; + if (!do_list.is_empty()) // if the do's are not empty + { + I_List_iterator<i_string> it(do_list); + i_string* tmp; - while((tmp=it++)) - { - if(!strcmp(tmp->ptr, db)) - return 1; // match - } - return 0; + while((tmp=it++)) + { + if (!strcmp(tmp->ptr, db)) + return 1; // match } + return 0; + } else // there are some elements in the don't, otherwise we cannot get here - { - I_List_iterator<i_string> it(ignore_list); - i_string* tmp; - - while((tmp=it++)) - { - if(!strcmp(tmp->ptr, db)) - return 0; // match - } + { + I_List_iterator<i_string> it(ignore_list); + i_string* tmp; - return 1; + while((tmp=it++)) + { + if (!strcmp(tmp->ptr, db)) + return 0; // match } + + return 1; + } } static int init_strvar_from_file(char* var, int max_size, IO_CACHE* f, @@ -327,7 +334,7 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) *var = atoi(buf); return 0; } - else if(default_val) + else if (default_val) { *var = default_val; return 0; @@ -530,7 +537,7 @@ int fetch_nx_table(THD* thd, const char* db_name, const char* table_name, void end_master_info(MASTER_INFO* mi) { - if(mi->fd >= 0) + if (mi->fd >= 0) { end_io_cache(&mi->file); (void)my_close(mi->fd, MYF(MY_WME)); @@ -567,7 +574,7 @@ int init_master_info(MASTER_INFO* mi) || init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0, MYF(MY_WME))) { - if(fd >= 0) + if (fd >= 0) my_close(fd, MYF(0)); pthread_mutex_unlock(&mi->lock); return 1; @@ -587,13 +594,13 @@ int init_master_info(MASTER_INFO* mi) } else // file exists { - if(fd >= 0) + if (fd >= 0) reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0); - else if((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 + else if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 || init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME))) { - if(fd >= 0) + if (fd >= 0) my_close(fd, MYF(0)); pthread_mutex_unlock(&mi->lock); return 1; @@ -608,7 +615,7 @@ int init_master_info(MASTER_INFO* mi) mi->log_file_name[length-1]= 0; // kill \n /* Reuse fname buffer */ - if(!my_b_gets(&mi->file, fname, sizeof(fname))) + if (!my_b_gets(&mi->file, fname, sizeof(fname))) { msg="Error reading log file position from master info file"; goto error; @@ -616,7 +623,7 @@ int init_master_info(MASTER_INFO* mi) mi->pos = strtoull(fname,(char**) 0, 10); mi->fd = fd; - if(init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, + if (init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, master_host) || init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, master_user) || @@ -654,19 +661,19 @@ int register_slave_on_master(MYSQL* mysql) String packet; char buf[4]; - if(!report_host) + if (!report_host) return 0; int4store(buf, server_id); packet.append(buf, 4); net_store_data(&packet, report_host); - if(report_user) + if (report_user) net_store_data(&packet, report_user); else packet.append((char)0); - if(report_password) + if (report_password) net_store_data(&packet, report_user); else packet.append((char)0); @@ -678,7 +685,7 @@ int register_slave_on_master(MYSQL* mysql) int4store(buf, 0); /* tell the master will fill in master_id */ packet.append(buf, 4); - if(mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(), + if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(), packet.length(), 0)) { sql_print_error("Error on COM_REGISTER_SLAVE: '%s'", @@ -710,7 +717,7 @@ int show_master_info(THD* thd) field_list.push_back(new Item_empty_string("Last_error", 20)); field_list.push_back(new Item_empty_string("Skip_counter", 12)); field_list.push_back(new Item_empty_string("Last_log_seq", 12)); - if(send_fields(thd, field_list, 1)) + if (send_fields(thd, field_list, 1)) DBUG_RETURN(-1); String* packet = &thd->packet; @@ -758,6 +765,7 @@ int flush_master_info(MASTER_INFO* mi) return 0; } + int st_master_info::wait_for_pos(THD* thd, String* log_name, ulonglong log_pos) { if (!inited) return -1; @@ -901,17 +909,18 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi) return 0; } + static int request_table_dump(MYSQL* mysql, const char* db, const char* table) { char buf[1024]; char * p = buf; uint table_len = (uint) strlen(table); uint db_len = (uint) strlen(db); - if(table_len + db_len > sizeof(buf) - 2) - { - sql_print_error("request_table_dump: Buffer overrun"); - return 1; - } + if (table_len + db_len > sizeof(buf) - 2) + { + sql_print_error("request_table_dump: Buffer overrun"); + return 1; + } *p++ = db_len; memcpy(p, db, db_len); @@ -1008,12 +1017,12 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) if (ev->server_id == ::server_id || (slave_skip_counter && type_code != ROTATE_EVENT)) { - if(type_code == LOAD_EVENT) + if (type_code == LOAD_EVENT) skip_load_data_infile(net); mi->inc_pos(event_len, ev->log_seq); flush_master_info(mi); - if(slave_skip_counter && /* protect against common user error of + if (slave_skip_counter && /* protect against common user error of setting the counter to 1 instead of 2 while recovering from an failed auto-increment insert */ @@ -1026,7 +1035,7 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) thd->server_id = ev->server_id; // use the original server id for logging thd->set_time(); // time the query - if(!thd->log_seq) + if (!thd->log_seq) thd->log_seq = ev->log_seq; if (!ev->when) ev->when = time(NULL); @@ -1050,7 +1059,7 @@ This may also be a network problem, or just a bug in the master or slave code.\ pthread_handler_decl(handle_slave,arg __attribute__((unused))) { #ifndef DBUG_OFF - slave_begin: +slave_begin: #endif THD *thd; // needs to be first for thread_stack MYSQL *mysql = NULL ; @@ -1065,12 +1074,12 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) pthread_exit((void*)1); } - if(slave_running) - { - pthread_cond_broadcast(&COND_slave_start); - pthread_mutex_unlock(&LOCK_slave); - pthread_exit((void*)1); // safety just in case - } + if (slave_running) + { + pthread_cond_broadcast(&COND_slave_start); + pthread_mutex_unlock(&LOCK_slave); + pthread_exit((void*)1); // safety just in case + } slave_running = 1; abort_slave = 0; #ifndef DBUG_OFF @@ -1090,10 +1099,10 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) pthread_detach_this_thread(); if (init_slave_thread(thd) || init_master_info(&glob_mi)) - { - sql_print_error("Failed during slave thread initialization"); - goto err; - } + { + sql_print_error("Failed during slave thread initialization"); + goto err; + } thd->thread_stack = (char*)&thd; // remember where our stack is thd->temporary_tables = save_temporary_tables; // restore temp tables threads.append(thd); @@ -1116,11 +1125,11 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) #endif // we can get killed during safe_connect if (!safe_connect(thd, mysql, &glob_mi)) - sql_print_error("Slave: connected to master '%s@%s:%d',\ + sql_print_error("Slave: connected to master '%s@%s:%d',\ replication started in log '%s' at position %s", glob_mi.user, - glob_mi.host, glob_mi.port, - RPL_LOG_NAME, - llstr(glob_mi.pos,llbuff)); + glob_mi.host, glob_mi.port, + RPL_LOG_NAME, + llstr(glob_mi.pos,llbuff)); else { sql_print_error("Slave thread killed while connecting to master"); @@ -1147,154 +1156,154 @@ connected: while (!slave_killed(thd)) { - thd->proc_info = "Requesting binlog dump"; - if(request_dump(mysql, &glob_mi)) - { - sql_print_error("Failed on request_dump()"); - if(slave_killed(thd)) - { - sql_print_error("Slave thread killed while requesting master \ + thd->proc_info = "Requesting binlog dump"; + if (request_dump(mysql, &glob_mi)) + { + sql_print_error("Failed on request_dump()"); + if (slave_killed(thd)) + { + sql_print_error("Slave thread killed while requesting master \ dump"); - goto err; - } - - thd->proc_info = "Waiiting to reconnect after a failed dump request"; - if(mysql->net.vio) - vio_close(mysql->net.vio); - // first time retry immediately, assuming that we can recover - // right away - if first time fails, sleep between re-tries - // hopefuly the admin can fix the problem sometime - if(retried_once) - safe_sleep(thd, glob_mi.connect_retry); - else - retried_once = 1; - - if(slave_killed(thd)) - { - sql_print_error("Slave thread killed while retrying master \ + goto err; + } + + thd->proc_info = "Waiiting to reconnect after a failed dump request"; + if (mysql->net.vio) + vio_close(mysql->net.vio); + // first time retry immediately, assuming that we can recover + // right away - if first time fails, sleep between re-tries + // hopefuly the admin can fix the problem sometime + if (retried_once) + safe_sleep(thd, glob_mi.connect_retry); + else + retried_once = 1; + + if (slave_killed(thd)) + { + sql_print_error("Slave thread killed while retrying master \ dump"); - goto err; - } + goto err; + } - thd->proc_info = "Reconnecting after a failed dump request"; - last_failed_pos=glob_mi.pos; - sql_print_error("Slave: failed dump request, reconnecting to \ + thd->proc_info = "Reconnecting after a failed dump request"; + last_failed_pos=glob_mi.pos; + sql_print_error("Slave: failed dump request, reconnecting to \ try again, log '%s' at postion %s", RPL_LOG_NAME, - llstr(last_failed_pos,llbuff)); - if(safe_reconnect(thd, mysql, &glob_mi) || slave_killed(thd)) - { - sql_print_error("Slave thread killed during or after reconnect"); - goto err; - } - - goto connected; - } + llstr(last_failed_pos,llbuff)); + if (safe_reconnect(thd, mysql, &glob_mi) || slave_killed(thd)) + { + sql_print_error("Slave thread killed during or after reconnect"); + goto err; + } + + goto connected; + } - while(!slave_killed(thd)) + while(!slave_killed(thd)) + { + thd->proc_info = "Reading master update"; + ulong event_len = read_event(mysql, &glob_mi); + if (slave_killed(thd)) + { + sql_print_error("Slave thread killed while reading event"); + goto err; + } + + + if (event_len == packet_error) + { + if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE) { - thd->proc_info = "Reading master update"; - ulong event_len = read_event(mysql, &glob_mi); - if(slave_killed(thd)) - { - sql_print_error("Slave thread killed while reading event"); - goto err; - } - - - if (event_len == packet_error) - { - if(mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE) - { - sql_print_error("Log entry on master is longer than \ + sql_print_error("Log entry on master is longer than \ max_allowed_packet on slave. Slave thread will be aborted. If the entry is \ really supposed to be that long, restart the server with a higher value of \ max_allowed_packet. The current value is %ld", max_allowed_packet); - goto err; - } - - thd->proc_info = "Waiting to reconnect after a failed read"; - if(mysql->net.vio) - vio_close(mysql->net.vio); - if(retried_once) // punish repeat offender with sleep - safe_sleep(thd, glob_mi.connect_retry); - else - retried_once = 1; - - if(slave_killed(thd)) - { - sql_print_error("Slave thread killed while waiting to \ + goto err; + } + + thd->proc_info = "Waiting to reconnect after a failed read"; + if (mysql->net.vio) + vio_close(mysql->net.vio); + if (retried_once) // punish repeat offender with sleep + safe_sleep(thd, glob_mi.connect_retry); + else + retried_once = 1; + + if (slave_killed(thd)) + { + sql_print_error("Slave thread killed while waiting to \ reconnect after a failed read"); - goto err; - } - thd->proc_info = "Reconnecting after a failed read"; - last_failed_pos= glob_mi.pos; - sql_print_error("Slave: Failed reading log event, \ + goto err; + } + thd->proc_info = "Reconnecting after a failed read"; + last_failed_pos= glob_mi.pos; + sql_print_error("Slave: Failed reading log event, \ reconnecting to retry, log '%s' position %s", RPL_LOG_NAME, - llstr(last_failed_pos, llbuff)); - if(safe_reconnect(thd, mysql, &glob_mi) || slave_killed(thd)) - { - sql_print_error("Slave thread killed during or after a \ + llstr(last_failed_pos, llbuff)); + if (safe_reconnect(thd, mysql, &glob_mi) || slave_killed(thd)) + { + sql_print_error("Slave thread killed during or after a \ reconnect done to recover from failed read"); - goto err; - } + goto err; + } - goto connected; - } // if(event_len == packet_error) + goto connected; + } // if (event_len == packet_error) - thd->proc_info = "Processing master log event"; - if(exec_event(thd, &mysql->net, &glob_mi, event_len)) - { - sql_print_error("\ + thd->proc_info = "Processing master log event"; + if (exec_event(thd, &mysql->net, &glob_mi, event_len)) + { + sql_print_error("\ Error running query, slave aborted. Fix the problem, and re-start \ the slave thread with \"mysqladmin start-slave\". We stopped at log \ '%s' position %s", - RPL_LOG_NAME, llstr(glob_mi.pos, llbuff)); - goto err; - // there was an error running the query - // abort the slave thread, when the problem is fixed, the user - // should restart the slave with mysqladmin start-slave - } + RPL_LOG_NAME, llstr(glob_mi.pos, llbuff)); + goto err; + // there was an error running the query + // abort the slave thread, when the problem is fixed, the user + // should restart the slave with mysqladmin start-slave + } #ifndef DBUG_OFF - if(abort_slave_event_count && !--events_till_abort) - { - sql_print_error("Slave: debugging abort"); - goto err; - } + if (abort_slave_event_count && !--events_till_abort) + { + sql_print_error("Slave: debugging abort"); + goto err; + } #endif - // successful exec with offset advance, - // the slave repents and his sins are forgiven! - if(glob_mi.pos > last_failed_pos) - { - retried_once = 0; + // successful exec with offset advance, + // the slave repents and his sins are forgiven! + if (glob_mi.pos > last_failed_pos) + { + retried_once = 0; #ifndef DBUG_OFF - stuck_count = 0; + stuck_count = 0; #endif - } + } #ifndef DBUG_OFF - else - { - // show a little mercy, allow slave to read one more event - // before cutting him off - otherwise he gets stuck - // on Intvar events, since they do not advance the offset - // immediately - if (++stuck_count > 2) - events_till_disconnect++; - } + else + { + // show a little mercy, allow slave to read one more event + // before cutting him off - otherwise he gets stuck + // on Intvar events, since they do not advance the offset + // immediately + if (++stuck_count > 2) + events_till_disconnect++; + } #endif - } // while(!slave_killed(thd)) - read/exec loop + } // while(!slave_killed(thd)) - read/exec loop } // while(!slave_killed(thd)) - slave loop // error = 0; - err: +err: // print the current replication position sql_print_error("Slave thread exiting, replication stopped in log '%s' at \ position %s", RPL_LOG_NAME, llstr(glob_mi.pos,llbuff)); thd->query = thd->db = 0; // extra safety - if(mysql) - mc_mysql_close(mysql); + if (mysql) + mc_mysql_close(mysql); thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&LOCK_slave); slave_running = 0; @@ -1309,7 +1318,7 @@ position %s", delete thd; my_thread_end(); #ifndef DBUG_OFF - if(abort_slave_event_count && !events_till_abort) + if (abort_slave_event_count && !events_till_abort) goto slave_begin; #endif pthread_exit(0); @@ -1346,7 +1355,7 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, events_till_disconnect = disconnect_slave_event_count; #endif while (!(slave_was_killed = slave_killed(thd)) && - (reconnect ? mc_mysql_reconnect(mysql) : + (reconnect ? mc_mysql_reconnect(mysql) != 0 : !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, mi->port, 0, 0))) { diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 94062978fa5..5e07a3529ea 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -286,13 +286,8 @@ If join_results allocated new block(s) then we need call pack_cache again. #if defined(EXTRA_DEBUG) && !defined(DBUG_OFF) #define MUTEX_LOCK(M) { DBUG_PRINT("lock", ("mutex lock 0x%lx", (ulong)(M))); \ pthread_mutex_lock(M);} -#define SEM_LOCK(M) { int val = 0; sem_getvalue (M, &val); \ - DBUG_PRINT("lock", ("sem lock 0x%lx (%d)", (ulong)(M), val)); \ - sem_wait(M); DBUG_PRINT("lock", ("sem lock ok")); } #define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\ (ulong)(M))); pthread_mutex_unlock(M);} -#define SEM_UNLOCK(M) {DBUG_PRINT("lock", ("sem unlock 0x%lx", (ulong)(M))); \ - sem_post(M); DBUG_PRINT("lock", ("sem unlock ok")); } #define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \ pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));} #define STRUCT_UNLOCK(M) { \ @@ -313,9 +308,7 @@ If join_results allocated new block(s) then we need call pack_cache again. #define DUMP(C) DBUG_EXECUTE("qcache", {(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() @@ -332,7 +325,7 @@ If join_results allocated new block(s) then we need call pack_cache again. inline Query_cache_block * Query_cache_block_table::block() { return (Query_cache_block *)(((byte*)this) - - sizeof(Query_cache_block_table)*n - + ALIGN_SIZE(sizeof(Query_cache_block_table)*n) - ALIGN_SIZE(sizeof(Query_cache_block))); }; @@ -432,7 +425,7 @@ 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_cond_init(&lock, NULL); pthread_mutex_init(&clients_guard,MY_MUTEX_INIT_FAST); clients = 0; lock_writing(); @@ -445,14 +438,14 @@ void Query_cache_query::init_n_lock() void Query_cache_query::unlock_n_destroy() { DBUG_ENTER("Query_cache_query::unlock_n_destroy"); + DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx", + ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block)))); /* The following call is not needed on system where one can destroy an active semaphore */ this->unlock_writing(); - DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx", - ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block)))); - sem_destroy(&lock); + pthread_cond_destroy(&lock); pthread_mutex_destroy(&clients_guard); DBUG_VOID_RETURN; } @@ -468,7 +461,9 @@ void Query_cache_query::unlock_n_destroy() void Query_cache_query::lock_writing() { - SEM_LOCK(&lock); + MUTEX_LOCK(&clients_guard); + while (clients != 0) + pthread_cond_wait(&lock,&clients_guard); } @@ -482,11 +477,17 @@ void Query_cache_query::lock_writing() my_bool Query_cache_query::try_lock_writing() { DBUG_ENTER("Query_cache_block::try_lock_writing"); - if (sem_trywait(&lock)!=0 || clients != 0) + if (pthread_mutex_trylock(&clients_guard)) { DBUG_PRINT("qcache", ("can't lock mutex")); DBUG_RETURN(0); } + if (clients != 0) + { + DBUG_PRINT("info", ("already locked (r)")); + MUTEX_UNLOCK(&clients_guard); + DBUG_RETURN(0); + } DBUG_PRINT("qcache", ("mutex 'lock' 0x%lx locked", (ulong) &lock)); DBUG_RETURN(1); } @@ -495,15 +496,14 @@ my_bool Query_cache_query::try_lock_writing() void Query_cache_query::lock_reading() { MUTEX_LOCK(&clients_guard); - if (!clients++) - SEM_LOCK(&lock); + clients++; MUTEX_UNLOCK(&clients_guard); } void Query_cache_query::unlock_writing() { - SEM_UNLOCK(&lock); + MUTEX_UNLOCK(&clients_guard); } @@ -511,7 +511,7 @@ void Query_cache_query::unlock_reading() { MUTEX_LOCK(&clients_guard); if (--clients == 0) - SEM_UNLOCK(&lock); + pthread_cond_broadcast(&lock); MUTEX_UNLOCK(&clients_guard); } @@ -677,6 +677,7 @@ Query_cache::Query_cache(ulong query_cache_limit, :query_cache_size(0), query_cache_limit(query_cache_limit), queries_in_cache(0), hits(0), inserts(0), refused(0), + total_blocks(0), min_allocation_unit(min_allocation_unit), min_result_data_size(min_result_data_size), def_query_hash_size(def_query_hash_size), @@ -747,7 +748,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) /* Check if another thread is processing the 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); + hash_search(&queries, (byte*) thd->query, thd->query_length+1); DBUG_PRINT("qcache", ("competitor 0x%lx, flags %x", (ulong) competitor, flags)); if (competitor == 0) @@ -779,7 +780,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) { refused++; DBUG_PRINT("warning", ("tables list including failed")); - hash_delete(&queries, (char *) query_block); + hash_delete(&queries, (byte *) query_block); header->unlock_n_destroy(); free_memory_block(query_block); STRUCT_UNLOCK(&structure_guard_mutex); @@ -790,7 +791,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) queries_in_cache++; STRUCT_UNLOCK(&structure_guard_mutex); - net->query_cache_query = (gptr) query_block; + net->query_cache_query= (gptr) query_block; header->writer(net); // init_n_lock make query block locked BLOCK_UNLOCK_WR(query_block); @@ -890,7 +891,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) } sql[query_length] = (char) flags; - query_block = (Query_cache_block *) hash_search(&queries, sql, + query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql, query_length+1); sql[query_length] = '\0'; @@ -1026,20 +1027,11 @@ void Query_cache::invalidate(Query_cache_table::query_cache_table_type type) { STRUCT_LOCK(&structure_guard_mutex); DUMP(this); - if (query_cache_size > 0 && tables_blocks[type] != 0) + if (query_cache_size > 0) { - Query_cache_block *table_block = tables_blocks[type]; - do - { - /* Store next block address defore deleting the current block */ - Query_cache_block *next = table_block->next; - invalidate_table(table_block); -#ifdef TO_BE_DELETED - if (next == table_block) // End of list - break; -#endif - table_block = next; - } while (table_block != tables_blocks[type]); + /* invalidate_table reduce list while only root of list remain */ + while (tables_blocks[type] != 0) + invalidate_table(tables_blocks[type]); } STRUCT_UNLOCK(&structure_guard_mutex); } @@ -1060,27 +1052,11 @@ void Query_cache::invalidate(char *db) if (query_cache_size > 0) { DUMP(this); - int i = 0; - for(; i < (int) Query_cache_table::TYPES_NUMBER; i++) + for (int i=0 ; 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); -#ifdef TO_BE_DELETED - if (table_block == next) - break; -#endif - table_block = next; - } while (table_block != tables_blocks[i]); - } + /* invalidate_table reduce list while only root of list remain */ + while (tables_blocks[i] !=0 ) + invalidate_table(tables_blocks[i]); } } STRUCT_UNLOCK(&structure_guard_mutex); @@ -1101,7 +1077,8 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename) if (query_cache_size > 0) // Safety if cache removed { Query_cache_block *table_block; - if ((table_block = (Query_cache_block*) hash_search(&tables, key, + if ((table_block = (Query_cache_block*) hash_search(&tables, + (byte*) key, key_length))) invalidate_table(table_block); } @@ -1243,6 +1220,7 @@ ulong Query_cache::init_cache() first_block = (Query_cache_block *) (cache + additional_data_size); first_block->init(query_cache_size); + total_blocks++; first_block->pnext=first_block->pprev=first_block; first_block->next=first_block->prev=first_block; @@ -1290,8 +1268,8 @@ ulong Query_cache::init_cache() size += inc; } } - bins[mem_bin_num].number= 1; // For easy end test - free_memory= 0; + bins[mem_bin_num].number = 1; // For easy end test in get_free_block + free_memory = free_memory_blocks = 0; insert_into_free_memory_list(first_block); DUMP(this); @@ -1348,6 +1326,7 @@ void Query_cache::free_cache(my_bool destruction) /* Becasue we did a flush, all cache memory must be in one this block */ bins[0].free_blocks->destroy(); + total_blocks--; DBUG_PRINT("qcache", ("free memory %lu (should be %lu)", free_memory , query_cache_size)); my_free((gptr) cache, MYF(MY_ALLOW_ZERO_PTR)); @@ -1738,7 +1717,7 @@ void Query_cache::invalidate_table(TABLE_LIST *table_list) // We don't store temporary tables => no key_length+=4 ... if ((table_block = (Query_cache_block*) - hash_search(&tables,key,key_length))) + hash_search(&tables,(byte*) key,key_length))) invalidate_table(table_block); } } @@ -1747,7 +1726,7 @@ 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, + hash_search(&tables, (byte*) table->table_cache_key, table->key_length)))) invalidate_table(table_block); } @@ -1856,7 +1835,8 @@ Query_cache::insert_table(uint key_len, char *key, (ulong)node, key_len)); Query_cache_block *table_block = ((Query_cache_block *) - hash_search(&tables, key, key_len)); + hash_search(&tables, (byte*) key, + key_len)); if (table_block == 0) { @@ -1905,6 +1885,7 @@ Query_cache::insert_table(uint key_len, char *key, void Query_cache::unlink_table(Query_cache_block_table *node) { + DBUG_ENTER("Query_cache::unlink_table"); node->prev->next = node->next; node->next->prev = node->prev; Query_cache_block_table *neighbour = node->next; @@ -1917,6 +1898,7 @@ void Query_cache::unlink_table(Query_cache_block_table *node) hash_delete(&tables,(byte *) table_block); free_memory_block(table_block); } + DBUG_VOID_RETURN; } /***************************************************************************** @@ -2038,6 +2020,7 @@ void Query_cache::split_block(Query_cache_block *block,ulong len) Query_cache_block *new_block = (Query_cache_block*)(((byte*) block)+len); new_block->init(block->length - len); + total_blocks++; block->length=len; new_block->pnext = block->pnext; block->pnext = new_block; @@ -2068,6 +2051,7 @@ Query_cache::join_free_blocks(Query_cache_block *first_block, // May be was not free block second_block->used=0; second_block->destroy(); + total_blocks--; first_block->length += second_block->length; first_block->pnext = second_block->pnext; @@ -2090,6 +2074,7 @@ my_bool Query_cache::append_next_free_block(Query_cache_block *block, ulong old_len = block->length; exclude_from_free_memory_list(next_block); next_block->destroy(); + total_blocks--; block->length += next_block->length; block->pnext = next_block->pnext; @@ -2112,6 +2097,7 @@ void Query_cache::exclude_from_free_memory_list(Query_cache_block *free_block) double_linked_list_exclude(free_block, &bin->free_blocks); bin->number--; free_memory-=free_block->length; + free_memory_blocks--; DBUG_PRINT("qcache",("exclude block 0x%lx, bin 0x%lx", (ulong) free_block, (ulong) bin)); DBUG_VOID_RETURN; @@ -2207,6 +2193,7 @@ void Query_cache::insert_into_free_memory_sorted_list(Query_cache_block * point->next = new_block; } free_memory+=new_block->length; + free_memory_blocks++; DBUG_VOID_RETURN; } @@ -2222,11 +2209,11 @@ Query_cache::double_linked_list_simple_include(Query_cache_block *point, *list_pointer=point->next=point->prev=point; else { + // insert to and of list point->next = (*list_pointer); point->prev = (*list_pointer)->prev; point->prev->next = point; (*list_pointer)->prev = point; - (*list_pointer) = point; } DBUG_VOID_RETURN; } @@ -2360,6 +2347,7 @@ void Query_cache::pack_cache() { Query_cache_block *new_block = (Query_cache_block *) border; new_block->init(gap); + total_blocks++; new_block->pnext = before->pnext; before->pnext = new_block; new_block->pprev = before; @@ -2395,6 +2383,7 @@ my_bool Query_cache::move_by_type(byte **border, block->pprev->pnext=block->pnext; block->pnext->pprev=block->pprev; block->destroy(); + total_blocks--; DBUG_PRINT("qcache", ("added to gap (%lu)", *gap)); break; } @@ -2416,7 +2405,7 @@ my_bool Query_cache::move_by_type(byte **border, byte *key; uint key_length; key=query_cache_table_get_key((byte*) block, &key_length,0); - hash_search(&tables, key, key_length); + hash_search(&tables, (byte*) key, key_length); block->destroy(); new_block->init(len); @@ -2432,8 +2421,10 @@ my_bool Query_cache::move_by_type(byte **border, 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; + tnext->prev = nlist_root; + tprev->next = nlist_root; + for (;tnext != nlist_root; tnext=tnext->next) + tnext->parent = new_block->table(); *border += len; *before = new_block; /* Fix hash to point at moved block */ @@ -2462,7 +2453,7 @@ my_bool Query_cache::move_by_type(byte **border, byte *key; uint key_length; key=query_cache_query_get_key((byte*) block, &key_length,0); - hash_search(&queries, key, key_length); + hash_search(&queries, (byte*) key, key_length); memcpy((char*) new_block->table(0), (char*) block->table(0), ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table))); @@ -2654,7 +2645,6 @@ my_bool Query_cache::join_results(ulong join_limit) uint Query_cache::filename_2_table_key (char *key, const char *path) { char tablename[FN_REFLEN+2], *filename, *dbname; - Query_cache_block *table_block; uint db_length; DBUG_ENTER("Query_cache::filename_2_table_key"); @@ -2666,7 +2656,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path) filename= tablename + dirname_length(tablename + 2) + 2; /* Find start of databasename */ for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ; - db_length= (filename - dbname) - 1; + db_length= (filename - dbname) - 1; DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename)); DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1, diff --git a/sql/sql_cache.h b/sql/sql_cache.h index f5f0580d051..c01ea1e21d4 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -17,8 +17,6 @@ #ifndef _SQL_CACHE_H #define _SQL_CACHE_H -#include <semaphore.h> - /* Query cache */ /* @@ -105,7 +103,7 @@ struct Query_cache_query Query_cache_block *res; NET *wri; ulong len; - sem_t lock; // R/W lock of block + pthread_cond_t lock; // R/W lock of block pthread_mutex_t clients_guard; uint clients; @@ -220,7 +218,8 @@ public: /* Info */ ulong query_cache_size, query_cache_limit; /* statistics */ - ulong free_memory, queries_in_cache, hits, inserts, refused; + ulong free_memory, queries_in_cache, hits, inserts, refused, + free_memory_blocks, total_blocks; protected: /* diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index acad297cda1..bfee5f9235b 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1023,11 +1023,11 @@ err: int log_loaded_block(IO_CACHE* file) { LOAD_FILE_INFO* lf_info; - uint block_len ; + ulong block_len ; /* file->request_pos contains position where we started last read */ - char* buffer = (char*) file->request_pos; - if (!(block_len = file->read_end - buffer)) + byte *buffer = file->request_pos; + if (!(block_len = (ulong) (file->read_end - buffer))) return 0; lf_info = (LOAD_FILE_INFO*)file->arg; if (lf_info->last_pos_in_file != HA_POS_ERROR && @@ -1036,14 +1036,14 @@ int log_loaded_block(IO_CACHE* file) lf_info->last_pos_in_file = file->pos_in_file; if (lf_info->wrote_create_file) { - Append_block_log_event a(lf_info->thd, buffer, block_len); + Append_block_log_event a(lf_info->thd, (char*) buffer, block_len); mysql_bin_log.write(&a); } else { Create_file_log_event c(lf_info->thd,lf_info->ex,lf_info->db, lf_info->table_name, *lf_info->fields, - lf_info->handle_dup, buffer, + lf_info->handle_dup, (char*) buffer, block_len); mysql_bin_log.write(&c); lf_info->wrote_create_file = 1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ab74ee74171..a4be2567315 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3172,11 +3172,9 @@ option_value: } query_cache_type: - '0' { current_thd->query_cache_type = 0; } + NUM { current_thd->query_cache_type = set_zone(atoi($1.str),0,3); } | 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: |