Skip to content

Commit 7454369

Browse files
committed
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)
1 parent 008786a commit 7454369

24 files changed

+176
-100
lines changed

libmysqld/lib_sql.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,7 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
140140
}
141141

142142
/* Clear result variables */
143-
thd->clear_error();
144-
thd->get_stmt_da()->reset_diagnostics_area();
143+
thd->clear_error(1);
145144
mysql->affected_rows= ~(my_ulonglong) 0;
146145
mysql->field_count= 0;
147146
net_clear_error(net);

mysql-test/r/errors.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ UPDATE t1 SET a = 'new'
168168
WHERE COLUMN_CREATE( 1, 'v', 1, 'w' ) IS NULL;
169169
ERROR 22007: Illegal value used as argument of dynamic column function
170170
drop table t1;
171+
set max_session_mem_used = 50000;
172+
select * from seq_1_to_1000;
171173
set max_session_mem_used = 8192;
172174
select * from seq_1_to_1000;
173-
Got one of the listed errors
174-
set global max_session_mem_used = default;

mysql-test/t/errors.test

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,13 @@ drop table t1;
203203
#
204204
# errors caused by max_session_mem_used
205205
#
206+
--disable_result_log
207+
set max_session_mem_used = 50000;
208+
--error 0,ER_OPTION_PREVENTS_STATEMENT
209+
select * from seq_1_to_1000;
206210
set max_session_mem_used = 8192;
207-
--error ER_SQL_DISCOVER_ERROR,ER_OPTION_PREVENTS_STATEMENT
211+
--error 0,ER_OPTION_PREVENTS_STATEMENT
208212
select * from seq_1_to_1000;
209-
set global max_session_mem_used = default;
213+
--enable_result_log
214+
# We may not be able to execute any more queries with this connection
215+
# because of too little memory#

sql/debug_sync.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
15021502
{
15031503
if (!--action->hit_limit)
15041504
{
1505-
thd->killed= KILL_QUERY;
1505+
thd->set_killed(KILL_QUERY);
15061506
my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0));
15071507
}
15081508
DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'",

sql/log_event.cc

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -371,12 +371,6 @@ static void pretty_print_str(IO_CACHE* cache, const char* str, int len)
371371

372372
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
373373

374-
static void clear_all_errors(THD *thd, Relay_log_info *rli)
375-
{
376-
thd->is_slave_error = 0;
377-
thd->clear_error();
378-
}
379-
380374
inline int idempotent_error_code(int err_code)
381375
{
382376
int ret= 0;
@@ -4255,7 +4249,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
42554249

42564250
DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
42574251

4258-
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
4252+
thd->clear_error(1);
42594253
current_stmt_is_commit= is_commit();
42604254

42614255
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,
44754469
to check/fix it.
44764470
*/
44774471
if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
4478-
clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); /* Can ignore query */
4472+
thd->clear_error(1);
44794473
else
44804474
{
44814475
rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
@@ -4556,7 +4550,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query());
45564550
ignored_error_code(actual_error))
45574551
{
45584552
DBUG_PRINT("info",("error ignored"));
4559-
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
4553+
thd->clear_error(1);
45604554
if (actual_error == ER_QUERY_INTERRUPTED ||
45614555
actual_error == ER_CONNECTION_KILLED)
45624556
thd->reset_killed();
@@ -6025,8 +6019,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
60256019
new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length);
60266020
thd->set_db(new_db.str, new_db.length);
60276021
DBUG_ASSERT(thd->query() == 0);
6028-
thd->is_slave_error= 0;
6029-
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
6022+
thd->clear_error(1);
60306023

60316024
/* see Query_log_event::do_apply_event() and BUG#13360 */
60326025
DBUG_ASSERT(!rgi->m_table_map.count());
@@ -6036,7 +6029,7 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
60366029
*/
60376030
lex_start(thd);
60386031
thd->lex->local_file= local_fname;
6039-
thd->reset_for_next_command();
6032+
thd->reset_for_next_command(0); // Errors are cleared above
60406033

