mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-13179 main.errors fails with wrong errno
The problem was that the introduction of max-thread-mem-used can cause an allocation error very early, even before mysql_parse() is called. As mysql_parse() calls thd->reset_for_next_command(), which called clear_error(), the error number was lost. Fixed by adding an option to have unique messages for each KILL signal and change max-thread-mem-used to use this new feature. This removes a lot of problems with the original approach, where one could get errors signaled silenty almost any time. ixed by moving clear_error() from reset_for_next_command() to do_command(), before any memory allocation for the thread. Related changes: - reset_for_next_command() now have an optional parameter if we should call clear_error() or not. By default it's called, but not anymore from dispatch_command() which was the original problem. - Added optional paramater to clear_error() to force calling of reset_diagnostics_area(). Before clear_error() only called reset_diagnostics_area() if there was no error, so we normally called reset_diagnostics_area() twice. - This change removed several duplicated calls to clear_error() when starting a query. - Reset max_mem_used on COM_QUIT, to protect against kill during quit. - Use fatal_error() instead of setting is_fatal_error (cleanup) - Set fatal_error if max_thead_mem_used is signaled. (Same logic we use for other places where we are out of resources)
This commit is contained in:
@ -333,7 +333,7 @@ void thd_set_psi(THD *thd, PSI_thread *psi)
|
||||
*/
|
||||
void thd_set_killed(THD *thd)
|
||||
{
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -935,6 +935,7 @@ THD::THD(bool is_wsrep_applier)
|
||||
query_start_used= query_start_sec_part_used= 0;
|
||||
count_cuted_fields= CHECK_FIELD_IGNORE;
|
||||
killed= NOT_KILLED;
|
||||
killed_err= 0;
|
||||
col_access=0;
|
||||
is_slave_error= thread_specific_used= FALSE;
|
||||
my_hash_clear(&handler_tables_hash);
|
||||
@ -992,6 +993,7 @@ THD::THD(bool is_wsrep_applier)
|
||||
#endif
|
||||
mysql_mutex_init(key_LOCK_thd_data, &LOCK_thd_data, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_LOCK_wakeup_ready, &LOCK_wakeup_ready, MY_MUTEX_INIT_FAST);
|
||||
mysql_mutex_init(key_LOCK_thd_kill, &LOCK_thd_kill, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_COND_wakeup_ready, &COND_wakeup_ready, 0);
|
||||
/*
|
||||
LOCK_thread_count goes before LOCK_thd_data - the former is called around
|
||||
@ -1256,7 +1258,7 @@ Sql_condition* THD::raise_condition(uint sql_errno,
|
||||
push_warning and strict SQL_MODE case.
|
||||
*/
|
||||
level= Sql_condition::WARN_LEVEL_ERROR;
|
||||
killed= KILL_BAD_DATA;
|
||||
set_killed(KILL_BAD_DATA);
|
||||
}
|
||||
|
||||
switch (level)
|
||||
@ -1564,7 +1566,7 @@ void THD::cleanup(void)
|
||||
DBUG_ENTER("THD::cleanup");
|
||||
DBUG_ASSERT(cleanup_done == 0);
|
||||
|
||||
killed= KILL_CONNECTION;
|
||||
set_killed(KILL_CONNECTION);
|
||||
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
|
||||
if (transaction.xid_state.xa_state == XA_PREPARED)
|
||||
{
|
||||
@ -1667,6 +1669,7 @@ THD::~THD()
|
||||
mysql_cond_destroy(&COND_wakeup_ready);
|
||||
mysql_mutex_destroy(&LOCK_wakeup_ready);
|
||||
mysql_mutex_destroy(&LOCK_thd_data);
|
||||
mysql_mutex_destroy(&LOCK_thd_kill);
|
||||
#ifndef DBUG_OFF
|
||||
dbug_sentry= THD_SENTRY_GONE;
|
||||
#endif
|
||||
@ -1839,7 +1842,8 @@ void THD::awake(killed_state state_to_set)
|
||||
state_to_set= killed;
|
||||
|
||||
/* Set the 'killed' flag of 'this', which is the target THD object. */
|
||||
killed= state_to_set;
|
||||
mysql_mutex_lock(&LOCK_thd_kill);
|
||||
set_killed_no_mutex(state_to_set);
|
||||
|
||||
if (state_to_set >= KILL_CONNECTION || state_to_set == NOT_KILLED)
|
||||
{
|
||||
@ -1925,6 +1929,7 @@ void THD::awake(killed_state state_to_set)
|
||||
}
|
||||
mysql_mutex_unlock(&mysys_var->mutex);
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -1942,7 +1947,7 @@ void THD::disconnect()
|
||||
|
||||
mysql_mutex_lock(&LOCK_thd_data);
|
||||
|
||||
killed= KILL_CONNECTION;
|
||||
set_killed(KILL_CONNECTION);
|
||||
|
||||
#ifdef SIGNAL_WITH_VIO_CLOSE
|
||||
/*
|
||||
@ -1978,7 +1983,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
|
||||
DBUG_PRINT("info", ("kill delayed thread"));
|
||||
mysql_mutex_lock(&in_use->LOCK_thd_data);
|
||||
if (in_use->killed < KILL_CONNECTION)
|
||||
in_use->killed= KILL_CONNECTION;
|
||||
in_use->set_killed(KILL_CONNECTION);
|
||||
if (in_use->mysys_var)
|
||||
{
|
||||
mysql_mutex_lock(&in_use->mysys_var->mutex);
|
||||
@ -2031,13 +2036,21 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
|
||||
/*
|
||||
Get error number for killed state
|
||||
Note that the error message can't have any parameters.
|
||||
If one needs parameters, one should use THD::killed_err_msg
|
||||
See thd::kill_message()
|
||||
*/
|
||||
|
||||
int killed_errno(killed_state killed)
|
||||
int THD::killed_errno()
|
||||
{
|
||||
DBUG_ENTER("killed_errno");
|
||||
DBUG_PRINT("enter", ("killed: %d", killed));
|
||||
DBUG_PRINT("enter", ("killed: %d killed_errno: %d",
|
||||
killed, killed_err ? killed_err->no: 0));
|
||||
|
||||
/* Ensure that killed_err is not set if we are not killed */
|
||||
DBUG_ASSERT(!killed_err || killed != NOT_KILLED);
|
||||
|
||||
if (killed_err)
|
||||
DBUG_RETURN(killed_err->no);
|
||||
|
||||
switch (killed) {
|
||||
case NOT_KILLED:
|
||||
@ -2478,7 +2491,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
|
||||
{
|
||||
my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_FATALERROR),
|
||||
ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
|
||||
killed= KILL_CONNECTION;
|
||||
set_killed(KILL_CONNECTION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user