diff options
-rw-r--r-- | dbug/dbug.c | 28 | ||||
-rw-r--r-- | include/my_sys.h | 4 | ||||
-rw-r--r-- | mysql-test/r/multi_update.result | 27 | ||||
-rw-r--r-- | mysql-test/r/rpl000015.result | 6 | ||||
-rw-r--r-- | mysql-test/t/multi_update.test | 11 | ||||
-rw-r--r-- | mysql-test/t/rpl000014.test | 1 | ||||
-rw-r--r-- | mysql-test/t/rpl000015-slave-master-info.opt | 2 | ||||
-rw-r--r-- | mysql-test/t/rpl000015.test | 1 | ||||
-rw-r--r-- | mysys/my_static.h | 6 | ||||
-rw-r--r-- | mysys/my_thr_init.c | 39 | ||||
-rw-r--r-- | mysys/safemalloc.c | 70 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/log.cc | 1 | ||||
-rw-r--r-- | sql/log_event.cc | 3 | ||||
-rw-r--r-- | sql/mysqld.cc | 24 | ||||
-rw-r--r-- | sql/slave.cc | 10 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_repl.cc | 47 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 16 |
20 files changed, 273 insertions, 28 deletions
diff --git a/dbug/dbug.c b/dbug/dbug.c index 9e1e51d2404..8f214bfbe7c 100644 --- a/dbug/dbug.c +++ b/dbug/dbug.c @@ -21,7 +21,8 @@ * all copies and derivative works. Thank you. * * * * The author makes no warranty of any kind with respect to this * - * product and explicitly disclaims any implied warranties of mer- * + * product and explicitly disclaims any implied warranties of mer- *ct_lex.table_list.first=0; + thd->lex.selec * chantability or fitness for any particular purpose. * * * ****************************************************************************** @@ -58,7 +59,7 @@ * seismo!bpa!sjuvax!bbanerje * * Michael Widenius: - * DBUG_DUMP - To dump a pice of memory. + * DBUG_DUMP - To dump a block of memory. * PUSH_FLAG "O" - To be used insted of "o" if we don't * want flushing (for slow systems) * PUSH_FLAG "A" - as 'O', but we will append to the out file instead @@ -707,7 +708,13 @@ char ***_sframep_ __attribute__((unused))) int save_errno=errno; if (!init_done) _db_push_ (_DBUG_START_CONDITION_); - state=code_state(); + /* Sasha: the test below is so we could call functions with DBUG_ENTER + before my_thread_init(). I needed this because I suspected corruption + of a block allocated by my_thread_init() itself, so I wanted to use + my_malloc()/my_free() in my_thread_init()/my_thread_end() + */ + if (!(state=code_state())) + return; *_sfunc_ = state->func; *_sfile_ = state->file; @@ -855,6 +862,9 @@ uint _line_, const char *keyword) { CODE_STATE *state=code_state(); + /* Sasha: pre-my_thread_init() safety */ + if (!state) + return; state->u_line = _line_; state->u_keyword = (char*) keyword; } @@ -890,7 +900,9 @@ void _db_doprnt_ (const char *format,...) { va_list args; CODE_STATE *state; - state=code_state(); + /* Sasha: pre-my_thread_init() safety */ + if (!(state=code_state())) + return; va_start(args,format); @@ -942,7 +954,9 @@ uint length) int pos; char dbuff[90]; CODE_STATE *state; - state=code_state(); + /* Sasha: pre-my_thread_init() safety */ + if (!(state=code_state())) + return; if (_db_keyword_ ((char*) keyword)) { @@ -1224,7 +1238,9 @@ const char *keyword) if (!init_done) _db_push_ (""); - state=code_state(); + /* Sasha: pre-my_thread_init() safety */ + if (!(state=code_state())) + return FALSE; result = FALSE; if (DEBUGGING && state->level <= stack -> maxdepth && diff --git a/include/my_sys.h b/include/my_sys.h index 4aee27e2939..3950bfce758 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -137,6 +137,10 @@ extern int NEAR my_errno; /* Last error in mysys */ #define NORMAL_SAFEMALLOC sf_malloc_quick=0 extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick; extern ulonglong safemalloc_mem_limit; +/* keep track of shutdown,signal, and main threads so that my_end() will not + report errors with them +*/ +extern pthread_t shutdown_th, main_th,signal_th; #define CALLER_INFO_PROTO , const char *sFile, uint uLine #define CALLER_INFO , __FILE__, __LINE__ #define ORIG_CALLER_INFO , sFile, uLine diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index b1423667c44..85819d9571d 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -2,7 +2,34 @@ drop table if exists t1,t2,t3; create table t1(id1 int not null auto_increment primary key, t char(12)); create table t2(id2 int not null, t char(12)); create table t3(id3 int not null, t char(12), index(id3)); +select count(*) from t1 where id1 > 95; +count(*) +5 +select count(*) from t2 where id2 > 95; +count(*) +25 +select count(*) from t3 where id3 > 95; +count(*) +250 update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90; +select count(*) from t1 where t = "aaa"; +count(*) +10 +select count(*) from t1 where id1 > 90; +count(*) +10 +select count(*) from t2 where t = "bbb"; +count(*) +10 +select count(*) from t2 where id2 > 90; +count(*) +50 +select count(*) from t3 where t = "cc"; +count(*) +500 +select count(*) from t3 where id3 > 90; +count(*) +500 delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95; check table t1, t2, t3; Table Op Msg_type Msg_text diff --git a/mysql-test/r/rpl000015.result b/mysql-test/r/rpl000015.result index 03370bc6b0d..1546e5eb48d 100644 --- a/mysql-test/r/rpl000015.result +++ b/mysql-test/r/rpl000015.result @@ -9,16 +9,16 @@ Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Lo change master to master_host='127.0.0.1'; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos -127.0.0.1 test MASTER_PORT 60 4 slave-relay-bin.001 4 No No 0 0 0 +127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos -127.0.0.1 root MASTER_PORT 60 4 slave-relay-bin.001 4 No No 0 0 0 +127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.001 4 No No 0 0 0 slave start; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos -127.0.0.1 root MASTER_PORT 60 master-bin.001 79 slave-relay-bin.001 120 master-bin.001 Yes Yes 0 0 79 +127.0.0.1 root MASTER_PORT 7 master-bin.001 79 slave-relay-bin.001 120 master-bin.001 Yes Yes 0 0 79 drop table if exists t1; create table t1 (n int); insert into t1 values (10),(45),(90); diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 11697f794a9..c16189168d2 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -29,7 +29,18 @@ while ($1) dec $1; } enable_query_log; + +select count(*) from t1 where id1 > 95; +select count(*) from t2 where id2 > 95; +select count(*) from t3 where id3 > 95; + update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90; +select count(*) from t1 where t = "aaa"; +select count(*) from t1 where id1 > 90; +select count(*) from t2 where t = "bbb"; +select count(*) from t2 where id2 > 90; +select count(*) from t3 where t = "cc"; +select count(*) from t3 where id3 > 90; delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95; check table t1, t2, t3; diff --git a/mysql-test/t/rpl000014.test b/mysql-test/t/rpl000014.test index a673a23dde2..df15fa6e600 100644 --- a/mysql-test/t/rpl000014.test +++ b/mysql-test/t/rpl000014.test @@ -8,6 +8,7 @@ sync_with_master; show slave status; change master to master_log_pos=73; slave stop; + change master to master_log_pos=73; --replace_result 3306 MASTER_PORT 9306 MASTER_PORT 3334 MASTER_PORT 3336 MASTER_PORT show slave status; diff --git a/mysql-test/t/rpl000015-slave-master-info.opt b/mysql-test/t/rpl000015-slave-master-info.opt index 80190bf6d29..28bc753dd56 100644 --- a/mysql-test/t/rpl000015-slave-master-info.opt +++ b/mysql-test/t/rpl000015-slave-master-info.opt @@ -1 +1 @@ ---server-id=2 +--server-id=22 --master-connect-retry=7 diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test index 8fd04613ab8..c42e14699c5 100644 --- a/mysql-test/t/rpl000015.test +++ b/mysql-test/t/rpl000015.test @@ -8,6 +8,7 @@ connection slave; reset slave; --replace_result $MASTER_MYPORT MASTER_PORT show slave status; + change master to master_host='127.0.0.1'; # The following needs to be cleaned up when change master is fixed --replace_result $MASTER_MYPORT MASTER_PORT 3306 MASTER_PORT 3334 MASTER_PORT diff --git a/mysys/my_static.h b/mysys/my_static.h index 4f944938b8d..ca384009063 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -38,6 +38,7 @@ struct irem { my_string _sFileName; /* File in which memory was new'ed */ uint _uLineNum; /* Line number in above file */ uint _uDataSize; /* Size requested */ + pthread_t thread_id; long _lSpecialValue; /* Underrun marker value */ }; @@ -56,6 +57,11 @@ extern const char *soundex_map; extern USED_MEM* my_once_root_block; extern uint my_once_extra; +/* these threads are exept from safemalloc leak scrutiny unless + PEDANTIC_SAFEMALLOC is defined +*/ +extern pthread_t signal_thread,kill_thread; + #ifndef HAVE_TEMPNAM extern int _my_tempnam_used; #endif diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index b4d98feeeb6..2c7fd098c63 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -105,19 +105,33 @@ static long thread_id=0; my_bool my_thread_init(void) { struct st_my_thread_var *tmp; +#ifdef EXTRA_DEBUG + fprintf(stderr,"my_thread_init(): thread_id=%ld\n",pthread_self()); +#endif #if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX) pthread_mutex_lock(&THR_LOCK_lock); #endif #if !defined(__WIN__) || defined(USE_TLS) if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys)) { +#ifdef EXTRA_DEBUG + fprintf(stderr,"my_thread_init() called more than once in thread %ld\n", + pthread_self()); +#endif pthread_mutex_unlock(&THR_LOCK_lock); return 0; /* Safequard */ } /* We must have many calloc() here because these are freed on pthread_exit */ + /* + Sasha: the above comment does not make sense. I have changed calloc() to + equivalent my_malloc() but it was calloc() before. It seems like the + comment is out of date - we always call my_thread_end() before + pthread_exit() to clean up. Note that I have also fixed up DBUG + code to be able to call it from my_thread_init() + */ if (!(tmp=(struct st_my_thread_var *) - calloc(1,sizeof(struct st_my_thread_var)))) + my_malloc(sizeof(struct st_my_thread_var),MYF(MY_WME|MY_ZEROFILL)))) { pthread_mutex_unlock(&THR_LOCK_lock); return 1; @@ -125,6 +139,9 @@ my_bool my_thread_init(void) pthread_setspecific(THR_KEY_mysys,tmp); #else + /* Sasha: TODO - explain what exactly we are doing on Windows + At first glance, I have a hard time following the code + */ if (THR_KEY_mysys.id) /* Already initialized */ { #if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX) @@ -146,9 +163,18 @@ my_bool my_thread_init(void) void my_thread_end(void) { struct st_my_thread_var *tmp=my_thread_var; +#ifdef EXTRA_DEBUG + fprintf(stderr,"my_thread_end(): tmp=%p,thread_id=%ld\n", + tmp,pthread_self()); +#endif if (tmp) { #if !defined(DBUG_OFF) + /* Sasha: tmp->dbug is allocated inside DBUG library + so for now we will not mess with trying to use my_malloc()/ + my_free(), but in the future it would be nice to figure out a + way to do it + */ if (tmp->dbug) { free(tmp->dbug); @@ -160,12 +186,15 @@ void my_thread_end(void) #endif pthread_mutex_destroy(&tmp->mutex); #if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS) - free(tmp); + /* we need to setspecific to 0 BEFORE we call my_free, as my_free + uses some DBUG_ macros that will use the follow the specific + pointer after the block it is pointing to has been freed if + specific does not get reset first + */ + pthread_setspecific(THR_KEY_mysys,0); + my_free((gptr)tmp,MYF(MY_WME)); #endif } -#if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS) - pthread_setspecific(THR_KEY_mysys,0); -#endif } struct st_my_thread_var *_my_thread_var(void) diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index d8c089c2ff0..062f9b9db02 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -73,14 +73,25 @@ #include "mysys_err.h" ulonglong safemalloc_mem_limit = ~(ulonglong)0; +pthread_t shutdown_th=0,main_th=0,signal_th=0; #define pNext tInt._pNext #define pPrev tInt._pPrev #define sFileName tInt._sFileName #define uLineNum tInt._uLineNum #define uDataSize tInt._uDataSize +#define thread_id tInt.thread_id #define lSpecialValue tInt._lSpecialValue +#ifndef PEDANTIC_SAFEMALLOC +static int sf_malloc_tampered = 0; /* set to 1 after TERMINATE() if we had + to fiddle with cNewCount and the linked + list of blocks so that _sanity() will + not fuss when it is not supposed to + */ +#endif + + /* Static functions prototypes */ static int check_ptr(const char *where, byte *ptr, const char *sFile, @@ -174,6 +185,7 @@ gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags) pTmp -> sFileName = (my_string) sFile; pTmp -> uLineNum = uLine; pTmp -> uDataSize = uSize; + pTmp->thread_id = pthread_self(); pTmp -> pPrev = NULL; /* Add this remember structure to the linked list */ @@ -359,6 +371,12 @@ static int check_ptr(const char *where, byte *ptr, const char *sFile, return 0; } +static int legal_leak(struct remember* pPtr) +{ + return pthread_self() == pPtr->thread_id || main_th == pPtr->thread_id + || shutdown_th == pPtr->thread_id + || signal_th == pPtr->thread_id; +} /* * TERMINATE(FILE *file) @@ -376,6 +394,47 @@ void TERMINATE (FILE *file) /* NEW and the number of calls to FREE. >0 means more */ /* NEWs than FREEs. <0, etc. */ +#ifndef PEDANTIC_SAFEMALLOC + /* Avoid false alarms for blocks that we cannot free before my_end() + This does miss some positives, but that is ok. This will only miss + failures to free things allocated in the main thread which + performs only one-time allocations. If you really need to + debug memory allocations in the main thread, + #define PEDANTIC_SAFEMALLOC + */ + if ((pPtr=pRememberRoot)) + { + while (pPtr) + { + if (legal_leak(pPtr)) + { + sf_malloc_tampered=1; + cNewCount--; + lCurMemory -= pPtr->uDataSize; + if (pPtr->pPrev) + { + struct remember* tmp; + tmp = pPtr->pPrev->pNext = pPtr->pNext; + if (tmp) + tmp->pPrev = pPtr->pPrev; + pPtr->pNext = pPtr->pPrev = 0; + pPtr = tmp; + } + else + { + pRememberRoot = pPtr->pNext; + pPtr->pNext = pPtr->pPrev = 0; + pPtr = pRememberRoot; + if (pPtr) + pPtr->pPrev=0; + } + } + else + pPtr = pPtr->pNext; + } + } +#endif + if (cNewCount) { if (file) @@ -402,10 +461,14 @@ void TERMINATE (FILE *file) if (file) { fprintf (file, - "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'\n", + "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'", pPtr -> uDataSize, (ulong) &(pPtr -> aData[sf_malloc_prehunc]), pPtr -> uLineNum, pPtr -> sFileName); +#ifdef THREAD + fprintf(file, " in thread %ld", pPtr->thread_id); +#endif + fprintf(file, "\n"); (void) fflush(file); } DBUG_PRINT("safe", @@ -484,6 +547,10 @@ int _sanity (const char *sFile, uint uLine) uint count=0; pthread_mutex_lock(&THR_LOCK_malloc); +#ifndef PEDANTIC_SAFEMALLOC + if (sf_malloc_tampered && cNewCount < 0) + cNewCount=0; +#endif count=cNewCount; for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext) flag+=_checkchunk (pTmp, sFile, uLine); @@ -492,6 +559,7 @@ int _sanity (const char *sFile, uint uLine) { const char *format="Safemalloc link list destroyed, discovered at '%s:%d'"; fprintf (stderr, format, sFile, uLine); fputc('\n',stderr); + fprintf (stderr, "root=%p,count=%d,pTmp=%p\n", pRememberRoot,count,pTmp); (void) fflush(stderr); DBUG_PRINT("safe",(format, sFile, uLine)); flag=1; diff --git a/sql/lex.h b/sql/lex.h index 10c1ad766d5..8c7beb64b9b 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -280,6 +280,8 @@ static SYMBOL symbols[] = { { "READ", SYM(READ_SYM),0,0}, { "REAL", SYM(REAL),0,0}, { "REFERENCES", SYM(REFERENCES),0,0}, + { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM),0,0}, + { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM),0,0}, { "RELOAD", SYM(RELOAD),0,0}, { "REGEXP", SYM(REGEXP),0,0}, { "RENAME", SYM(RENAME),0,0}, diff --git a/sql/log.cc b/sql/log.cc index 1052b3379b3..dc6b1d35cef 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -479,6 +479,7 @@ err: rli->relay_log_pos = 4; strnmov(rli->relay_log_name,rli->linfo.log_file_name, sizeof(rli->relay_log_name)); + flush_relay_log_info(rli); } /* No need to free io_buf because we allocated both fname and io_buf in diff --git a/sql/log_event.cc b/sql/log_event.cc index 528110deb74..8db10a84661 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1607,7 +1607,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) { mysql_parse(thd, thd->query, q_len); if (expected_error != - (actual_error = thd->net.last_errno) && expected_error) + (actual_error = thd->net.last_errno) && expected_error && + !ignored_error_code(actual_error)) { const char* errmsg = "Slave: did not get the expected error\ running query from master - expected: '%s' (%d), got '%s' (%d)"; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d33ec9b92ca..a0154f980f1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -38,7 +38,17 @@ #define ONE_THREAD #endif -/* do stack traces are only supported on linux intel */ +#ifdef SAFEMALLOC +#define SHUTDOWN_THD shutdown_th=pthread_self(); +#define MAIN_THD main_th=pthread_self(); +#define SIGNAL_THD signal_th=pthread_self(); +#else +#define SHUTDOWN_THD +#define MAIN_THD +#define SIGNAL_THD +#endif + +/* stack traces are only supported on linux intel */ #if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK) #define HAVE_STACK_TRACE_ON_SEGV #include "../pstack/pstack.h" @@ -701,6 +711,7 @@ static void __cdecl kill_server(int sig_ptr) sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */ #if defined(USE_ONE_SIGNAL_HAND) && !defined(__WIN__) && !defined(OS2) + SHUTDOWN_THD; my_thread_init(); // If this is a new thread #endif close_connections(); @@ -716,6 +727,7 @@ static void __cdecl kill_server(int sig_ptr) #ifdef USE_ONE_SIGNAL_HAND static pthread_handler_decl(kill_server_thread,arg __attribute__((unused))) { + SHUTDOWN_THD; my_thread_init(); // Initialize new thread kill_server(0); my_thread_end(); // Normally never reached @@ -1262,6 +1274,7 @@ static void init_signals(void) signal(SIGALRM, SIG_IGN); signal(SIGBREAK,SIG_IGN); signal_thread = pthread_self(); + SIGNAL_THD; } static void start_signal_handler(void) @@ -1387,6 +1400,7 @@ static void init_signals(void) sigaction(SIGBUS, &sa, NULL); #endif sigaction(SIGILL, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); } (void) sigemptyset(&set); #ifdef THREAD_SPECIFIC_SIGPIPE @@ -1454,7 +1468,7 @@ static void *signal_hand(void *arg __attribute__((unused))) int sig; my_thread_init(); // Init new thread DBUG_ENTER("signal_hand"); - + SIGNAL_THD; /* Setup alarm handler */ init_thr_alarm(max_connections+max_insert_delayed_threads); #if SIGINT != THR_KILL_SIGNAL @@ -1509,7 +1523,10 @@ static void *signal_hand(void *arg __attribute__((unused))) else while ((error=my_sigwait(&set,&sig)) == EINTR) ; if (cleanup_done) + { + my_thread_end(); pthread_exit(0); // Safety + } switch (sig) { case SIGTERM: case SIGQUIT: @@ -1603,6 +1620,7 @@ int uname(struct utsname *a) pthread_handler_decl(handle_shutdown,arg) { MSG msg; + SHUTDOWN_THD; my_thread_init(); /* this call should create the message queue for this thread */ @@ -1629,6 +1647,7 @@ int __stdcall handle_kill(ulong ctrl_type) #ifdef OS2 pthread_handler_decl(handle_shutdown,arg) { + SHUTDOWN_THD; my_thread_init(); // wait semaphore @@ -1700,6 +1719,7 @@ int main(int argc, char **argv) my_umask=0660; // Default umask for new files my_umask_dir=0700; // Default umask for new directories + MAIN_THD; MY_INIT(argv[0]); // init my_sys library & pthreads tzset(); // Set tzname diff --git a/sql/slave.cc b/sql/slave.cc index 176f5db2f79..9050bf7362f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -345,7 +345,13 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, } } DBUG_ASSERT(thd != 0); - KICK_SLAVE(thd); + /* is is criticate to test if the slave is running. Otherwise, we might + be referening freed memory trying to kick it + */ + if (*slave_running) + { + KICK_SLAVE(thd); + } while (*slave_running) { /* there is a small chance that slave thread might miss the first @@ -367,7 +373,9 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, DBUG_ASSERT_LOCK(cond_lock); pthread_cond_timedwait(term_cond, cond_lock, &abstime); if (*slave_running) + { KICK_SLAVE(thd); + } } if (term_lock) pthread_mutex_unlock(term_lock); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 43195bc908b..42a8a700da3 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -151,6 +151,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE); lex->slave_thd_opt=0; + bzero(&lex->mi,sizeof(lex->mi)); return lex; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ecfb3dec99c..6961ab8c712 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -98,6 +98,8 @@ typedef struct st_lex_master_info uint port, connect_retry; ulonglong pos; ulong server_id; + char* relay_log_name; + ulong relay_log_pos; } LEX_MASTER_INFO; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index c6384817512..bbe92f3e526 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -690,6 +690,7 @@ int change_master(THD* thd, MASTER_INFO* mi) { int error=0,restart_thread_mask; const char* errmsg=0; + bool need_relay_log_purge=1; // kill slave thread lock_slave_threads(mi); @@ -742,17 +743,47 @@ int change_master(THD* thd, MASTER_INFO* mi) if (lex_mi->connect_retry) mi->connect_retry = lex_mi->connect_retry; + if (lex_mi->relay_log_name) + { + need_relay_log_purge = 0; + strnmov(mi->rli.relay_log_name,lex_mi->relay_log_name, + sizeof(mi->rli.relay_log_name)); + } + + if (lex_mi->relay_log_pos) + { + need_relay_log_purge=0; + mi->rli.relay_log_pos=lex_mi->relay_log_pos; + } + flush_master_info(mi); - pthread_mutex_unlock(&mi->data_lock); - thd->proc_info="purging old relay logs"; - if (purge_relay_logs(&mi->rli,0 /* not only reset, but also reinit*/, - &errmsg)) + if (need_relay_log_purge) { - send_error(&thd->net, 0, "Failed purging old relay logs"); - unlock_slave_threads(mi); - return 1; + pthread_mutex_unlock(&mi->data_lock); + thd->proc_info="purging old relay logs"; + if (purge_relay_logs(&mi->rli,0 /* not only reset, but also reinit*/, + &errmsg)) + { + send_error(&thd->net, 0, "Failed purging old relay logs"); + unlock_slave_threads(mi); + return 1; + } + pthread_mutex_lock(&mi->rli.data_lock); + } + else + { + const char* msg; + if (init_relay_log_pos(&mi->rli,0/*log already inited*/, + 0 /*pos already inited*/, + 0 /*no data lock*/, + &msg)) + { + net_printf(&thd->net,0,"Failed initializing relay log position: %s",msg); + unlock_slave_threads(mi); + return 1; + } + } - pthread_mutex_lock(&mi->rli.data_lock); mi->rli.master_log_pos = mi->master_log_pos; strnmov(mi->rli.master_log_name,mi->master_log_name, sizeof(mi->rli.master_log_name)); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 00330c7cab7..8012768e508 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -241,6 +241,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MASTER_PORT_SYM %token MASTER_CONNECT_RETRY_SYM %token MASTER_SERVER_ID_SYM +%token RELAY_LOG_FILE_SYM +%token RELAY_LOG_POS_SYM %token MATCH %token MAX_ROWS %token MAX_QUERIES_PER_HOUR @@ -701,6 +703,16 @@ master_def: { Lex->mi.connect_retry = $3; } + | + RELAY_LOG_FILE_SYM EQ TEXT_STRING + { + Lex->mi.relay_log_name = $3.str; + } + | + RELAY_LOG_POS_SYM EQ ULONG_NUM + { + Lex->mi.relay_log_pos = $3; + } /* create a table */ @@ -3013,6 +3025,7 @@ keyword: | ISSUER_SYM {} | INNOBASE_SYM {} | INSERT_METHOD {} + | IO_THREAD {} | LAST_SYM {} | LEVEL_SYM {} | LOCAL_SYM {} @@ -3055,6 +3068,8 @@ keyword: | RAID_CHUNKSIZE {} | RAID_STRIPED_SYM {} | RAID_TYPE {} + | RELAY_LOG_FILE_SYM {} + | RELAY_LOG_POS_SYM {} | RELOAD {} | REPAIR {} | REPEATABLE_SYM {} @@ -3074,6 +3089,7 @@ keyword: | SQL_CACHE_SYM {} | SQL_NO_CACHE_SYM {} | SQL_QUERY_CACHE_TYPE_SYM {} + | SQL_THREAD {} | START_SYM {} | STATUS_SYM {} | STOP_SYM {} |