60416034
/*
60426035
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)
1009110084
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
1009210085
get_type_str(),
1009310086
RPL_LOG_NAME, (ulong) log_pos);
10094-
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
10087+
thd->clear_error(1);
1009510088
error= 0;
1009610089
if (idempotent_error == 0)
1009710090
break;
@@ -10143,7 +10136,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
1014310136
slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
1014410137
get_type_str(),
1014510138
RPL_LOG_NAME, (ulong) log_pos);
10146-
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
10139+
thd->clear_error(1);
1014710140
error= 0;
1014810141
}
1014910142
} // if (table)

sql/mysqld.cc

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
878878
key_LOCK_prepared_stmt_count,
879879
key_LOCK_rpl_status, key_LOCK_server_started,
880880
key_LOCK_status, key_LOCK_show_status,
881-
key_LOCK_system_variables_hash, key_LOCK_thd_data,
881+
key_LOCK_system_variables_hash, key_LOCK_thd_data, key_LOCK_thd_kill,
882882
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
883883
key_master_info_data_lock, key_master_info_run_lock,
884884
key_master_info_sleep_lock, key_master_info_start_stop_lock,
@@ -949,6 +949,7 @@ static PSI_mutex_info all_server_mutexes[]=
949949
{ &key_LOCK_wait_commit, "wait_for_commit::LOCK_wait_commit", 0},
950950
{ &key_LOCK_gtid_waiting, "gtid_waiting::LOCK_gtid_waiting", 0},
951951
{ &key_LOCK_thd_data, "THD::LOCK_thd_data", 0},
952+
{ &key_LOCK_thd_kill, "THD::LOCK_thd_kill", 0},
952953
{ &key_LOCK_user_conn, "LOCK_user_conn", PSI_FLAG_GLOBAL},
953954
{ &key_LOCK_uuid_short_generator, "LOCK_uuid_short_generator", PSI_FLAG_GLOBAL},
954955
{ &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
@@ -1650,7 +1651,7 @@ static void close_connections(void)
16501651
if (WSREP(tmp) && (tmp->wsrep_exec_mode==REPL_RECV || tmp->wsrep_applier))
16511652
continue;
16521653
#endif
1653-
tmp->killed= KILL_SERVER_HARD;
1654+
tmp->set_killed(KILL_SERVER_HARD);
16541655
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
16551656
mysql_mutex_lock(&tmp->LOCK_thd_data);
16561657
if (tmp->mysys_var)
@@ -1738,7 +1739,7 @@ static void close_connections(void)
17381739
if (WSREP(tmp) && tmp->wsrep_exec_mode==REPL_RECV)
17391740
{
17401741
sql_print_information("closing wsrep system thread");
1741-
tmp->killed= KILL_CONNECTION;
1742+
tmp->set_killed(KILL_CONNECTION);
17421743
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
17431744
if (tmp->mysys_var)
17441745
{
@@ -3943,11 +3944,16 @@ static void my_malloc_size_cb_func(long long size, my_bool is_thread_specific)
39433944
thd->status_var.local_memory_used > (int64)thd->variables.max_mem_used &&
39443945
!thd->killed && !thd->get_stmt_da()->is_set())
39453946
{
3946-
char buf[1024];
3947-
thd->killed= KILL_QUERY;
3947+
/* Ensure we don't get called here again */
3948+
char buf[50], *buf2;
3949+
thd->set_killed(KILL_QUERY);
39483950
my_snprintf(buf, sizeof(buf), "--max-thread-mem-used=%llu",
39493951
thd->variables.max_mem_used);
3950-
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), buf);
3952+
if ((buf2= (char*) thd->alloc(256)))
3953+
{
3954+
my_snprintf(buf2, 256, ER_THD(thd, ER_OPTION_PREVENTS_STATEMENT), buf);
3955+
thd->set_killed(KILL_QUERY, ER_OPTION_PREVENTS_STATEMENT, buf2);
3956+
}
39513957
}
39523958
DBUG_ASSERT((longlong) thd->status_var.local_memory_used >= 0);
39533959
}
@@ -6318,7 +6324,7 @@ void create_thread_to_handle_connection(THD *thd)
63186324
DBUG_PRINT("error",
63196325
("Can't create thread to handle request (error %d)",
63206326
error));
6321-
thd->killed= KILL_CONNECTION; // Safety
6327+
thd->set_killed(KILL_CONNECTION); // Safety
63226328
mysql_mutex_unlock(&LOCK_thread_count);
63236329

