From 13af39824030a675bf2188d3870e56197ef13425 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 15 Aug 2011 23:53:55 +0300 Subject: [PATCH 1/4] Fixed recovery crash lp:814806 "Unclean shutdown corrupted Aria table blocking startup" storage/maria/ma_recovery.c: Moved trman_init() before parse_checkpoint_record() as this calls trnman functions if we have to open tables. --- storage/maria/ma_recovery.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 8752f70668c..4263b0131a9 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -320,25 +320,32 @@ int maria_apply_log(LSN from_lsn, LSN end_lsn, skip_DDLs= skip_DDLs_arg; skipped_undo_phase= 0; + trnman_init(max_trid_in_control_file); + if (from_lsn == LSN_IMPOSSIBLE) { if (last_checkpoint_lsn == LSN_IMPOSSIBLE) { from_lsn= translog_first_lsn_in_log(); if (unlikely(from_lsn == LSN_ERROR)) + { + trnman_destroy(); goto err; + } } else { from_lsn= parse_checkpoint_record(last_checkpoint_lsn); if (from_lsn == LSN_ERROR) + { + trnman_destroy(); goto err; + } } } now= my_getsystime(); in_redo_phase= TRUE; - trnman_init(max_trid_in_control_file); if (run_redo_phase(from_lsn, end_lsn, apply)) { ma_message_no_user(0, "Redo phase failed"); From 8ce93bbd64a38514de82e73fade36ba703ada5dd Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 16 Aug 2011 12:32:06 +0300 Subject: [PATCH 2/4] Fixed bug that MAX_USER_CONNECTIONS was not working properly in all situations (which could cause aborted connects) thd->user_connect is now handled in thd->clenup() which will ensure that it works in all context (including slaves). I added also some DBUG_ASSERT() to ensure that things are working correctly. sql/sql_acl.cc: Reset thd->user_connect on failed check_for_max_user_connections() to ensure we don't decrement value twice. Removed not needed call to decrease_user_connections() as thd->cleanup() will now do it. sql/sql_class.cc: Call decrease_user_connections() in thd->cleanup() sql/sql_connect.cc: Ensure we don't allocate thd->user_connect twice. Simplify check_for_max_user_connections(). sql/sql_parse.cc: Ensure that thd->user_connect is handled properly in for 'change_user' command. --- sql/sql_acl.cc | 9 +++------ sql/sql_class.cc | 5 +++++ sql/sql_connect.cc | 16 ++++++++++++---- sql/sql_parse.cc | 3 +++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5eda8202f73..bea029b325b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8167,6 +8167,8 @@ bool acl_authenticate(THD *thd, uint connect_errors, max_user_connections) && check_for_max_user_connections(thd, thd->user_connect)) { + /* Ensure we don't decrement thd->user_connections->connections twice */ + thd->user_connect= 0; status_var_increment(denied_connections); DBUG_RETURN(1); // The error is set in check_for_max_user_connections() } @@ -8207,12 +8209,7 @@ bool acl_authenticate(THD *thd, uint connect_errors, if (mysql_change_db(thd, &mpvio.db, FALSE)) { /* mysql_change_db() has pushed the error message. */ - if (thd->user_connect) - { - status_var_increment(thd->status_var.access_denied_errors); - decrease_user_connections(thd->user_connect); - thd->user_connect= 0; - } + status_var_increment(thd->status_var.access_denied_errors); DBUG_RETURN(1); } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0db3ea22c78..1ba6b7131d9 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1080,6 +1080,11 @@ void THD::cleanup(void) lock=locked_tables; locked_tables=0; close_thread_tables(this); } + if (user_connect) + { + decrease_user_connections(user_connect); + user_connect= 0; // Safety + } wt_thd_destroy(&transaction.wt); #if defined(ENABLED_DEBUG_SYNC) diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index def0c8dd951..be53c60e8ca 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -49,6 +49,7 @@ int get_or_create_user_conn(THD *thd, const char *user, DBUG_ASSERT(user != 0); DBUG_ASSERT(host != 0); + DBUG_ASSERT(thd->user_connect == 0); user_len= strlen(user); temp_len= (strmov(strmov(temp_user, user)+1, host) - temp_user)+1; @@ -108,7 +109,7 @@ end: int check_for_max_user_connections(THD *thd, USER_CONN *uc) { - int error=0; + int error= 1; DBUG_ENTER("check_for_max_user_connections"); (void) pthread_mutex_lock(&LOCK_user_conn); @@ -116,7 +117,6 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) max_user_connections < (uint) uc->connections) { my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user); - error=1; goto end; } time_out_user_resource_limits(thd, uc); @@ -126,7 +126,6 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_user_connections", (long) uc->user_resources.user_conn); - error= 1; goto end; } if (uc->user_resources.conn_per_hour && @@ -135,10 +134,10 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc) my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_connections_per_hour", (long) uc->user_resources.conn_per_hour); - error=1; goto end; } uc->conn_per_hour++; + error= 0; end: if (error) @@ -1027,8 +1026,17 @@ void end_connection(THD *thd) { NET *net= &thd->net; plugin_thdvar_cleanup(thd); + if (thd->user_connect) + { + /* + We decrease this variable early to make it easy to log again quickly. + This code is not critical as we will in any case do this test + again in thd->cleanup() + */ decrease_user_connections(thd->user_connect); + thd->user_connect= 0; + } if (thd->killed || (net->error && net->vio != 0)) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c930eb0824a..0fdc0b1690c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1138,12 +1138,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Ensure we don't free security_ctx->user in case we have to revert */ thd->security_ctx->user= 0; + thd->user_connect= 0; if (acl_authenticate(thd, 0, packet_length)) { /* Free user if allocated by acl_authenticate */ x_free(thd->security_ctx->user); *thd->security_ctx= save_security_ctx; + if (thd->user_connect) + decrease_user_connections(thd->user_connect); thd->user_connect= save_user_connect; thd->reset_db(save_db, save_db_length); thd->variables.character_set_client= save_character_set_client; From a75dbb41586a6094bd05160f02b5189316914802 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 16 Aug 2011 13:06:07 +0300 Subject: [PATCH 3/4] If mysqld --log-warnings=3 or higher, then print all check and repair warnings for MyISAM tables to the log. This is useful when trying to find out why an automatic myisam repair failes. storage/myisam/ha_myisam.cc: If mysqld --log-warnings=3 or higher, then print all check and repair warnings for MyISAM tables to the error log. --- storage/myisam/ha_myisam.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index d19f9a18b11..e73eb545c3b 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -123,6 +123,9 @@ static void mi_check_print_msg(HA_CHECK *param, const char* msg_type, if (protocol->write()) sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", msgbuf); + else if (thd->variables.log_warnings > 2) + sql_print_error("%s", msgbuf); + #ifdef THREAD if (param->need_print_msg_lock) pthread_mutex_unlock(¶m->print_msg_mutex); From cea27d300236436cfc0a0fca6c0993c3867be8f6 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Tue, 16 Aug 2011 13:28:20 +0300 Subject: [PATCH 4/4] Fixed build failure in embedded library regarding that decrease_user_connections() was not declared --- sql/mysql_priv.h | 3 +++ sql/sql_acl.cc | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 38a29686906..22ce8547c96 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -809,6 +809,7 @@ inline bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *table_list) inline bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc) { return false; } +#define decrease_user_connections(X) do { } while(0) /* nothing */ #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ bool multi_update_precheck(THD *thd, TABLE_LIST *tables); @@ -1042,7 +1043,9 @@ bool init_new_connection_handler_thread(); void reset_mqh(LEX_USER *lu, bool get_them); bool check_mqh(THD *thd, uint check_command); void time_out_user_resource_limits(THD *thd, USER_CONN *uc); +#ifndef NO_EMBEDDED_ACCESS_CHECKS void decrease_user_connections(USER_CONN *uc); +#endif bool thd_init_client_charset(THD *thd, uint cs_number); inline bool is_supported_parser_charset(CHARSET_INFO *cs) { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index bea029b325b..0b97cd69559 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -6977,7 +6977,6 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, #undef HAVE_OPENSSL #ifdef NO_EMBEDDED_ACCESS_CHECKS #define initialized 0 -#define decrease_user_connections(X) /* nothing */ #define check_for_max_user_connections(X,Y) 0 #define get_or_create_user_conn(A,B,C,D) 0 #endif