From 66f4900b517681da2aed3b562158ef58679961e4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 11 Jan 2021 13:16:38 +0100 Subject: Revert "MDEV-23536 : Race condition between KILL and transaction commit" This reverts the server part of the commit 775fccea0 but keeps InnoDB part (which reverted MDEV-17092 5530a93f4). So after this both MDEV-23536 and MDEV-17092 are reverted, and the original bug is resurrected. --- sql/sql_class.cc | 38 +++++++------------------------------- sql/sql_class.h | 2 +- 2 files changed, 8 insertions(+), 32 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2321991d99f..2595717572a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1357,15 +1357,12 @@ void THD::change_user(void) /* Do operations that may take a long time */ -void THD::cleanup(bool have_mutex) +void THD::cleanup(void) { DBUG_ENTER("THD::cleanup"); DBUG_ASSERT(cleanup_done == 0); - if (have_mutex) - set_killed_no_mutex(KILL_CONNECTION,0,0); - else - set_killed(KILL_CONNECTION); + set_killed(KILL_CONNECTION); #ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE if (transaction.xid_state.xa_state == XA_PREPARED) { @@ -1440,28 +1437,6 @@ void THD::cleanup(bool have_mutex) void THD::free_connection() { DBUG_ASSERT(free_connection_done == 0); - /* Check that we have already called thd->unlink() */ - DBUG_ASSERT(prev == 0 && next == 0); - - /* - Other threads may have a lock on THD::LOCK_thd_data or - THD::LOCK_thd_kill to ensure that this THD is not deleted - while they access it. The following mutex_lock ensures - that no one else is using this THD and it's now safe to - continue. - - For example consider KILL-statement execution on - sql_parse.cc kill_one_thread() that will use - THD::LOCK_thd_data to protect victim thread during - THD::awake(). - */ - mysql_mutex_lock(&LOCK_thd_data); - mysql_mutex_lock(&LOCK_thd_kill); - -#ifdef WITH_WSREP - delete wsrep_rgi; - wsrep_rgi= 0; -#endif /* WITH_WSREP */ my_free(db); db= NULL; #ifndef EMBEDDED_LIBRARY @@ -1470,8 +1445,8 @@ void THD::free_connection() net.vio= 0; net_end(&net); #endif - if (!cleanup_done) - cleanup(true); // We have locked THD::LOCK_thd_kill + if (!cleanup_done) + cleanup(); ha_close_connection(this); plugin_thdvar_cleanup(this); mysql_audit_free_thd(this); @@ -1482,8 +1457,6 @@ void THD::free_connection() #if defined(ENABLED_PROFILING) profiling.restart(); // Reset profiling #endif - mysql_mutex_unlock(&LOCK_thd_kill); - mysql_mutex_unlock(&LOCK_thd_data); } /* @@ -1539,6 +1512,9 @@ THD::~THD() mysql_mutex_lock(&LOCK_thd_data); mysql_mutex_unlock(&LOCK_thd_data); +#ifdef WITH_WSREP + delete wsrep_rgi; +#endif if (!free_connection_done) free_connection(); diff --git a/sql/sql_class.h b/sql/sql_class.h index a97f64c13b3..b68e3553a2d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3194,7 +3194,7 @@ public: void update_all_stats(); void update_stats(void); void change_user(void); - void cleanup(bool have_mutex=false); + void cleanup(void); void cleanup_after_query(); void free_connection(); void reset_for_reuse(); -- cgit v1.2.1 From 9b750dcbd89ecf455211a77348a85464b282abee Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 11 Jan 2021 13:21:42 +0100 Subject: MDEV-23536 Race condition between KILL and transaction commit Server part: kill_handlerton() was accessing thd->ha_data[] for some other thd, while it could be concurrently modified by its owner thd. protect thd->ha_data[] modifications with a mutex. require this mutex when accessing thd->ha_data[] from kill_handlerton. InnoDB part: on close_connection, detach trx from thd before freeing the trx --- sql/handler.cc | 1 + sql/sql_class.cc | 3 +++ 2 files changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index c38c604347a..29b01763e8b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -838,6 +838,7 @@ static my_bool kill_handlerton(THD *thd, plugin_ref plugin, { handlerton *hton= plugin_hton(plugin); + mysql_mutex_assert_owner(&thd->LOCK_thd_data); if (hton->state == SHOW_OPTION_YES && hton->kill_query && thd_get_ha_data(thd, hton)) hton->kill_query(hton, thd, *(enum thd_kill_levels *) level); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2595717572a..c3274ae9b82 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -444,6 +444,7 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton, const void *ha_data) { plugin_ref *lock= &thd->ha_data[hton->slot].lock; + DBUG_ASSERT(thd == current_thd); if (ha_data && !*lock) *lock= ha_lock_engine(NULL, (handlerton*) hton); else if (!ha_data && *lock) @@ -451,7 +452,9 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton, plugin_unlock(NULL, *lock); *lock= NULL; } + mysql_mutex_lock(&thd->LOCK_thd_data); *thd_ha_data(thd, hton)= (void*) ha_data; + mysql_mutex_unlock(&thd->LOCK_thd_data); } -- cgit v1.2.1 From 4c448836d489bd5a25c7509e8a69309c3b0a8e72 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 5 Jan 2021 18:10:04 +0100 Subject: MDEV-12161 Can't specify collation for virtual columns sql standard (2016) allows in two places in the - as a part of the or at the very end. Let's do that too. Side effect: in column/SP declaration `COLLATE cs_coll` automatically implies `CHARACTER SET cs` (unless charset was specified explicitly). See changes in sp-ucs2.result --- sql/sql_show.cc | 7 ++++++- sql/sql_yacc.yy | 42 ++++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 21 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 49659c239bc..79897429a4f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2013,8 +2013,13 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, /* For string types dump collation name only if collation is not primary for the given charset + + For generated fields don't print the COLLATE clause if + the collation matches the expression's collation. */ - if (!(field->charset()->state & MY_CS_PRIMARY) && !field->vcol_info) + if (!(field->charset()->state & MY_CS_PRIMARY) && + (!field->vcol_info || + field->charset() != field->vcol_info->expr->collation.collation)) { packet->append(STRING_WITH_LEN(" COLLATE ")); packet->append(field->charset()->name); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1f37296842c..a1616024fb8 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1033,7 +1033,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); Currently there are 98 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 98 +%expect 109 /* Comments for TOKENS. @@ -1774,7 +1774,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type int_type real_type -%type type_with_opt_collate field_type +%type field_type %type opt_dyncol_type dyncol_type numeric_dyncol_type temporal_dyncol_type string_dyncol_type @@ -3010,11 +3010,12 @@ sp_param_name_and_type: thd->variables.collation_database); $$= spvar; } - type_with_opt_collate + field_type { LEX *lex= Lex; sp_variable *spvar= $2; + Lex->set_last_field_type($3); if (lex->sphead->fill_field_definition(thd, lex, lex->last_field)) { MYSQL_YYABORT; @@ -3096,14 +3097,15 @@ sp_decl: thd->lex->init_last_field(&spvar->field_def, spvar->name.str, thd->variables.collation_database); } - type_with_opt_collate + field_type sp_opt_default { LEX *lex= Lex; sp_pcontext *pctx= lex->spcont; uint num_vars= pctx->context_var_count(); Item *dflt_value_item= $5; - + Lex->set_last_field_type($4); + if (!dflt_value_item) { dflt_value_item= new (thd->mem_root) Item_null(thd); @@ -6665,20 +6667,6 @@ serial_attribute: ; -type_with_opt_collate: - field_type opt_collate - { - $$= $1; - - if ($2) - { - if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))) - MYSQL_YYABORT; - } - Lex->set_last_field_type($1); - } - ; - charset: CHAR_SYM SET {} | CHARSET {} @@ -6751,12 +6739,25 @@ charset_or_alias: } ; +collate: COLLATE_SYM collation_name_or_default + { + Lex->charset= Lex->last_field->charset= $2; + } + ; + opt_binary: /* empty */ { bincmp_collation(NULL, false); } | BYTE_SYM { bincmp_collation(&my_charset_bin, false); } | charset_or_alias opt_bin_mod { bincmp_collation($1, $2); } | BINARY { bincmp_collation(NULL, true); } | BINARY charset_or_alias { bincmp_collation($2, true); } + | charset_or_alias collate + { + if (!my_charset_same(Lex->charset, $1)) + my_yyabort_error((ER_COLLATION_CHARSET_MISMATCH, MYF(0), + Lex->charset->name, $1->csname)); + } + | collate { } ; opt_bin_mod: @@ -16854,8 +16855,9 @@ sf_tail: lex->init_last_field(&lex->sphead->m_return_field_def, NULL, thd->variables.collation_database); } - type_with_opt_collate /* $11 */ + field_type /* $11 */ { /* $12 */ + Lex->set_last_field_type($11); if (Lex->sphead->fill_field_definition(thd, Lex, Lex->last_field)) MYSQL_YYABORT; } -- cgit v1.2.1 From 63f91927870b41b8965e2a2a868abcc2b3672f68 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 7 Jan 2021 19:37:47 +0100 Subject: MDEV-17251 SHOW STATUS unnecessary calls calc_sum_of_all_status 1. only call calc_sum_of_all_status() if a global SHOW_xxx_STATUS variable is to be returned 2. only lock LOCK_status when copying global_status_var, but not when iterating all threads --- sql/sql_parse.cc | 1 + sql/sql_plugin.h | 5 +++-- sql/sql_show.cc | 20 +++++++++++--------- sql/sql_test.cc | 1 + 4 files changed, 16 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 54937116383..131ba4a86c5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2179,6 +2179,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; general_log_print(thd, command, NullS); status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]); + *current_global_status_var= global_status_var; calc_sum_of_all_status(current_global_status_var); if (!(uptime= (ulong) (thd->start_time - server_start_time))) queries_per_second1000= 0; diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 64194b5a1b5..13f7296e0cd 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -22,9 +22,10 @@ that is defined in plugin.h */ #define SHOW_always_last SHOW_KEY_CACHE_LONG, \ - SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, \ SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, \ - SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_LEX_STRING + SHOW_LONG_NOFLUSH, SHOW_LEX_STRING, \ + /* SHOW_*_STATUS must be at the end, SHOW_LONG_STATUS being first */ \ + SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, SHOW_LONGLONG_STATUS #include #undef SHOW_always_last diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 79897429a4f..4294157cce3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3580,6 +3580,16 @@ static bool show_status_array(THD *thd, const char *wild, if (show_type == SHOW_SYS) mysql_mutex_lock(&LOCK_global_system_variables); + else if (show_type >= SHOW_LONG_STATUS && scope == OPT_GLOBAL && + !status_var->local_memory_used) + { + mysql_mutex_lock(&LOCK_status); + *status_var= global_status_var; + mysql_mutex_unlock(&LOCK_status); + calc_sum_of_all_status(status_var); + DBUG_ASSERT(status_var->local_memory_used); + } + pos= get_one_variable(thd, var, scope, show_type, status_var, &charset, buff, &length); @@ -3620,8 +3630,6 @@ uint calc_sum_of_all_status(STATUS_VAR *to) I_List_iterator it(threads); THD *tmp; - /* Get global values as base */ - *to= global_status_var; to->local_memory_used= 0; /* Add to this status from existing threads */ @@ -7586,13 +7594,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) if (partial_cond) partial_cond->val_int(); - if (scope == OPT_GLOBAL) - { - /* We only hold LOCK_status for summary status vars */ - mysql_mutex_lock(&LOCK_status); - calc_sum_of_all_status(&tmp); - mysql_mutex_unlock(&LOCK_status); - } + tmp.local_memory_used= 0; // meaning tmp was not populated yet mysql_mutex_lock(&LOCK_show_status); res= show_status_array(thd, wild, diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 4e68ec2ec2e..c0e62227665 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -564,6 +564,7 @@ void mysql_print_status() STATUS_VAR tmp; uint count; + tmp= global_status_var; count= calc_sum_of_all_status(&tmp); printf("\nStatus information:\n\n"); (void) my_getwd(current_dir, sizeof(current_dir),MYF(0)); -- cgit v1.2.1 From fc0d9a470ce9ae2285f687e9b13f08b76527051b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 9 Jan 2021 17:00:04 +0100 Subject: MDEV-22966 Server crashes or hangs with SET ROLE when started with skip-grant-tables --- sql/sql_acl.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 6aa53e50bae..f1034986f22 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2770,6 +2770,12 @@ end: int acl_check_setrole(THD *thd, char *rolename, ulonglong *access) { + if (!initialized) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); + return 1; + } + return check_user_can_set_role(thd, thd->security_ctx->priv_user, thd->security_ctx->host, thd->security_ctx->ip, rolename, access); } -- cgit v1.2.1 From 22b171d3044675481c03b83888cffa018a502c4e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 9 Jan 2021 17:56:33 +0100 Subject: MDEV-17852 Altered connection limits for user have no effect update mqh in struct user_conn after taking it from the cache --- sql/sql_connect.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index aa7a877ed20..ec1bc45433a 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -85,7 +85,6 @@ int get_or_create_user_conn(THD *thd, const char *user, uc->host= uc->user + user_len + 1; uc->len= temp_len; uc->connections= uc->questions= uc->updates= uc->conn_per_hour= 0; - uc->user_resources= *mqh; uc->reset_utime= thd->thr_create_utime; if (my_hash_insert(&hash_user_connections, (uchar*) uc)) { @@ -95,6 +94,7 @@ int get_or_create_user_conn(THD *thd, const char *user, goto end; } } + uc->user_resources= *mqh; thd->user_connect=uc; uc->connections++; end: -- cgit v1.2.1 From 674be2fd8296092f246f2d89bc514f50f65dfa2c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 9 Jan 2021 18:52:33 +0100 Subject: MDEV-18428 Memory: If transactional=0 is specified in CREATE TABLE, it is not possible to ALTER TABLE fix "engine does not support TRANSACTIONAL=1" error message to match user input --- sql/sql_table.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 57284272316..4b62ccb7d7c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4254,7 +4254,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, ER_ILLEGAL_HA_CREATE_OPTION, ER_THD(thd, ER_ILLEGAL_HA_CREATE_OPTION), file->engine_name()->str, - "TRANSACTIONAL=1"); + create_info->transactional == HA_CHOICE_YES + ? "TRANSACTIONAL=1" : "TRANSACTIONAL=0"); if (parse_option_list(thd, file->partition_ht(), &create_info->option_struct, &create_info->option_list, -- cgit v1.2.1 From 4568a72ce45207a538d89449ffcff4a84cb3ea33 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 10 Jan 2021 01:31:38 +0100 Subject: don't do a warning for bad table options in replication slave thread otherwise ALTER TABLE can break replication --- sql/create_options.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/create_options.cc b/sql/create_options.cc index 4049443de2a..63552e60c4b 100644 --- a/sql/create_options.cc +++ b/sql/create_options.cc @@ -97,14 +97,13 @@ static bool report_unknown_option(THD *thd, engine_option_value *val, { DBUG_ENTER("report_unknown_option"); - if (val->parsed || suppress_warning) + if (val->parsed || suppress_warning || thd->slave_thread) { DBUG_PRINT("info", ("parsed => exiting")); DBUG_RETURN(FALSE); } - if (!(thd->variables.sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS) && - !thd->slave_thread) + if (!(thd->variables.sql_mode & MODE_IGNORE_BAD_TABLE_OPTIONS)) { my_error(ER_UNKNOWN_OPTION, MYF(0), val->name.str); DBUG_RETURN(TRUE); -- cgit v1.2.1 From 6f707430e5e24aed3720e39de6cf49dc8d18d131 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 9 Jan 2021 18:48:16 +0100 Subject: cleanup: copy RAII helpers from 10.5, cleanup test --- sql/sql_class.h | 32 ++++++++++++++++++++++++++++++++ sql/unireg.cc | 4 +--- 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.h b/sql/sql_class.h index b68e3553a2d..fe920270542 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5997,6 +5997,38 @@ class Sql_mode_save sql_mode_t old_mode; // SQL mode saved at construction time. }; +class Abort_on_warning_instant_set +{ + THD *m_thd; + bool m_save_abort_on_warning; +public: + Abort_on_warning_instant_set(THD *thd, bool temporary_value) + :m_thd(thd), m_save_abort_on_warning(thd->abort_on_warning) + { + thd->abort_on_warning= temporary_value; + } + ~Abort_on_warning_instant_set() + { + m_thd->abort_on_warning= m_save_abort_on_warning; + } +}; + +class Check_level_instant_set +{ + THD *m_thd; + enum_check_fields m_check_level; +public: + Check_level_instant_set(THD *thd, enum_check_fields temporary_value) + :m_thd(thd), m_check_level(thd->count_cuted_fields) + { + thd->count_cuted_fields= temporary_value; + } + ~Check_level_instant_set() + { + m_thd->count_cuted_fields= m_check_level; + } +}; + class Switch_to_definer_security_ctx { public: diff --git a/sql/unireg.cc b/sql/unireg.cc index 92949931f77..9c22527581a 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -944,7 +944,7 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, TABLE table; TABLE_SHARE share; Create_field *field; - enum_check_fields old_count_cuted_fields= thd->count_cuted_fields; + Check_level_instant_set old_count_cuted_fields(thd, CHECK_FIELD_WARN); DBUG_ENTER("make_empty_rec"); /* We need a table to generate columns for default values */ @@ -963,7 +963,6 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, null_pos= buff; List_iterator it(create_fields); - thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values while ((field=it++)) { /* regfield don't have to be deleted as it's allocated on THD::mem_root */ @@ -1039,6 +1038,5 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, *(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1); err: - thd->count_cuted_fields= old_count_cuted_fields; DBUG_RETURN(error); } /* make_empty_rec */ -- cgit v1.2.1 From 0d8bd7cc3ac9b71450f47700320dfd3d67347a88 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 10 Jan 2021 00:57:02 +0100 Subject: MDEV-18428 Memory: If transactional=0 is specified in CREATE TABLE, it is not possible to ALTER TABLE * be strict in CREATE TABLE, just like in ALTER TABLE, because CREATE TABLE, just like ALTER TABLE, can be rolled back for any engine * but don't auto-convert warnings into errors for engine warnings (handler::create) - this matches ALTER TABLE behavior * and not when creating a default record, these errors are handled specially (and replaced with ER_INVALID_DEFAULT) * always issue a Note when a non-unique key is truncated, because it's not a Warning that can be converted to an Error. Before this commit it was a Note for blobs and a Warning for all other data types. --- sql/handler.cc | 1 + sql/sql_table.cc | 10 +++++++--- sql/unireg.cc | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 29b01763e8b..87592beb5d3 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4847,6 +4847,7 @@ int ha_create_table(THD *thd, const char *path, char name_buff[FN_REFLEN]; const char *name; TABLE_SHARE share; + Abort_on_warning_instant_set old_abort_on_warning(thd, 0); bool temp_table __attribute__((unused)) = create_info->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4b62ccb7d7c..cb28c6adcec 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3983,8 +3983,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, { /* not a critical problem */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_TOO_LONG_KEY, - ER_THD(thd, ER_TOO_LONG_KEY), + ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY), key_part_length); /* Align key length to multibyte char boundary */ key_part_length-= key_part_length % sql_field->charset->mbmaxlen; @@ -4030,7 +4029,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (key->type == Key::MULTIPLE) { /* not a critical problem */ - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_TOO_LONG_KEY, ER_THD(thd, ER_TOO_LONG_KEY), key_part_length); /* Align key length to multibyte char boundary */ @@ -5133,6 +5132,9 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, if (!opt_explicit_defaults_for_timestamp) promote_first_timestamp_column(&alter_info->create_list); + /* We can abort create table for any table type */ + thd->abort_on_warning= thd->is_strict_mode(); + if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info, &is_trans, create_table_mode) > 0) { @@ -5165,6 +5167,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, } err: + thd->abort_on_warning= 0; + /* In RBR we don't need to log CREATE TEMPORARY TABLE */ if (!result && thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) DBUG_RETURN(result); diff --git a/sql/unireg.cc b/sql/unireg.cc index 9c22527581a..7974255af35 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -945,6 +945,7 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, TABLE_SHARE share; Create_field *field; Check_level_instant_set old_count_cuted_fields(thd, CHECK_FIELD_WARN); + Abort_on_warning_instant_set old_abort_on_warning(thd, 0); DBUG_ENTER("make_empty_rec"); /* We need a table to generate columns for default values */ -- cgit v1.2.1 From ad9a140d9b210758b354a997572ff86e884954fc Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 10 Jan 2021 20:35:27 +0100 Subject: MDEV-14884 Failed to enable encryption of temporary files in mariadb 10.3.3 enable the encryption (and abort on failure) after printing --help, not before --- sql/mysqld.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d3e124e3405..8d67bc53164 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5439,12 +5439,12 @@ static int init_server_components() } } - if (init_io_cache_encryption()) - unireg_abort(1); - if (opt_abort) unireg_abort(0); + if (init_io_cache_encryption()) + unireg_abort(1); + /* if the errmsg.sys is not loaded, terminate to maintain behaviour */ if (!DEFAULT_ERRMSGS[0][0]) unireg_abort(1); -- cgit v1.2.1 From 3b94309a6cec8d8149c9f312229d18227036e01d Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 12 Jan 2021 11:17:37 +0530 Subject: MDEV-23753: SIGSEGV in Column_stat::store_stat_fields For EITS collection min and max fields are allocated for each column that is set in the read_set bitmap of a table. This allocation of min and max fields happens inside alloc_statistics_for_table. For a partitioned table ha_rnd_init is called inside the function collect_statistics_for_table which sets the read_set bitmap for the columns inside the partition expression. This happens only when there is a write lock on the partitioned table. But the allocation happens before this, so min and max fields are not allocated for the columns involved in the partition expression. This resulted in a crash, as the EITS statistics were collected but there was no min and max field to store the value to. The fix would be to call ha_rnd_init inside the function alloc_statistics_for_table that would make sure that min and max fields are allocated for the columns involved in the partition expression. --- sql/sql_statistics.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index ab8edbf584b..b63172045e6 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -2110,6 +2110,10 @@ int alloc_statistics_for_table(THD* thd, TABLE *table) ulonglong *idx_avg_frequency= (ulonglong*) alloc_root(&table->mem_root, sizeof(ulonglong) * key_parts); + if (table->file->ha_rnd_init(TRUE)) + DBUG_RETURN(1); + table->file->ha_rnd_end(); + uint columns= 0; for (field_ptr= table->field; *field_ptr; field_ptr++) { -- cgit v1.2.1 From ab271ee7e22ce1250ec36b09123bfb98bc3f8107 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 12 Jan 2021 14:25:55 +0530 Subject: MDEV-23826: ORDER BY in view definition leads to wrong result with GROUP BY on query using view Introduced val_time_packed and val_datetime_packed functions for Item_direct_ref to make sure to get the value from the item it is referring to. The issue for incorrect result was that the item was getting its value from the temporary table rather than from the view. --- sql/item.cc | 16 ++++++++++++++++ sql/item.h | 19 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index a2753caf496..e633964270b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8160,6 +8160,22 @@ bool Item_direct_ref::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate) } +longlong Item_direct_ref::val_time_packed() +{ + longlong tmp = (*ref)->val_time_packed(); + null_value= (*ref)->null_value; + return tmp; +} + + +longlong Item_direct_ref::val_datetime_packed() +{ + longlong tmp = (*ref)->val_datetime_packed(); + null_value= (*ref)->null_value; + return tmp; +} + + Item_cache_wrapper::~Item_cache_wrapper() { DBUG_ASSERT(expr_cache == 0); diff --git a/sql/item.h b/sql/item.h index ed20074a8da..823ffd873b6 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4671,13 +4671,16 @@ public: return Item_ref::fix_fields(thd, it); } void save_val(Field *to); + /* Below we should have all val() methods as in Item_ref */ double val_real(); longlong val_int(); - String *val_str(String* tmp); my_decimal *val_decimal(my_decimal *); bool val_bool(); + String *val_str(String* tmp); bool is_null(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + longlong val_datetime_packed(); + longlong val_time_packed(); virtual Ref_Type ref_type() { return DIRECT_REF; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } @@ -4992,6 +4995,20 @@ public: } return Item_direct_ref::get_date(ltime, fuzzydate); } + longlong val_time_packed() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_time_packed(); + } + longlong val_datetime_packed() + { + if (check_null_ref()) + return 0; + else + return Item_direct_ref::val_datetime_packed(); + } bool send(Protocol *protocol, String *buffer); void save_org_in_field(Field *field, fast_field_copier data __attribute__ ((__unused__))) -- cgit v1.2.1 From 9e4a5a81fc062c082312afb230d2b8d4cf6b11cf Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 13 Jan 2021 16:16:13 +0700 Subject: MDEV-24208 SHOW RELAYLOG EVENTS command is not supported in the prepared statement protocol yet Added sending of metadata in response to preparing request for the commands SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_RELAYLOG_EVENTS --- sql/sql_prepare.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index dc2fb414de9..3dff2cb8106 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -121,6 +121,7 @@ When one supplies long data for a placeholder: static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8; #endif #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL +#include "log_event.h" // class Log_event #include "sql_handler.h" #include "transaction.h" // trans_rollback_implicit #include "wsrep_mysqld.h" @@ -2521,6 +2522,16 @@ static bool check_prepared_statement(Prepared_statement *stmt) DBUG_RETURN(FALSE); } break; + case SQLCOM_SHOW_BINLOG_EVENTS: + case SQLCOM_SHOW_RELAYLOG_EVENTS: + { + List field_list; + Log_event::init_show_field_list(thd, &field_list); + + if ((res= send_stmt_metadata(thd, stmt, &field_list)) == 2) + DBUG_RETURN(FALSE); + } + break; #endif /* EMBEDDED_LIBRARY */ case SQLCOM_SHOW_CREATE_PROC: if ((res= mysql_test_show_create_routine(stmt, TYPE_ENUM_PROCEDURE)) == 2) -- cgit v1.2.1 From beaea31ab12ab56ea8a6eb5e99cf82648675ea78 Mon Sep 17 00:00:00 2001 From: sjaakola Date: Wed, 9 Dec 2020 21:53:18 +0200 Subject: MDEV-23851 BF-BF Conflict issue because of UK GAP locks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some DML operations on tables having unique secondary keys cause scanning in the secondary index, for instance to find potential unique key violations in the seconday index. This scanning may involve GAP locking in the index. As this locking happens also when applying replication events in high priority applier threads, there is a probabality for lock conflicts between two wsrep high priority threads. This PR avoids lock conflicts of high priority wsrep threads, which do secondary index scanning e.g. for duplicate key detection. The actual fix is the patch in sql_class.cc:thd_need_ordering_with(), where we allow relaxed GAP locking protocol between wsrep high priority threads. wsrep high priority threads (replication appliers, replayers and TOI processors) are ordered by the replication provider, and they will not need serializability support gained by secondary index GAP locks. PR contains also a mtr test, which exercises a scenario where two replication applier threads have a false positive conflict in GAP of unique secondary index. The conflicting local committing transaction has to replay, and the test verifies also that the replaying phase will not conflict with the latter repllication applier. Commit also contains new test scenario for galera.galera_UK_conflict.test, where replayer starts applying after a slave applier thread, with later seqno, has advanced to commit phase. The applier and replayer have false positive GAP lock conflict on secondary unique index, and replayer should ignore this. This test scenario caused crash with earlier version in this PR, and to fix this, the secondary index uniquenes checking has been relaxed even further. Now innodb trx_t structure has new member: bool wsrep_UK_scan, which is set to true, when high priority thread is performing unique secondary index scanning. The member trx_t::wsrep_UK_scan is defined inside WITH_WSREP directive, to make it possible to prepare a MariaDB build where this additional trx_t member is not present and is not used in the code base. trx->wsrep_UK_scan is set to true only for the duration of function call for: lock_rec_lock() trx->wsrep_UK_scan is used only in lock_rec_has_to_wait() function to relax the need to wait if wsrep_UK_scan is set and conflicting transaction is also high priority. Reviewed-by: Jan Lindström --- sql/mdl.cc | 8 ++++---- sql/sql_class.cc | 12 +++++++++++- sql/wsrep_thd.cc | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/mdl.cc b/sql/mdl.cc index f2b205a86f2..8cb21771991 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1082,7 +1082,7 @@ MDL_wait::timed_wait(MDL_context_owner *owner, struct timespec *abs_timeout, DBUG_ASSERT(!debug_sync_set_action((owner->get_thd()), STRING_WITH_LEN(act))); };); - if (wsrep_thd_is_BF(owner->get_thd(), false)) + if (WSREP_ON && wsrep_thd_is_BF(owner->get_thd(), false)) { wait_result= mysql_cond_wait(&m_COND_wait_status, &m_LOCK_wait_status); } @@ -1155,7 +1155,7 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) */ DBUG_ASSERT(ticket->get_lock()); #ifdef WITH_WSREP - if ((this == &(ticket->get_lock()->m_waiting)) && + if (WSREP_ON && (this == &(ticket->get_lock()->m_waiting)) && wsrep_thd_is_BF(ticket->get_ctx()->get_thd(), false)) { Ticket_iterator itw(ticket->get_lock()->m_waiting); @@ -1581,7 +1581,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, ticket->is_incompatible_when_granted(type_arg)) { #ifdef WITH_WSREP - if (wsrep_thd_is_BF(requestor_ctx->get_thd(),false) && + if (WSREP_ON && wsrep_thd_is_BF(requestor_ctx->get_thd(),false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF: %lu %s", @@ -1615,7 +1615,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, } else { - if (wsrep_thd_is_BF(requestor_ctx->get_thd(), false) && + if (WSREP_ON && wsrep_thd_is_BF(requestor_ctx->get_thd(), false) && key.mdl_namespace() == MDL_key::GLOBAL) { WSREP_DEBUG("global lock granted for BF (waiting queue): %lu %s", diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c3274ae9b82..92736eacee2 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB Corporation. + Copyright (c) 2008, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4730,6 +4730,16 @@ thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd) DBUG_EXECUTE_IF("disable_thd_need_ordering_with", return 1;); if (!thd || !other_thd) return 1; +#ifdef WITH_WSREP + /* wsrep applier, replayer and TOI processing threads are ordered + by replication provider, relaxed GAP locking protocol can be used + between high priority wsrep threads + */ + if (WSREP_ON && + wsrep_thd_is_BF(const_cast(thd), false) && + wsrep_thd_is_BF(const_cast(other_thd), true)) + return 0; +#endif /* WITH_WSREP */ rgi= thd->rgi_slave; other_rgi= other_thd->rgi_slave; if (!rgi || !other_rgi) diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 1c43aeaaead..d8ca70d1cbe 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -22,6 +22,7 @@ //#include "global_threads.h" // LOCK_thread_count, etc. #include "sql_base.h" // close_thread_tables() #include "mysqld.h" // start_wsrep_THD(); +#include "debug_sync.h" #include "slave.h" // opt_log_slave_updates #include "rpl_filter.h" @@ -371,6 +372,19 @@ void wsrep_replay_transaction(THD *thd) thd->variables.option_bits|= OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; + /* Allow tests to block the replayer thread using the DBUG facilities */ +#ifdef ENABLED_DEBUG_SYNC + DBUG_EXECUTE_IF("sync.wsrep_replay_cb", + { + const char act[]= + "now " + "SIGNAL sync.wsrep_replay_cb_reached " + "WAIT_FOR signal.wsrep_replay_cb"; + DBUG_ASSERT(!debug_sync_set_action(thd, + STRING_WITH_LEN(act))); + };); +#endif /* ENABLED_DEBUG_SYNC */ + int rcode = wsrep->replay_trx(wsrep, &thd->wsrep_ws_handle, (void *)thd); -- cgit v1.2.1 From 94890a749a217bb831a5c260703d27b0a3e290d4 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Fri, 18 Dec 2020 00:28:38 +0530 Subject: MDEV-24179: Assertion `m_status == DA_ERROR || m_status == DA_OK || m_status == DA_OK_BULK' failed in Diagnostics_area::message() Analysis: Assertion failure happens because we reach the maximum limit to examine rows. Fix: Return the error state. --- sql/sql_show.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4294157cce3..3e9916816b9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5058,6 +5058,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) continue; } + if (thd->killed == ABORT_QUERY) + { + error= 0; + goto err; + } + DEBUG_SYNC(thd, "before_open_in_get_all_tables"); if (fill_schema_table_by_open(thd, FALSE, table, schema_table, -- cgit v1.2.1 From 959dfac4d0e715725d05448a77c08d870d5aa247 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 19 Jan 2021 15:29:03 +0400 Subject: MDEV-19723 Assertion `je->state == JST_KEY' failed while SELECT ST_GEOMFROMGEOJSON() and Assertion `!mysql_bin_log.is_open() || thd.is_current_stmt_binlog_format_row()' The invalid GeoJSON case wasn't handled here. --- sql/spatial.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/spatial.cc b/sql/spatial.cc index 83905fc9f3d..840f8bd809c 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -605,6 +605,7 @@ Geometry *Geometry::create_from_json(Geometry_buffer *buffer, if (feature_type_found) goto handle_geometry_key; } + goto err_return; } else { -- cgit v1.2.1 From b22285e4821b49546de9b88990bbc9c453dc14b2 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 19 Jan 2021 08:02:37 -0800 Subject: MDEV-16940 Server crashes in unsafe_key_update upon attempt to update view through 2nd execution of SP This bug caused a server crash on the second call of any stored procedure that contained an UPDATE statement over a multi-table view reporting an error message at the prepare stage. On the first call of the stored procedure after reporting an error at the preparation stage of the UPDATE statement finished without calling the function SELECT_LEX::save_prep_leaf_tables() for the SELECT used as the definition of the view. This left the SELECT_LEX structure used by the UPDATE statement in an inconsistent state for second call of the stored procedure. Approved by Oleksandr Byelkin --- sql/sql_lex.cc | 3 +++ sql/sql_update.cc | 3 +++ 2 files changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 77e6b2b6571..5059e4f656e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4585,6 +4585,9 @@ bool LEX::save_prep_leaf_tables() bool st_select_lex::save_prep_leaf_tables(THD *thd) { + if (prep_leaf_list_state == SAVED) + return FALSE; + List_iterator_fast li(leaf_tables); TABLE_LIST *table; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7454d16d55d..01743a6751e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1398,6 +1398,9 @@ bool Multiupdate_prelocking_strategy::handle_end(THD *thd) if (select_lex->handle_derived(thd->lex, DT_MERGE)) DBUG_RETURN(1); + if (thd->lex->save_prep_leaf_tables()) + DBUG_RETURN(1); + List *fields= &lex->select_lex.item_list; if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), *fields, MARK_COLUMNS_WRITE, 0, 0)) -- cgit v1.2.1 From eb75e8705d9a444e10057967eaebf947b1115ff8 Mon Sep 17 00:00:00 2001 From: Sujatha Date: Thu, 7 Jan 2021 17:34:57 +0530 Subject: MDEV-8134: The relay-log is not flushed after the slave-relay-log.999999 showed Problem: ======== Auto purge of relaylogs stops when relay-log-file is 'slave-relay-log.999999' and slave_parallel_threads is enabled. Analysis: ========= The problem is that in Relay_log_info::inc_group_relay_log_pos() function, when two log names are compared via strcmp() function, it gives correct result, when log name sequence numbers are of same digits(6 digits), But when the number goes to 7 digits, a 999999 compares greater than 1000000, which is wrong, hence the bug. Fix: ==== Extract the numeric extension part of the file name, convert it into unsigned long and compare. Thanks to David Zhao for the contribution. --- sql/rpl_parallel.cc | 5 +++-- sql/rpl_rli.cc | 4 ++-- sql/sql_repl.cc | 17 +++++++++++++++++ sql/sql_repl.h | 1 + 4 files changed, 23 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 4cf87ba73b7..869640fd46f 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -4,6 +4,7 @@ #include "rpl_mi.h" #include "sql_parse.h" #include "debug_sync.h" +#include "sql_repl.h" /* Code for optional parallel execution of replicated events on the slave. @@ -82,7 +83,7 @@ handle_queued_pos_update(THD *thd, rpl_parallel_thread::queued_event *qev) return; mysql_mutex_lock(&rli->data_lock); - cmp= strcmp(rli->group_relay_log_name, qev->event_relay_log_name); + cmp= compare_log_name(rli->group_relay_log_name, qev->event_relay_log_name); if (cmp < 0) { rli->group_relay_log_pos= qev->future_event_relay_log_pos; @@ -91,7 +92,7 @@ handle_queued_pos_update(THD *thd, rpl_parallel_thread::queued_event *qev) rli->group_relay_log_pos < qev->future_event_relay_log_pos) rli->group_relay_log_pos= qev->future_event_relay_log_pos; - cmp= strcmp(rli->group_master_log_name, qev->future_event_master_log_name); + cmp= compare_log_name(rli->group_master_log_name, qev->future_event_master_log_name); if (cmp < 0) { strcpy(rli->group_master_log_name, qev->future_event_master_log_name); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 40ab375571a..5273b33c728 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -989,7 +989,7 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos, if (rgi->is_parallel_exec) { /* In case of parallel replication, do not update the position backwards. */ - int cmp= strcmp(group_relay_log_name, rgi->event_relay_log_name); + int cmp= compare_log_name(group_relay_log_name, rgi->event_relay_log_name); if (cmp < 0) { group_relay_log_pos= rgi->future_event_relay_log_pos; @@ -1001,7 +1001,7 @@ void Relay_log_info::inc_group_relay_log_pos(ulonglong log_pos, In the parallel case we need to update the master_log_name here, rather than in Rotate_log_event::do_update_pos(). */ - cmp= strcmp(group_master_log_name, rgi->future_event_master_log_name); + cmp= compare_log_name(group_master_log_name, rgi->future_event_master_log_name); if (cmp <= 0) { if (cmp < 0) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4af8ebc2dd8..59a3f686e45 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -4541,5 +4541,22 @@ rpl_gtid_pos_update(THD *thd, char *str, size_t len) return false; } +int compare_log_name(const char *log_1, const char *log_2) { + int res= 1; + const char *ext1_str= strrchr(log_1, '.'); + const char *ext2_str= strrchr(log_2, '.'); + char file_name_1[255], file_name_2[255]; + strmake(file_name_1, log_1, (ext1_str - log_1)); + strmake(file_name_2, log_2, (ext2_str - log_2)); + char *endptr = NULL; + res= strcmp(file_name_1, file_name_2); + if (!res) + { + ulong ext1= strtoul(++ext1_str, &endptr, 10); + ulong ext2= strtoul(++ext2_str, &endptr, 10); + res= (ext1 > ext2 ? 1 : ((ext1 == ext2) ? 0 : -1)); + } + return res; +} #endif /* HAVE_REPLICATION */ diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 8ddfa9239f6..9129aaeed5e 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -56,6 +56,7 @@ bool show_binlogs(THD* thd); extern int init_master_info(Master_info* mi); void kill_zombie_dump_threads(uint32 slave_server_id); int check_binlog_magic(IO_CACHE* log, const char** errmsg); +int compare_log_name(const char *log_1, const char *log_2); struct LOAD_FILE_IO_CACHE : public IO_CACHE { -- cgit v1.2.1 From 29d9897fe2f46bf72356671ee3ad094abfe032c3 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 22 Jun 2016 15:52:07 +0200 Subject: MDEV-10272: add master host/port info to slave thread exit messages Sample log error message generated: 2021-01-21 2:33:24 139912137520896 [Note] Slave SQL thread exiting, replication stopped in log 'master-bin.000001' at position 369 33:24 139912137520896 [Note] master was 127.0.0.1:16400 2021-01-21 2:33:24 139912137828096 [Note] Slave I/O thread exiting, read up to log 'master-bin.000001', position 369 2021-01-21 2:33:24 139912137828096 [Note] master was 127.0.0.1:16400 Based on work by Hartmut Holzgraefe. Reviewer: knielsen@knielsen-hq.org, Andrei, Sachin --- sql/slave.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index a2c35e5f116..5685769bbfb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4646,8 +4646,11 @@ log space"); err: // print the current replication position if (mi->using_gtid == Master_info::USE_GTID_NO) + { sql_print_information("Slave I/O thread exiting, read up to log '%s', " "position %llu", IO_RPL_LOG_NAME, mi->master_log_pos); + sql_print_information("master was %s:%d", mi->host, mi->port); + } else { StringBuffer<100> tmp; @@ -4656,6 +4659,7 @@ err: "position %llu; GTID position %s", IO_RPL_LOG_NAME, mi->master_log_pos, tmp.c_ptr_safe()); + sql_print_information("master was %s:%d", mi->host, mi->port); } RUN_HOOK(binlog_relay_io, thread_stop, (thd, mi)); thd->reset_query(); @@ -5244,6 +5248,7 @@ pthread_handler_t handle_slave_sql(void *arg) sql_print_information("Slave SQL thread exiting, replication stopped in " "log '%s' at position %llu%s", RPL_LOG_NAME, rli->group_master_log_pos, tmp.c_ptr_safe()); + sql_print_information("master was %s:%d", mi->host, mi->port); } err_before_start: -- cgit v1.2.1 From 4a7e62296a295758b128d20f6bbb0973b94c5193 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Jan 2021 11:22:48 +0100 Subject: don't allow `KILL QUERY ID USER xxx` --- sql/sql_yacc.yy | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a1616024fb8..6eb47f1e49f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1033,7 +1033,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); Currently there are 98 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 109 +%expect 115 /* Comments for TOKENS. @@ -13525,7 +13525,7 @@ kill: lex->sql_command= SQLCOM_KILL; lex->kill_type= KILL_TYPE_ID; } - kill_type kill_option kill_expr + kill_type kill_option { Lex->kill_signal= (killed_state) ($3 | $4); } @@ -13538,16 +13538,21 @@ kill_type: ; kill_option: - /* empty */ { $$= (int) KILL_CONNECTION; } - | CONNECTION_SYM { $$= (int) KILL_CONNECTION; } - | QUERY_SYM { $$= (int) KILL_QUERY; } - | QUERY_SYM ID_SYM + opt_connection kill_expr { $$= (int) KILL_CONNECTION; } + | QUERY_SYM kill_expr { $$= (int) KILL_QUERY; } + | QUERY_SYM ID_SYM expr { $$= (int) KILL_QUERY; Lex->kill_type= KILL_TYPE_QUERY; + Lex->value_list.push_front($3, thd->mem_root); } ; +opt_connection: + /* empty */ { } + | CONNECTION_SYM { } + ; + kill_expr: expr { @@ -13560,7 +13565,6 @@ kill_expr: } ; - shutdown: SHUTDOWN { Lex->sql_command= SQLCOM_SHUTDOWN; } ; -- cgit v1.2.1 From 990eb09333dcb2147ccffa9633c1b2bd246aea65 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Jan 2021 18:01:17 +0100 Subject: cleanup: fix and generalize handle_manager thread * provide an argument to the callback * don't ignore a callback request if it's already present in the queue * initialize mutex/cond/in_use flag before starting the thread, in case the first callback queueing request arrives before handle_manager had time to initialize * set/check abort_manager under a mutex, otherwise handle_manager thread might destroy LOCK_manager before stop_handle_manager released it * signal COND on queueing a callback, stop cond_wait on callback request * always start the thread, even if flush_time is 0 * but keep the old behavior in embedded (no replication, no galera) * style cleanups (e.g. remove volatile for a variable protected by a mutex) --- sql/sql_manager.cc | 87 +++++++++++++++++++++++++----------------------------- sql/sql_manager.h | 2 +- 2 files changed, 41 insertions(+), 48 deletions(-) (limited to 'sql') diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index 7fa9a78f06f..d57963cceb0 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -26,8 +26,8 @@ #include "sql_manager.h" #include "sql_base.h" // flush_tables -static bool volatile manager_thread_in_use; -static bool abort_manager; +static bool volatile manager_thread_in_use = 0; +static bool abort_manager = false; pthread_t manager_thread; mysql_mutex_t LOCK_manager; @@ -35,31 +35,31 @@ mysql_cond_t COND_manager; struct handler_cb { struct handler_cb *next; - void (*action)(void); + void (*action)(void *); + void *data; }; -static struct handler_cb * volatile cb_list; +static struct handler_cb *cb_list; // protected by LOCK_manager -bool mysql_manager_submit(void (*action)()) +bool mysql_manager_submit(void (*action)(void *), void *data) { bool result= FALSE; DBUG_ASSERT(manager_thread_in_use); - struct handler_cb * volatile *cb; + struct handler_cb **cb; mysql_mutex_lock(&LOCK_manager); cb= &cb_list; - while (*cb && (*cb)->action != action) + while (*cb) cb= &(*cb)->next; + *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME)); if (!*cb) + result= TRUE; + else { - *cb= (struct handler_cb *)my_malloc(sizeof(struct handler_cb), MYF(MY_WME)); - if (!*cb) - result= TRUE; - else - { - (*cb)->next= NULL; - (*cb)->action= action; - } + (*cb)->next= NULL; + (*cb)->action= action; + (*cb)->data= data; } + mysql_cond_signal(&COND_manager); mysql_mutex_unlock(&LOCK_manager); return result; } @@ -69,18 +69,14 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused))) int error = 0; struct timespec abstime; bool reset_flush_time = TRUE; - struct handler_cb *cb= NULL; my_thread_init(); DBUG_ENTER("handle_manager"); pthread_detach_this_thread(); manager_thread = pthread_self(); - mysql_cond_init(key_COND_manager, &COND_manager,NULL); - mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL); - manager_thread_in_use = 1; - for (;;) + mysql_mutex_lock(&LOCK_manager); + while (!abort_manager) { - mysql_mutex_lock(&LOCK_manager); /* XXX: This will need to be made more general to handle different * polling needs. */ if (flush_time) @@ -90,40 +86,37 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused))) set_timespec(abstime, flush_time); reset_flush_time = FALSE; } - while ((!error || error == EINTR) && !abort_manager) + while ((!error || error == EINTR) && !abort_manager && !cb_list) error= mysql_cond_timedwait(&COND_manager, &LOCK_manager, &abstime); + + if (error == ETIMEDOUT || error == ETIME) + { + tc_purge(); + error = 0; + reset_flush_time = TRUE; + } } else { - while ((!error || error == EINTR) && !abort_manager) + while ((!error || error == EINTR) && !abort_manager && !cb_list) error= mysql_cond_wait(&COND_manager, &LOCK_manager); } - if (cb == NULL) - { - cb= cb_list; - cb_list= NULL; - } - mysql_mutex_unlock(&LOCK_manager); - if (abort_manager) - break; - - if (error == ETIMEDOUT || error == ETIME) - { - tc_purge(); - error = 0; - reset_flush_time = TRUE; - } + struct handler_cb *cb= cb_list; + cb_list= NULL; + mysql_mutex_unlock(&LOCK_manager); while (cb) { struct handler_cb *next= cb->next; - cb->action(); + cb->action(cb->data); my_free(cb); cb= next; } + mysql_mutex_lock(&LOCK_manager); } manager_thread_in_use = 0; + mysql_mutex_unlock(&LOCK_manager); mysql_mutex_destroy(&LOCK_manager); mysql_cond_destroy(&COND_manager); DBUG_LEAVE; // Can't use DBUG_RETURN after my_thread_end @@ -137,15 +130,15 @@ void start_handle_manager() { DBUG_ENTER("start_handle_manager"); abort_manager = false; - if (flush_time && flush_time != ~(ulong) 0L) { pthread_t hThread; - int error; - if ((error= mysql_thread_create(key_thread_handle_manager, - &hThread, &connection_attrib, - handle_manager, 0))) - sql_print_warning("Can't create handle_manager thread (errno= %d)", - error); + int err; + manager_thread_in_use = 1; + mysql_cond_init(key_COND_manager, &COND_manager,NULL); + mysql_mutex_init(key_LOCK_manager, &LOCK_manager, NULL); + if ((err= mysql_thread_create(key_thread_handle_manager, &hThread, + &connection_attrib, handle_manager, 0))) + sql_print_warning("Can't create handle_manager thread (errno: %M)", err); } DBUG_VOID_RETURN; } @@ -155,10 +148,10 @@ void start_handle_manager() void stop_handle_manager() { DBUG_ENTER("stop_handle_manager"); - abort_manager = true; if (manager_thread_in_use) { mysql_mutex_lock(&LOCK_manager); + abort_manager = true; DBUG_PRINT("quit", ("initiate shutdown of handle manager thread: %lu", (ulong)manager_thread)); mysql_cond_signal(&COND_manager); diff --git a/sql/sql_manager.h b/sql/sql_manager.h index 9c6c84450ed..f97d4a2cfc5 100644 --- a/sql/sql_manager.h +++ b/sql/sql_manager.h @@ -18,6 +18,6 @@ void start_handle_manager(); void stop_handle_manager(); -bool mysql_manager_submit(void (*action)()); +bool mysql_manager_submit(void (*action)(void *), void *data); #endif /* SQL_MANAGER_INCLUDED */ -- cgit v1.2.1 From 6a1cb449feb1b77e5ec94904c228d7c5477f528a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 18 Jan 2021 18:02:16 +0100 Subject: cleanup: remove slave background thread, use handle_manager thread instead --- sql/mysqld.cc | 15 +---- sql/mysqld.h | 4 +- sql/slave.cc | 172 +++++++++++----------------------------------------------- 3 files changed, 35 insertions(+), 156 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8d67bc53164..c0bf69b38b9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -385,7 +385,6 @@ static bool binlog_format_used= false; LEX_STRING opt_init_connect, opt_init_slave; mysql_cond_t COND_thread_cache; static mysql_cond_t COND_flush_thread_cache; -mysql_cond_t COND_slave_background; static DYNAMIC_ARRAY all_options; /* Global variables */ @@ -758,7 +757,7 @@ mysql_mutex_t LOCK_crypt, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, - LOCK_connection_count, LOCK_error_messages, LOCK_slave_background; + LOCK_connection_count, LOCK_error_messages; mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, LOCK_global_table_stats, LOCK_global_index_stats; @@ -947,8 +946,7 @@ PSI_mutex_key key_LOCK_stats, PSI_mutex_key key_LOCK_gtid_waiting; PSI_mutex_key key_LOCK_after_binlog_sync; -PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered, - key_LOCK_slave_background; +PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered; PSI_mutex_key key_TABLE_SHARE_LOCK_share; static PSI_mutex_info all_server_mutexes[]= @@ -1017,7 +1015,6 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_after_binlog_sync, "LOCK_after_binlog_sync", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, - { &key_LOCK_slave_background, "LOCK_slave_background", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, { &key_LOCK_thread_cache, "LOCK_thread_cache", PSI_FLAG_GLOBAL}, @@ -1074,7 +1071,7 @@ PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy; PSI_cond_key key_COND_rpl_thread_queue, key_COND_rpl_thread, key_COND_rpl_thread_stop, key_COND_rpl_thread_pool, key_COND_parallel_entry, key_COND_group_commit_orderer, - key_COND_prepare_ordered, key_COND_slave_background; + key_COND_prepare_ordered; PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; static PSI_cond_info all_server_conds[]= @@ -1124,7 +1121,6 @@ static PSI_cond_info all_server_conds[]= { &key_COND_parallel_entry, "COND_parallel_entry", 0}, { &key_COND_group_commit_orderer, "COND_group_commit_orderer", 0}, { &key_COND_prepare_ordered, "COND_prepare_ordered", 0}, - { &key_COND_slave_background, "COND_slave_background", 0}, { &key_COND_start_thread, "COND_start_thread", PSI_FLAG_GLOBAL}, { &key_COND_wait_gtid, "COND_wait_gtid", 0}, { &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0} @@ -2379,8 +2375,6 @@ static void clean_up_mutexes() mysql_cond_destroy(&COND_prepare_ordered); mysql_mutex_destroy(&LOCK_after_binlog_sync); mysql_mutex_destroy(&LOCK_commit_ordered); - mysql_mutex_destroy(&LOCK_slave_background); - mysql_cond_destroy(&COND_slave_background); DBUG_VOID_RETURN; } @@ -4838,9 +4832,6 @@ static int init_thread_environment() MY_MUTEX_INIT_SLOW); mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered, MY_MUTEX_INIT_SLOW); - mysql_mutex_init(key_LOCK_slave_background, &LOCK_slave_background, - MY_MUTEX_INIT_SLOW); - mysql_cond_init(key_COND_slave_background, &COND_slave_background, NULL); #ifdef HAVE_OPENSSL mysql_mutex_init(key_LOCK_des_key_file, diff --git a/sql/mysqld.h b/sql/mysqld.h index 2947734901c..64e5aef5946 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -568,8 +568,7 @@ extern mysql_mutex_t LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_user_conn, - LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count, - LOCK_slave_background; + LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_thread_count, LOCK_global_system_variables; extern mysql_mutex_t LOCK_start_thread; @@ -583,7 +582,6 @@ extern mysql_rwlock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern mysql_prlock_t LOCK_system_variables_hash; extern mysql_cond_t COND_thread_count, COND_start_thread; extern mysql_cond_t COND_manager; -extern mysql_cond_t COND_slave_background; extern int32 thread_running; extern int32 thread_count, service_thread_count; diff --git a/sql/slave.cc b/sql/slave.cc index 5685769bbfb..3124b2d10ab 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -60,6 +60,7 @@ #include "rpl_tblmap.h" #include "debug_sync.h" #include "rpl_parallel.h" +#include "sql_manager.h" #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -279,8 +280,6 @@ static void init_slave_psi_keys(void) #endif /* HAVE_PSI_INTERFACE */ -static bool slave_background_thread_running; -static bool slave_background_thread_stop; static bool slave_background_thread_gtid_loaded; struct slave_background_kill_t { @@ -289,24 +288,15 @@ struct slave_background_kill_t { } *slave_background_kill_list; -pthread_handler_t -handle_slave_background(void *arg __attribute__((unused))) +static void bg_rpl_load_gtid_slave_state(void *) { - THD *thd; - PSI_stage_info old_stage; - bool stop; - - my_thread_init(); - thd= new THD(next_thread_id()); + THD *thd= new THD(next_thread_id()); thd->thread_stack= (char*) &thd; /* Set approximate stack start */ thd->system_thread = SYSTEM_THREAD_SLAVE_BACKGROUND; - thread_safe_increment32(&service_thread_count); thd->store_globals(); thd->security_ctx->skip_grants(); thd->set_command(COM_DAEMON); -#ifdef WITH_WSREP thd->variables.wsrep_on= 0; -#endif thd_proc_info(thd, "Loading slave GTID position from table"); if (rpl_load_gtid_slave_state(thd)) @@ -316,136 +306,34 @@ handle_slave_background(void *arg __attribute__((unused))) thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); - mysql_mutex_lock(&LOCK_slave_background); + // hijacking global_rpl_thread_pool cond here - it's only once on startup + mysql_mutex_lock(&global_rpl_thread_pool.LOCK_rpl_thread_pool); slave_background_thread_gtid_loaded= true; - mysql_cond_broadcast(&COND_slave_background); - - THD_STAGE_INFO(thd, stage_slave_background_process_request); - do - { - slave_background_kill_t *kill_list; - - thd->ENTER_COND(&COND_slave_background, &LOCK_slave_background, - &stage_slave_background_wait_request, - &old_stage); - for (;;) - { - stop= abort_loop || thd->killed || slave_background_thread_stop; - kill_list= slave_background_kill_list; - if (stop || kill_list) - break; - mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); - } - - slave_background_kill_list= NULL; - thd->EXIT_COND(&old_stage); - - while (kill_list) - { - slave_background_kill_t *p = kill_list; - THD *to_kill= p->to_kill; - kill_list= p->next; - - mysql_mutex_lock(&to_kill->LOCK_thd_data); - to_kill->awake(KILL_CONNECTION); - mysql_mutex_unlock(&to_kill->LOCK_thd_data); - mysql_mutex_lock(&to_kill->LOCK_wakeup_ready); - to_kill->rgi_slave->killed_for_retry= - rpl_group_info::RETRY_KILL_KILLED; - mysql_cond_broadcast(&to_kill->COND_wakeup_ready); - mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready); - my_free(p); - } - mysql_mutex_lock(&LOCK_slave_background); - } while (!stop); - - slave_background_thread_running= false; - mysql_cond_broadcast(&COND_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); - + mysql_cond_signal(&global_rpl_thread_pool.COND_rpl_thread_pool); + mysql_mutex_unlock(&global_rpl_thread_pool.LOCK_rpl_thread_pool); delete thd; - thread_safe_decrement32(&service_thread_count); - signal_thd_deleted(); - - my_thread_end(); - return 0; } - - -void -slave_background_kill_request(THD *to_kill) +static void bg_slave_kill(void *victim) { - if (to_kill->rgi_slave->killed_for_retry) - return; // Already deadlock killed. - slave_background_kill_t *p= - (slave_background_kill_t *)my_malloc(sizeof(*p), MYF(MY_WME)); - if (p) - { - p->to_kill= to_kill; - to_kill->rgi_slave->killed_for_retry= - rpl_group_info::RETRY_KILL_PENDING; - mysql_mutex_lock(&LOCK_slave_background); - p->next= slave_background_kill_list; - slave_background_kill_list= p; - mysql_cond_signal(&COND_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); - } + THD *to_kill= (THD *)victim; + mysql_mutex_lock(&to_kill->LOCK_thd_data); + to_kill->awake(KILL_CONNECTION); + mysql_mutex_unlock(&to_kill->LOCK_thd_data); + mysql_mutex_lock(&to_kill->LOCK_wakeup_ready); + to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; + mysql_cond_broadcast(&to_kill->COND_wakeup_ready); + mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready); } - -/* - Start the slave background thread. - - This thread is currently used for two purposes: - - 1. To load the GTID state from mysql.gtid_slave_pos at server start; reading - from table requires valid THD, which is otherwise not available during - server init. - - 2. To kill worker thread transactions during parallel replication, when a - storage engine attempts to take an errorneous conflicting lock that would - cause a deadlock. Killing is done asynchroneously, as the kill may not - be safe within the context of a callback from inside storage engine - locking code. -*/ -static int -start_slave_background_thread() -{ - pthread_t th; - - slave_background_thread_running= true; - slave_background_thread_stop= false; - slave_background_thread_gtid_loaded= false; - if (mysql_thread_create(key_thread_slave_background, - &th, &connection_attrib, handle_slave_background, - NULL)) - { - sql_print_error("Failed to create thread while initialising slave"); - return 1; - } - - mysql_mutex_lock(&LOCK_slave_background); - while (!slave_background_thread_gtid_loaded) - mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); - - return 0; -} - - -static void -stop_slave_background_thread() +void slave_background_kill_request(THD *to_kill) { - mysql_mutex_lock(&LOCK_slave_background); - slave_background_thread_stop= true; - mysql_cond_broadcast(&COND_slave_background); - while (slave_background_thread_running) - mysql_cond_wait(&COND_slave_background, &LOCK_slave_background); - mysql_mutex_unlock(&LOCK_slave_background); + if (to_kill->rgi_slave->killed_for_retry) + return; // Already deadlock killed. + to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_PENDING; + mysql_manager_submit(bg_slave_kill, to_kill); } - /* Initialize slave structures */ int init_slave() @@ -457,12 +345,19 @@ int init_slave() init_slave_psi_keys(); #endif - if (start_slave_background_thread()) - return 1; - if (global_rpl_thread_pool.init(opt_slave_parallel_threads)) return 1; + slave_background_thread_gtid_loaded= false; + mysql_manager_submit(bg_rpl_load_gtid_slave_state, NULL); + + // hijacking global_rpl_thread_pool cond here - it's only once on startup + mysql_mutex_lock(&global_rpl_thread_pool.LOCK_rpl_thread_pool); + while (!slave_background_thread_gtid_loaded) + mysql_cond_wait(&global_rpl_thread_pool.COND_rpl_thread_pool, + &global_rpl_thread_pool.LOCK_rpl_thread_pool); + mysql_mutex_unlock(&global_rpl_thread_pool.LOCK_rpl_thread_pool); + /* This is called when mysqld starts. Before client connections are accepted. However bootstrap may conflict with us if it does START SLAVE. @@ -1080,7 +975,6 @@ void slave_prepare_for_shutdown() mysql_mutex_lock(&LOCK_active_mi); master_info_index->free_connections(); mysql_mutex_unlock(&LOCK_active_mi); - stop_slave_background_thread(); } /* @@ -1111,8 +1005,6 @@ void end_slave() active_mi= 0; mysql_mutex_unlock(&LOCK_active_mi); - stop_slave_background_thread(); - global_rpl_thread_pool.destroy(); free_all_rpl_filters(); DBUG_VOID_RETURN; @@ -4335,9 +4227,7 @@ pthread_handler_t handle_slave_io(void *arg) goto err; } -#ifdef WITH_WSREP thd->variables.wsrep_on= 0; -#endif if (RUN_HOOK(binlog_relay_io, thread_start, (thd, mi))) { mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL, -- cgit v1.2.1 From 5d1db34585bdedfcc1f6339c18ea2fce2cdb7ce3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 Jan 2021 15:22:26 +0100 Subject: cleanup: void hton::abort_transaction() and void wsrep_innobase_kill_one_trx() as their return values are never used. Also remove redundant cast and checks that are always true --- sql/handler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index 96f2836c921..6113b748696 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1237,7 +1237,7 @@ struct handlerton enum handler_create_iterator_result (*create_iterator)(handlerton *hton, enum handler_iterator_type type, struct handler_iterator *fill_this_in); - int (*abort_transaction)(handlerton *hton, THD *bf_thd, + void (*abort_transaction)(handlerton *hton, THD *bf_thd, THD *victim_thd, my_bool signal); int (*set_checkpoint)(handlerton *hton, const XID* xid); int (*get_checkpoint)(handlerton *hton, XID* xid); -- cgit v1.2.1 From 29bbcac0ee841faaa68eeb09c86ff825eabbe6b6 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 20 Jan 2021 18:22:38 +0100 Subject: MDEV-23328 Server hang due to Galera lock conflict resolution mutex order violation here. when wsrep bf thread kills a conflicting trx, the stack is wsrep_thd_LOCK() wsrep_kill_victim() lock_rec_other_has_conflicting() lock_clust_rec_read_check_and_lock() row_search_mvcc() ha_innobase::index_read() ha_innobase::rnd_pos() handler::ha_rnd_pos() handler::rnd_pos_by_record() handler::ha_rnd_pos_by_record() Rows_log_event::find_row() Update_rows_log_event::do_exec_row() Rows_log_event::do_apply_event() Log_event::apply_event() wsrep_apply_events() and mutexes are taken in the order lock_sys->mutex -> victim_trx->mutex -> victim_thread->LOCK_thd_data When a normal KILL statement is executed, the stack is innobase_kill_query() kill_handlerton() plugin_foreach_with_mask() ha_kill_query() THD::awake() kill_one_thread() and mutexes are victim_thread->LOCK_thd_data -> lock_sys->mutex -> victim_trx->mutex To fix the mutex order violation we kill the victim thd asynchronously, from the manager thread --- sql/wsrep_mysqld.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'sql') diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index d392d1c2a61..c033f7e1464 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2762,9 +2762,7 @@ extern "C" void wsrep_thd_awake(THD *thd, my_bool signal) { if (signal) { - mysql_mutex_lock(&thd->LOCK_thd_data); thd->awake(KILL_QUERY); - mysql_mutex_unlock(&thd->LOCK_thd_data); } else { -- cgit v1.2.1 From 8cdeee177d353e60f4a9cdebe6c851f9505d84b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 20 Jan 2021 09:38:20 +0200 Subject: MDEV-24509 : Warning: Memory not freed: 56 on SET @@global.wsrep_sst_auth It seems that memory is not freed when updated value is NULL or when wsrep is not initialized before shutdown. --- sql/mysqld.cc | 4 ++++ sql/wsrep_sst.cc | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c0bf69b38b9..55ed5a6a680 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2011,8 +2011,11 @@ static void __cdecl kill_server(int sig_ptr) close_connections(); +#ifdef WITH_WSREP if (wsrep_inited == 1) wsrep_deinit(true); + wsrep_sst_auth_free(); +#endif /* WITH_WSREP */ if (sig != MYSQL_KILL_SIGNAL && sig != 0) @@ -2132,6 +2135,7 @@ extern "C" void unireg_abort(int exit_code) /* In bootstrap mode we deinitialize wsrep here. */ if (opt_bootstrap && wsrep_inited) wsrep_deinit(true); + wsrep_sst_auth_free(); } #endif // WITH_WSREP diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 65a3f971c62..e12a26efbb6 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -149,6 +149,12 @@ static bool sst_auth_real_set (const char* value) if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); } wsrep_sst_auth= my_strdup(WSREP_SST_AUTH_MASK, MYF(0)); } + else + { + if (wsrep_sst_auth) { my_free((void*) wsrep_sst_auth); } + wsrep_sst_auth= NULL; + } + return 0; } return 1; -- cgit v1.2.1 From 20f6c403eb976a6dd25cb58d0ce17f6da2566253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 28 Jan 2021 10:31:57 +0200 Subject: MDEV-20717 : Plugin system variables and activation options can break "mysqld --wsrep_recover" Problem is that not all plugins are loaded when wsrep_recover is executed. Thus, we allow unknown system variables and extra system variables during wsrep_recover. Any unknown system variables would still be caught when the server starts up normally after the SST. --- sql/mysqld.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 55ed5a6a680..4bfac5c20d1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5417,6 +5417,10 @@ static int init_server_components() that there are unprocessed options. */ my_getopt_skip_unknown= 0; +#ifdef WITH_WSREP + if (wsrep_recovery) + my_getopt_skip_unknown= TRUE; +#endif if ((ho_error= handle_options(&remaining_argc, &remaining_argv, no_opts, mysqld_get_one_option))) @@ -5426,12 +5430,19 @@ static int init_server_components() remaining_argv--; my_getopt_skip_unknown= TRUE; - if (remaining_argc > 1) +#ifdef WITH_WSREP + if (!wsrep_recovery) { - fprintf(stderr, "%s: Too many arguments (first extra is '%s').\n", - my_progname, remaining_argv[1]); - unireg_abort(1); +#endif + if (remaining_argc > 1) + { + fprintf(stderr, "%s: Too many arguments (first extra is '%s').\n", + my_progname, remaining_argv[1]); + unireg_abort(1); + } +#ifdef WITH_WSREP } +#endif } if (opt_abort) -- cgit v1.2.1 From 33ede50f207552df835d7606f990fa9ccc4e0d12 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 28 Jan 2021 20:46:13 +0300 Subject: MDEV-22251: get_key_scans_params: Conditional jump or move depends on uninitialised value Apply the patch based on the patch by Varun Gupta: PARAM::is_ror_scan might be used unitialized when check_quick_select() is invoked for a "degenerate" SEL_ARG tree (e.g. one having type SEL_ARG::IMPOSSIBLE). Make check_quick_select() always initialize PARAM::is_ror_scan. --- sql/opt_range.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7785c768fbc..f3f184367c9 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -10385,6 +10385,7 @@ ha_rows check_quick_select(PARAM *param, uint idx, bool index_only, uint keynr= param->real_keynr[idx]; DBUG_ENTER("check_quick_select"); + param->is_ror_scan= FALSE; /* Handle cases when we don't have a valid non-empty list of range */ if (!tree) DBUG_RETURN(HA_POS_ERROR); -- cgit v1.2.1 From 17867608a2c3a13c909a2362ec5ee2a5a41547c1 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Fri, 29 Jan 2021 11:18:06 +0100 Subject: ASAN heap-use-after-free in Item_exists_subselect::is_top_level_item check that we can do type casting --- sql/item_cmpfunc.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d16c7413f0a..d5b89f13f04 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1234,7 +1234,9 @@ longlong Item_func_truth::val_int() bool Item_in_optimizer::is_top_level_item() { - return ((Item_in_subselect *)args[1])->is_top_level_item(); + if (!invisible_mode()) + return ((Item_in_subselect *)args[1])->is_top_level_item(); + return false; } -- cgit v1.2.1