From 44f65c246d80de4518e8d74359159b14a1ef3bd4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 26 Sep 2003 22:56:13 +0200 Subject: [PATCH] A fix of the fix for BUG#1209 (was: SELECT DATABASE() still shows dropped database). Don't free the client's selected db (thd->db) when it has been DROPped, if this is a slave thread; the x_free() was causing a lot of various bugs in rpl_loaddata_rule_m (garbage characters, segfault, hangs in other threads). A small post-merge fix (rli->inside_transaction exists in 4.0 only). sql/log_event.cc: Post-merge fix (rli->inside_transaction existed in 4.0 only) sql/sql_db.cc: Don't free the client's selected db (thd->db) when it has been DROPped, if this is a slave thread; the x_free() was causing a lot of various bugs in rpl_loaddata_rule_m which does a DROP DATABASE (garbage characters, segfault, hangs in other threads). --- sql/log_event.cc | 11 +++++++---- sql/sql_db.cc | 26 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index eee5be4c40f..b6964c40422 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1876,19 +1876,22 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) pthread_mutex_lock(&rli->data_lock); -#ifdef TO_BE_CHECKED_BY_GUILHEM - if (rli->inside_transaction) + if (thd->options & OPTION_BEGIN) { slave_print_error(rli, 0, + opt_using_transactions ? "\ There is an unfinished transaction in the relay log (could find neither \ COMMIT nor ROLLBACK in the relay log); It could be that the master died while \ writing the transaction to its binary log. Now the slave is rolling back the \ -transaction."); +transaction." : + "\ +There is an unfinished transaction in the relay log (could find neither \ +COMMIT nor ROLLBACK in the relay log); It could be that the master died while \ +writing the transaction to its binary log."); pthread_mutex_unlock(&rli->data_lock); DBUG_RETURN(1); } -#endif memcpy(log_name, new_log_ident, ident_len+1); rli->notify_group_master_log_name_update(); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 2b42c2c9a5b..2ba7f73ba80 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -391,10 +391,32 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) exit: start_waiting_global_read_lock(thd); + /* + If this database was the client's selected database, we silently change the + client's selected database to nothing (to have an empty SELECT DATABASE() in + the future). For this we free() thd->db and set it to 0. But we don't do + free() for the slave thread. Indeed, doing a x_free() on it leads to nasty + problems (i.e. long painful debugging) because in this thread, thd->db is + the same as data_buf and db of the Query_log_event which is dropping the + database. So if you free() thd->db, you're freeing data_buf. You set thd->db + to 0 but not data_buf (thd->db and data_buf are two distinct pointers which + point to the same place). Then in ~Query_log_event(), we have + 'if (data_buf) free(data_buf)' + data_buf is !=0 so this makes a DOUBLE free(). + Side effects of this double free() are, randomly (depends on the machine), + when the slave is replicating a DROP DATABASE: + - garbage characters in the error message: + "Error 'Can't drop database 'test2'; database doesn't exist' on query + 'h4zIż'" + - segfault + - hang in "free(vio)" (yes!) in the I/O or SQL slave threads (so slave + server hangs at shutdown etc). + */ if (thd->db && !strcmp(thd->db, db)) { - x_free(thd->db); - thd->db= 0; + if (!(thd->slave_thread)) /* a slave thread will free it itself */ + x_free(thd->db); + thd->db= 0; } exit2: VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));