63246330
mysql_mutex_lock(&LOCK_connection_count);

sql/mysqld.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
290290
key_LOCK_prepared_stmt_count,
291291
key_LOCK_rpl_status, key_LOCK_server_started,
292292
key_LOCK_status, key_LOCK_show_status,
293-
key_LOCK_thd_data,
293+
key_LOCK_thd_data, key_LOCK_thd_kill,
294294
key_LOCK_user_conn, key_LOG_LOCK_log,
295295
key_master_info_data_lock, key_master_info_run_lock,
296296
key_master_info_sleep_lock, key_master_info_start_stop_lock,

sql/rpl_parallel.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -714,9 +714,7 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt,
714714
DBUG_EXECUTE_IF("inject_mdev8031", {
715715
/* Simulate that we get deadlock killed at this exact point. */
716716
rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
717-
mysql_mutex_lock(&thd->LOCK_thd_data);
718-
thd->killed= KILL_CONNECTION;
719-
mysql_mutex_unlock(&thd->LOCK_thd_data);
717+
thd->set_killed(KILL_CONNECTION);
720718
});
721719
rgi->cleanup_context(thd, 1);
722720
wait_for_pending_deadlock_kill(thd, rgi);
@@ -862,9 +860,7 @@ retry_event_group(rpl_group_info *rgi, rpl_parallel_thread *rpt,
862860
/* Simulate that we get deadlock killed during open_binlog(). */
863861
thd->reset_for_next_command();
864862
rgi->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED;
865-
mysql_mutex_lock(&thd->LOCK_thd_data);
866-
thd->killed= KILL_CONNECTION;
867-
mysql_mutex_unlock(&thd->LOCK_thd_data);
863+
thd->set_killed(KILL_CONNECTION);
868864
thd->send_kill_message();
869865
fd= (File)-1;
870866
err= 1;

sql/sp_rcontext.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,7 @@ bool sp_rcontext::handle_sql_condition(THD *thd,
331331

332332
/* Reset error state. */
333333
thd->clear_error();
334-
thd->killed= NOT_KILLED; // Some errors set thd->killed
335-
// (e.g. "bad data").
334+
thd->reset_killed(); // Some errors set thd->killed, (e.g. "bad data").
336335

337336
/* Add a frame to handler-call-stack. */
338337
Sql_condition_info *cond_info=

sql/sql_base.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ void kill_delayed_threads_for_table(TDC_element *element)
400400
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
401401
! in_use->killed)
402402
{
403-
in_use->killed= KILL_SYSTEM_THREAD;
403+
in_use->set_killed(KILL_SYSTEM_THREAD);
404404
mysql_mutex_lock(&in_use->mysys_var->mutex);
405405
if (in_use->mysys_var->current_cond)
406406
{
@@ -9136,7 +9136,7 @@ bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
91369136
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
91379137
!in_use->killed)
91389138
{
9139-
in_use->killed= KILL_SYSTEM_THREAD;
9139+
in_use->set_killed(KILL_SYSTEM_THREAD);
91409140
mysql_mutex_lock(&in_use->mysys_var->mutex);
91419141
if (in_use->mysys_var->current_cond)
91429142
{

0 commit comments

Comments
 (0)