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:
parent
008786aedb
commit
74543698a7
@ -140,8 +140,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
|
||||
}
|
||||
|
||||
/* Clear result variables */
|
||||
thd->clear_error();
|
||||
thd->get_stmt_da()->reset_diagnostics_area();
|
||||
thd->clear_error(1);
|
||||
mysql->affected_rows= ~(my_ulonglong) 0;
|
||||
mysql->field_count= 0;
|
||||
net_clear_error(net);
|
||||
|
@ -168,7 +168,7 @@ UPDATE t1 SET a = 'new'
|
||||
WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL;
|
||||
ERROR 22007: Illegal value used as argument of dynamic column function
|
||||
drop table t1;
|
||||
set max_session_mem_used = 50000;
|
||||
select * from seq_1_to_1000;
|
||||
set max_session_mem_used = 8192;
|
||||
select * from seq_1_to_1000;
|
||||
Got one of the listed errors
|
||||
set global max_session_mem_used = default;
|
||||
|
@ -203,7 +203,13 @@ drop table t1;
|
||||
#
|
||||
# errors caused by max_session_mem_used
|
||||
#
|
||||
set max_session_mem_used = 8192;
|
||||
--error ER_SQL_DISCOVER_ERROR,ER_OPTION_PREVENTS_STATEMENT
|
||||
--disable_result_log
|
||||
set max_session_mem_used = 50000;
|
||||
--error 0,ER_OPTION_PREVENTS_STATEMENT
|
||||
select * from seq_1_to_1000;
|
||||
set global max_session_mem_used = default;
|
||||
set max_session_mem_used = 8192;
|
||||
--error 0,ER_OPTION_PREVENTS_STATEMENT
|
||||
select * from seq_1_to_1000;
|
||||
--enable_result_log
|
||||
# We may not be able to execute any more queries with this connection
|
||||
# because of too little memory#
|
||||
|
@ -1502,7 +1502,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
|
||||
{
|
||||
if (!--action->hit_limit)
|
||||
{
|
||||
thd->killed= KILL_QUERY;
|
||||
thd->set_killed(KILL_QUERY);
|
||||
my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0));
|
||||
}
|
||||
DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'",
|
||||
|
@ -371,12 +371,6 @@ static void pretty_print_str(IO_CACHE* cache, const char* str, int len)
|
||||
|
||||
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
||||
|
||||
static void clear_all_errors(THD *thd, Relay_log_info *rli)
|
||||
{
|
||||
thd->is_slave_error = 0;
|
||||
thd->clear_error();
|
||||
}
|
||||
|
||||
inline int idempotent_error_code(int err_code)
|
||||
{
|
||||
int ret= 0;
|
||||
@ -4255,7 +4249,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
|
||||
|
||||
DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
|
||||
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||
thd->clear_error(1);
|
||||
current_stmt_is_commit= is_commit();
|
||||
|
||||
DBUG_ASSERT(!current_stmt_is_commit || !rgi->tables_to_lock);
|
||||
@ -4475,7 +4469,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
|
||||
to check/fix it.
|
||||
*/
|
||||
if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); /* Can ignore query */
|
||||
thd->clear_error(1);
|
||||
else
|
||||
{
|
||||
rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
|
||||
@ -4556,7 +4550,7 @@ compare_errors:
|
||||
ignored_error_code(actual_error))
|
||||
{
|
||||
DBUG_PRINT("info",("error ignored"));
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||
thd->clear_error(1);
|
||||
if (actual_error == ER_QUERY_INTERRUPTED ||
|
||||
actual_error == ER_CONNECTION_KILLED)
|
||||
thd->reset_killed();
|
||||
@ -6025,8 +6019,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
|
||||
new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length);
|
||||
thd->set_db(new_db.str, new_db.length);
|
||||
DBUG_ASSERT(thd->query() == 0);
|
||||
thd->is_slave_error= 0;
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||
thd->clear_error(1);
|
||||
|
||||
/* see Query_log_event::do_apply_event() and BUG#13360 */
|
||||
DBUG_ASSERT(!rgi->m_table_map.count());
|
||||
@ -6036,7 +6029,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
|
||||
*/
|
||||
lex_start(thd);
|
||||
thd->lex->local_file= local_fname;
|
||||
thd->reset_for_next_command();
|
||||
thd->reset_for_next_command(0); // Errors are cleared above
|
||||
|
||||
/*
|
||||
We test replicate_*_db rules. Note that we have already prepared
|
||||
@ -10091,7 +10084,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
||||
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
|
||||
get_type_str(),
|
||||
RPL_LOG_NAME, (ulong) log_pos);
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||
thd->clear_error(1);
|
||||
error= 0;
|
||||
if (idempotent_error == 0)
|
||||
break;
|
||||
@ -10143,7 +10136,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
||||
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
|
||||
get_type_str(),
|
||||
RPL_LOG_NAME, (ulong) log_pos);
|
||||
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
|
||||
thd->clear_error(1);
|
||||
error= 0;
|
||||
}
|
||||
} // if (table)
|
||||
|
@ -878,7 +878,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
|
||||
key_LOCK_prepared_stmt_count,
|
||||
key_LOCK_rpl_status, key_LOCK_server_started,
|
||||
key_LOCK_status, key_LOCK_show_status,
|
||||
key_LOCK_system_variables_hash, key_LOCK_thd_data,
|
||||
key_LOCK_system_variables_hash, key_LOCK_thd_data, key_LOCK_thd_kill,
|
||||
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
|
||||
key_master_info_data_lock, key_master_info_run_lock,
|
||||
key_master_info_sleep_lock, key_master_info_start_stop_lock,
|
||||
@ -949,6 +949,7 @@ static PSI_mutex_info all_server_mutexes[]=
|
||||
{ &key_LOCK_wait_commit, "wait_for_commit::LOCK_wait_commit", 0},
|
||||
{ &key_LOCK_gtid_waiting, "gtid_waiting::LOCK_gtid_waiting", 0},
|
||||
{ &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
|
||||
{ &key_LOCK_thd_kill, "THD::LOCK_thd_kill", 0},
|
||||
{ &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_uuid_short_generator, "LOCK_uuid_short_generator", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
|
||||
@ -1650,7 +1651,7 @@ static void close_connections(void)
|
||||
if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier))
|
||||
continue;
|
||||
#endif
|
||||
tmp->killed= KILL_SERVER_HARD;
|
||||
tmp->set_killed(KILL_SERVER_HARD);
|
||||
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_data);
|
||||
if (tmp->mysys_var)
|
||||
@ -1738,7 +1739,7 @@ static void close_connections(void)
|
||||
if (WSREP(tmp) && tmp->wsrep_exec_mode==REPL_RECV)
|
||||
{
|
||||
sql_print_information("closing wsrep system thread");
|
||||
tmp->killed= KILL_CONNECTION;
|
||||
tmp->set_killed(KILL_CONNECTION);
|
||||
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
|
||||
if (tmp->mysys_var)
|
||||
{
|
||||
@ -3943,11 +3944,16 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific)
|
||||
thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used &&
|
||||
!thd->killed && !thd->get_stmt_da()->is_set())
|
||||
{
|
||||
char buf[1024];
|
||||
thd->killed= KILL_QUERY;
|
||||
/* Ensure we don't get called here again */
|
||||
char buf[50], *buf2;
|
||||
thd->set_killed(KILL_QUERY);
|
||||
my_snprintf(buf, sizeof(buf), "--max-thread-mem-used=%llu",
|
||||
thd->variables.max_mem_used);
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), buf);
|
||||
if ((buf2= (char*) thd->alloc(256)))
|
||||
{
|
||||
my_snprintf(buf2, 256, ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf);
|
||||
thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, buf2);
|
||||
}
|
||||
}
|
||||
DBUG_ASSERT((longlong) thd->status_var.local_memory_used >= 0);
|
||||
}
|
||||
@ -6318,7 +6324,7 @@ void create_thread_to_handle_connection(THD *thd)
|
||||
DBUG_PRINT("error",
|
||||
("Can't create thread to handle request (error %d)",
|
||||
error));
|
||||
thd->killed= KILL_CONNECTION; // Safety
|
||||
thd->set_killed(KILL_CONNECTION); // Safety
|
||||
mysql_mutex_unlock(&LOCK_thread_count);
|
||||
|
||||
mysql_mutex_lock(&LOCK_connection_count);
|
||||
|
@ -290,7 +290,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
|
||||
key_LOCK_prepared_stmt_count,
|
||||
key_LOCK_rpl_status, key_LOCK_server_started,
|
||||
key_LOCK_status, key_LOCK_show_status,
|
||||
key_LOCK_thd_data,
|
||||
key_LOCK_thd_data, key_LOCK_thd_kill,
|
||||
key_LOCK_user_conn, key_LOG_LOCK_log,
|
||||
key_master_info_data_lock, key_master_info_run_lock,
|
||||
key_master_info_sleep_lock, key_master_info_start_stop_lock,
|
||||
|
@ -714,9 +714,7 @@ do_retry:
|
||||
DBUG_EXECUTE_IF("inject_mdev8031", {
|
||||
/* Simulate that we get deadlock killed at this exact point. */
|
||||
rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
thd->killed= KILL_CONNECTION;
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
});
|
||||
rgi->cleanup_context(thd, 1);
|
||||
wait_for_pending_deadlock_kill(thd, rgi);
|
||||
@ -862,9 +860,7 @@ do_retry:
|
||||
/* Simulate that we get deadlock killed during open_binlog(). */
|
||||
thd->reset_for_next_command();
|
||||
rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
thd->killed= KILL_CONNECTION;
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
thd->send_kill_message();
|
||||
fd= (File)-1;
|
||||
err= 1;
|
||||
|
@ -331,8 +331,7 @@ bool sp_rcontext::handle_sql_condition(THD *thd,
|
||||
|
||||
/* Reset error state. */
|
||||
thd->clear_error();
|
||||
thd->killed= NOT_KILLED; // Some errors set thd->killed
|
||||
// (e.g. "bad data").
|
||||
thd->reset_killed(); // Some errors set thd->killed, (e.g. "bad data").
|
||||
|
||||
/* Add a frame to handler-call-stack. */
|
||||
Sql_condition_info *cond_info=
|
||||
|
@ -400,7 +400,7 @@ void kill_delayed_threads_for_table(TDC_element *element)
|
||||
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
|
||||
! in_use->killed)
|
||||
{
|
||||
in_use->killed= KILL_SYSTEM_THREAD;
|
||||
in_use->set_killed(KILL_SYSTEM_THREAD);
|
||||
mysql_mutex_lock(&in_use->mysys_var->mutex);
|
||||
if (in_use->mysys_var->current_cond)
|
||||
{
|
||||
@ -9136,7 +9136,7 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
|
||||
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
|
||||
!in_use->killed)
|
||||
{
|
||||
in_use->killed= KILL_SYSTEM_THREAD;
|
||||
in_use->set_killed(KILL_SYSTEM_THREAD);
|
||||
mysql_mutex_lock(&in_use->mysys_var->mutex);
|
||||
if (in_use->mysys_var->current_cond)
|
||||
{
|
||||
|
@ -2160,8 +2160,7 @@ lookup:
|
||||
response, we can't handle it anyway.
|
||||
*/
|
||||
(void) trans_commit_stmt(thd);
|
||||
if (!thd->get_stmt_da()->is_set())
|
||||
thd->get_stmt_da()->disable_status();
|
||||
thd->get_stmt_da()->disable_status();
|
||||
|
||||
BLOCK_UNLOCK_RD(query_block);
|
||||
MYSQL_QUERY_CACHE_HIT(thd->query(), (ulong) thd->limit_found_rows);
|
||||
@ -4615,7 +4614,7 @@ void Query_cache::wreck(uint line, const char *message)
|
||||
DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
|
||||
DBUG_PRINT("warning", ("=================================="));
|
||||
if (thd)
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
cache_dump();
|
||||
/* check_integrity(0); */ /* Can't call it here because of locks */
|
||||
bins_dump();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -482,7 +482,6 @@ enum killed_state
|
||||
KILL_SERVER_HARD= 15
|
||||
};
|
||||
|
||||
extern int killed_errno(killed_state killed);
|
||||
#define killed_mask_hard(killed) ((killed_state) ((killed) & ~KILL_HARD_BIT))
|
||||
|
||||
enum killed_type
|
||||
@ -1924,7 +1923,7 @@ public:
|
||||
rpl_sql_thread_info *rpl_sql_info;
|
||||
} system_thread_info;
|
||||
|
||||
void reset_for_next_command();
|
||||
void reset_for_next_command(bool do_clear_errors= 1);
|
||||
/*
|
||||
Constant for THD::where initialization in the beginning of every query.
|
||||
|
||||
@ -1980,6 +1979,8 @@ public:
|
||||
Is locked when THD is deleted.
|
||||
*/
|
||||
mysql_mutex_t LOCK_thd_data;
|
||||
/* Protect kill information */
|
||||
mysql_mutex_t LOCK_thd_kill;
|
||||
|
||||
/* all prepared statements and cursors of this connection */
|
||||
Statement_map stmt_map;
|
||||
@ -2615,7 +2616,7 @@ public:
|
||||
void check_limit_rows_examined()
|
||||
{
|
||||
if (++accessed_rows_and_keys > lex->limit_rows_examined_cnt)
|
||||
killed= ABORT_QUERY;
|
||||
set_killed(ABORT_QUERY);
|
||||
}
|
||||
|
||||
USER_CONN *user_connect;
|
||||
@ -2716,6 +2717,16 @@ public:
|
||||
*/
|
||||
killed_state volatile killed;
|
||||
|
||||
/*
|
||||
The following is used if one wants to have a specific error number and
|
||||
text for the kill
|
||||
*/
|
||||
struct err_info
|
||||
{
|
||||
int no;
|
||||
const char msg[256];
|
||||
} *killed_err;
|
||||
|
||||
/* See also thd_killed() */
|
||||
inline bool check_killed()
|
||||
{
|
||||
@ -3280,18 +3291,18 @@ public:
|
||||
@todo: To silence an error, one should use Internal_error_handler
|
||||
mechanism. Issuing an error that can be possibly later "cleared" is not
|
||||
compatible with other installed error handlers and audit plugins.
|
||||
In future this function will be removed.
|
||||
*/
|
||||
inline void clear_error()
|
||||
inline void clear_error(bool clear_diagnostics= 0)
|
||||
{
|
||||
DBUG_ENTER("clear_error");
|
||||
if (get_stmt_da()->is_error())
|
||||
if (get_stmt_da()->is_error() || clear_diagnostics)
|
||||
get_stmt_da()->reset_diagnostics_area();
|
||||
is_slave_error= 0;
|
||||
if (killed == KILL_BAD_DATA)
|
||||
killed= NOT_KILLED; // KILL_BAD_DATA can be reset w/o a mutex
|
||||
reset_killed();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
inline bool vio_ok() const { return net.vio != 0; }
|
||||
/** Return FALSE if connection to client is broken. */
|
||||
@ -3401,10 +3412,54 @@ public:
|
||||
state after execution of a non-prepared SQL statement.
|
||||
*/
|
||||
void end_statement();
|
||||
inline int killed_errno() const
|
||||
|
||||
/*
|
||||
Mark thread to be killed, with optional error number and string.
|
||||
string is not released, so it has to be allocted on thd mem_root
|
||||
or be a global string
|
||||
|
||||
Ensure that we don't replace a kill with a lesser one. For example
|
||||
if user has done 'kill_connection' we shouldn't replace it with
|
||||
KILL_QUERY.
|
||||
*/
|
||||
inline void set_killed(killed_state killed_arg,
|
||||
int killed_errno_arg= 0,
|
||||
const char *killed_err_msg_arg= 0)
|
||||
{
|
||||
return ::killed_errno(killed);
|
||||
mysql_mutex_lock(&LOCK_thd_kill);
|
||||
set_killed_no_mutex(killed_arg, killed_errno_arg, killed_err_msg_arg);
|
||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||
}
|
||||
/*
|
||||
This is only used by THD::awake where we need to keep the lock mutex
|
||||
locked over some time.
|
||||
It's ok to have this inline, as in most cases killed_errno_arg will
|
||||
be a constant 0 and most of the function will disappear.
|
||||
*/
|
||||
inline void set_killed_no_mutex(killed_state killed_arg,
|
||||
int killed_errno_arg= 0,
|
||||
const char *killed_err_msg_arg= 0)
|
||||
{
|
||||
if (killed <= killed_arg)
|
||||
{
|
||||
killed= killed_arg;
|
||||
if (killed_errno_arg)
|
||||
{
|
||||
/*
|
||||
If alloc fails, we only remember the killed flag.
|
||||
The worst things that can happen is that we get
|
||||
a suboptimal error message.
|
||||
*/
|
||||
if ((killed_err= (err_info*) alloc(sizeof(*killed_err))))
|
||||
{
|
||||
killed_err->no= killed_errno_arg;
|
||||
::strmake((char*) killed_err->msg, killed_err_msg_arg,
|
||||
sizeof(killed_err->msg)-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int killed_errno();
|
||||
inline void reset_killed()
|
||||
{
|
||||
/*
|
||||
@ -3413,9 +3468,10 @@ public:
|
||||
*/
|
||||
if (killed != NOT_KILLED)
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_thd_data);
|
||||
mysql_mutex_lock(&LOCK_thd_kill);
|
||||
killed= NOT_KILLED;
|
||||
mysql_mutex_unlock(&LOCK_thd_data);
|
||||
killed_err= 0;
|
||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||
}
|
||||
}
|
||||
inline void reset_kill_query()
|
||||
@ -3426,11 +3482,14 @@ public:
|
||||
mysys_var->abort= 0;
|
||||
}
|
||||
}
|
||||
inline void send_kill_message() const
|
||||
inline void send_kill_message()
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_thd_kill);
|
||||
int err= killed_errno();
|
||||
if (err)
|
||||
my_message(err, ER_THD(this, err), MYF(0));
|
||||
my_message(err, killed_err ? killed_err->msg : ER_THD(this, err),
|
||||
MYF(0));
|
||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||
}
|
||||
/* return TRUE if we will abort query if we make a warning now */
|
||||
inline bool really_abort_on_warning()
|
||||
|
@ -1196,7 +1196,7 @@ void prepare_new_connection_state(THD* thd)
|
||||
if (thd->is_error())
|
||||
{
|
||||
Host_errors errors;
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
thd->print_aborted_warning(0, "init_connect command failed");
|
||||
sql_print_warning("%s", thd->get_stmt_da()->message());
|
||||
|
||||
|
@ -2681,7 +2681,7 @@ void kill_delayed_threads(void)
|
||||
{
|
||||
mysql_mutex_lock(&di->thd.LOCK_thd_data);
|
||||
if (di->thd.killed < KILL_CONNECTION)
|
||||
di->thd.killed= KILL_CONNECTION;
|
||||
di->thd.set_killed(KILL_CONNECTION);
|
||||
if (di->thd.mysys_var)
|
||||
{
|
||||
mysql_mutex_lock(&di->thd.mysys_var->mutex);
|
||||
@ -2827,7 +2827,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
thd->set_current_time();
|
||||
threads.append(thd);
|
||||
if (abort_loop)
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
else
|
||||
thd->reset_killed();
|
||||
mysql_mutex_unlock(&LOCK_thread_count);
|
||||
@ -2972,7 +2972,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
}
|
||||
#endif
|
||||
if (error == ETIMEDOUT || error == ETIME)
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
}
|
||||
/* We can't lock di->mutex and mysys_var->mutex at the same time */
|
||||
mysql_mutex_unlock(&di->mutex);
|
||||
@ -3001,7 +3001,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, 0)))
|
||||
{
|
||||
/* Fatal error */
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
}
|
||||
mysql_cond_broadcast(&di->cond_client);
|
||||
}
|
||||
@ -3010,7 +3010,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
if (di->handle_inserts())
|
||||
{
|
||||
/* Some fatal error */
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
}
|
||||
}
|
||||
di->status=0;
|
||||
@ -3054,7 +3054,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
this.
|
||||
*/
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
thd->killed= KILL_CONNECTION_HARD; // If error
|
||||
thd->set_killed(KILL_CONNECTION_HARD); // If error
|
||||
thd->mdl_context.set_needs_thr_lock_abort(0);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
|
||||
@ -3143,7 +3143,7 @@ bool Delayed_insert::handle_inserts(void)
|
||||
max_rows= delayed_insert_limit;
|
||||
if (thd.killed || table->s->tdc->flushed)
|
||||
{
|
||||
thd.killed= KILL_SYSTEM_THREAD;
|
||||
thd.set_killed(KILL_SYSTEM_THREAD);
|
||||
max_rows= ULONG_MAX; // Do as much as possible
|
||||
}
|
||||
|
||||
|
@ -613,7 +613,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
||||
DBUG_EXECUTE_IF("simulate_kill_bug27571",
|
||||
{
|
||||
error=1;
|
||||
thd->killed= KILL_QUERY;
|
||||
thd->set_killed(KILL_QUERY);
|
||||
};);
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
@ -669,6 +669,7 @@ void execute_init_command(THD *thd, LEX_STRING *init_command,
|
||||
*/
|
||||
save_vio= thd->net.vio;
|
||||
thd->net.vio= 0;
|
||||
thd->clear_error(1);
|
||||
dispatch_command(COM_QUERY, thd, buf, len);
|
||||
thd->client_capabilities= save_client_capabilities;
|
||||
thd->net.vio= save_vio;
|
||||
@ -800,6 +801,7 @@ static void handle_bootstrap_impl(THD *thd)
|
||||
if (bootstrap_error)
|
||||
break;
|
||||
|
||||
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
|
||||
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
|
||||
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
|
||||
thd->lex->restore_set_statement_var();
|
||||
@ -954,13 +956,8 @@ bool do_command(THD *thd)
|
||||
if(!thd->skip_wait_timeout)
|
||||
my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
|
||||
|
||||
|
||||
/*
|
||||
XXX: this code is here only to clear possible errors of init_connect.
|
||||
Consider moving to init_connect() instead.
|
||||
*/
|
||||
thd->clear_error(); // Clear error message
|
||||
thd->get_stmt_da()->reset_diagnostics_area();
|
||||
/* Errors and diagnostics are cleared once here before query */
|
||||
thd->clear_error(1);
|
||||
|
||||
net_new_transaction(net);
|
||||
|
||||
@ -1123,6 +1120,7 @@ bool do_command(THD *thd)
|
||||
WSREP_WARN("For retry temporally setting character set to : %s",
|
||||
my_charset_latin1.csname);
|
||||
}
|
||||
thd->clear_error();
|
||||
return_value= dispatch_command(command, thd, thd->wsrep_retry_query,
|
||||
thd->wsrep_retry_query_len);
|
||||
thd->variables.character_set_client = current_charset;
|
||||
@ -1272,7 +1270,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
|
||||
WSREP_DEBUG("Deadlock error for: %s", thd->query());
|
||||
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
|
||||
thd->killed = NOT_KILLED;
|
||||
thd->reset_killed();
|
||||
thd->mysys_var->abort = 0;
|
||||
thd->wsrep_conflict_state = NO_CONFLICT;
|
||||
thd->wsrep_retry_counter = 0;
|
||||
@ -1625,7 +1623,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
break;
|
||||
}
|
||||
packet= arg_end + 1;
|
||||
thd->reset_for_next_command();
|
||||
thd->reset_for_next_command(0); // Don't clear errors
|
||||
lex_start(thd);
|
||||
/* Must be before we init the table list. */
|
||||
if (lower_case_table_names)
|
||||
@ -1694,7 +1692,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
}
|
||||
#endif
|
||||
case COM_QUIT:
|
||||
/* We don't calculate statistics for this command */
|
||||
/* Note: We don't calculate statistics for this command */
|
||||
|
||||
/* Ensure that quit works even if max_mem_used is set */
|
||||
thd->variables.max_mem_used= LONGLONG_MAX;
|
||||
general_log_print(thd, command, NullS);
|
||||
net->error=0; // Don't give 'abort' message
|
||||
thd->get_stmt_da()->disable_status(); // Don't send anything back
|
||||
@ -1974,6 +1975,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
|
||||
dec_thread_running();
|
||||
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
|
||||
thd->reset_kill_query(); /* Ensure that killed_errmsg is released */
|
||||
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
|
||||
|
||||
#if defined(ENABLED_PROFILING)
|
||||
@ -5047,7 +5049,7 @@ end_with_restore_list:
|
||||
/* Disconnect the current client connection. */
|
||||
if (tx_release)
|
||||
{
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
thd->print_aborted_warning(3, "RELEASE");
|
||||
}
|
||||
#ifdef WITH_WSREP
|
||||
@ -5093,7 +5095,7 @@ end_with_restore_list:
|
||||
}
|
||||
/* Disconnect the current client connection. */
|
||||
if (tx_release)
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
#ifdef WITH_WSREP
|
||||
if (WSREP(thd) && thd->wsrep_conflict_state != NO_CONFLICT)
|
||||
{
|
||||
@ -6879,6 +6881,8 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
|
||||
Reset the part of THD responsible for the state of command
|
||||
processing.
|
||||
|
||||
@param do_clear_error Set if we should clear errors
|
||||
|
||||
This needs to be called before execution of every statement
|
||||
(prepared or conventional). It is not called by substatements of
|
||||
routines.
|
||||
@ -6886,12 +6890,16 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
|
||||
@todo Call it after we use THD for queries, not before.
|
||||
*/
|
||||
|
||||
void THD::reset_for_next_command()
|
||||
void THD::reset_for_next_command(bool do_clear_error)
|
||||
{
|
||||
THD *thd= this;
|
||||
DBUG_ENTER("THD::reset_for_next_command");
|
||||
DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
|
||||
DBUG_ASSERT(! thd->in_sub_stmt);
|
||||
|
||||
if (do_clear_error)
|
||||
clear_error(1);
|
||||
|
||||
thd->free_list= 0;
|
||||
thd->select_number= 1;
|
||||
/*
|
||||
@ -6947,8 +6955,6 @@ void THD::reset_for_next_command()
|
||||
reset_dynamic(&thd->user_var_events);
|
||||
thd->user_var_events_alloc= thd->mem_root;
|
||||
}
|
||||
thd->clear_error();
|
||||
thd->get_stmt_da()->reset_diagnostics_area();
|
||||
thd->get_stmt_da()->reset_for_next_command();
|
||||
thd->rand_used= 0;
|
||||
thd->m_sent_row_count= thd->m_examined_row_count= 0;
|
||||
@ -7180,7 +7186,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
|
||||
thd->wsrep_conflict_state == CERT_FAILURE)
|
||||
{
|
||||
thd->reset_for_next_command();
|
||||
thd->killed= NOT_KILLED;
|
||||
thd->reset_killed();
|
||||
if (is_autocommit &&
|
||||
thd->lex->sql_command != SQLCOM_SELECT &&
|
||||
(thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit))
|
||||
@ -7208,7 +7214,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
|
||||
thd->thread_id, is_autocommit, thd->wsrep_retry_counter,
|
||||
thd->variables.wsrep_retry_autocommit, thd->query());
|
||||
my_error(ER_LOCK_DEADLOCK, MYF(0), "wsrep aborted transaction");
|
||||
thd->killed= NOT_KILLED;
|
||||
thd->reset_killed();
|
||||
thd->wsrep_conflict_state= NO_CONFLICT;
|
||||
if (thd->wsrep_conflict_state != REPLAYING)
|
||||
thd->wsrep_retry_counter= 0; // reset
|
||||
@ -8282,10 +8288,10 @@ void sql_kill(THD *thd, longlong id, killed_state state, killed_type type)
|
||||
uint error;
|
||||
if (!(error= kill_one_thread(thd, id, state, type)))
|
||||
{
|
||||
if ((!thd->killed))
|
||||
if (!thd->killed)
|
||||
my_ok(thd);
|
||||
else
|
||||
my_error(killed_errno(thd->killed), MYF(0), id);
|
||||
thd->send_kill_message();
|
||||
}
|
||||
else
|
||||
my_error(error, MYF(0), id);
|
||||
|
@ -3592,7 +3592,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
|
||||
#endif
|
||||
|
||||
DBUG_EXECUTE_IF("bug11747970_raise_error",
|
||||
{ join->thd->killed= KILL_QUERY_HARD; });
|
||||
{ join->thd->set_killed(KILL_QUERY_HARD); });
|
||||
if (error)
|
||||
{
|
||||
table->file->print_error(error, MYF(0));
|
||||
|
@ -4783,7 +4783,7 @@ int create_table_impl(THD *thd,
|
||||
thd->variables.option_bits|= OPTION_KEEP_LOG;
|
||||
thd->log_current_statement= 1;
|
||||
create_info->table_was_deleted= 1;
|
||||
DBUG_EXECUTE_IF("send_kill_after_delete", thd->killed= KILL_QUERY; );
|
||||
DBUG_EXECUTE_IF("send_kill_after_delete", thd->set_killed(KILL_QUERY); );
|
||||
|
||||
/*
|
||||
Restart statement transactions for the case of CREATE ... SELECT.
|
||||
|
@ -940,7 +940,7 @@ int mysql_update(THD *thd,
|
||||
// simulated killing after the loop must be ineffective for binlogging
|
||||
DBUG_EXECUTE_IF("simulate_kill_bug27571",
|
||||
{
|
||||
thd->killed= KILL_QUERY;
|
||||
thd->set_killed(KILL_QUERY);
|
||||
};);
|
||||
error= (killed_status == NOT_KILLED)? error : 1;
|
||||
|
||||
|
@ -463,7 +463,7 @@ static void timeout_check(pool_timer_t *timer)
|
||||
{
|
||||
/* Wait timeout exceeded, kill connection. */
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
thd->killed = KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
post_kill_notification(thd);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
}
|
||||
|
@ -613,7 +613,7 @@ static VOID CALLBACK timer_callback(PTP_CALLBACK_INSTANCE instance,
|
||||
|
||||
if (timeout <= now())
|
||||
{
|
||||
con->thd->killed = KILL_CONNECTION;
|
||||
con->thd->set_killed(KILL_CONNECTION);
|
||||
if(con->thd->net.vio)
|
||||
vio_shutdown(con->thd->net.vio, SD_BOTH);
|
||||
}
|
||||
|
@ -1965,7 +1965,7 @@ static bool have_client_connections()
|
||||
|
||||
static void wsrep_close_thread(THD *thd)
|
||||
{
|
||||
thd->killed= KILL_CONNECTION;
|
||||
thd->set_killed(KILL_CONNECTION);
|
||||
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (thd));
|
||||
if (thd->mysys_var)
|
||||
{
|
||||
@ -2045,7 +2045,7 @@ void wsrep_close_client_connections(my_bool wait_to_end)
|
||||
|
||||
if (is_replaying_connection(tmp))
|
||||
{
|
||||
tmp->killed= KILL_CONNECTION;
|
||||
tmp->set_killed(KILL_CONNECTION);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ void wsrep_replay_transaction(THD *thd)
|
||||
mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
|
||||
|
||||
thd->reset_for_next_command();
|
||||
thd->killed= NOT_KILLED;
|
||||
thd->reset_killed();
|
||||
close_thread_tables(thd);
|
||||
if (thd->locked_tables_mode && thd->lock)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user