diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index d82d75eb36e5e..2709988d263f6 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -2173,7 +2173,8 @@ rpl_group_info::rpl_group_info(Relay_log_info *rli) deferred_events(NULL), m_annotate_event(0), is_parallel_exec(false), gtid_ev_flags2(0), gtid_ev_flags_extra(0), gtid_ev_sa_seq_no(0), reserved_start_alter_thread(0), finish_event_group_called(0), rpt(NULL), - start_alter_ev(NULL), direct_commit_alter(false), sa_info(NULL) + start_alter_ev(NULL), direct_commit_alter(false), sa_info(NULL), + is_new_trans(false) { reinit(rli); bzero(¤t_gtid, sizeof(current_gtid)); diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 3610e5258cfa8..9b8ff5b9746f4 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -950,7 +950,7 @@ struct rpl_group_info Query_log_event *start_alter_ev; bool direct_commit_alter; start_alter_info *sa_info; - + bool is_new_trans; // marker of start_new_trans context rpl_group_info(Relay_log_info *rli_); ~rpl_group_info(); void reinit(Relay_log_info *rli); @@ -1075,6 +1075,30 @@ struct rpl_group_info }; +/** + The function + @return true when the slave applier context is normal + false when either no slave applier around or + the applier is executing start_new_trans + */ +inline bool not_new_trans(rpl_group_info* rgi) +{ + return rgi && !rgi->is_new_trans; +} +/** + The following functions for start_new_trans' ctor and dtor. +*/ +inline void mark_in_new_trans(rpl_group_info* rgi) +{ + if (rgi) + rgi->is_new_trans= true; +} +inline void unmark_in_new_trans(rpl_group_info* rgi) +{ + if (rgi) + rgi->is_new_trans= false; +} + /* The class rpl_sql_thread_info is the THD::system_thread_info for an SQL diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0278a44723c6d..1022bcb43aa9c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6678,8 +6678,7 @@ start_new_trans::start_new_trans(THD *thd) thd->server_status&= ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); thd->server_status|= SERVER_STATUS_AUTOCOMMIT; - org_rgi_slave= thd->rgi_slave; - thd->rgi_slave= NULL; + mark_in_new_trans(thd->rgi_slave); } @@ -6696,7 +6695,7 @@ void start_new_trans::restore_old_transaction() MYSQL_COMMIT_TRANSACTION(org_thd->m_transaction_psi); org_thd->m_transaction_psi= m_transaction_psi; org_thd->variables.wsrep_on= wsrep_on; - org_thd->rgi_slave= org_rgi_slave; + unmark_in_new_trans(org_thd->rgi_slave); org_thd= 0; } diff --git a/sql/sql_class.h b/sql/sql_class.h index cc56151cde32e..6ee9979397826 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6314,11 +6314,6 @@ class start_new_trans uint in_sub_stmt; uint server_status; my_bool wsrep_on; - /* - THD:rgi_slave may hold a part of the replicated "old" transaction's - execution context. Therefore it has to be reset/restored too. - */ - rpl_group_info* org_rgi_slave; public: start_new_trans(THD *thd); diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index bb6a1605257ea..29f3e76c392a3 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -948,6 +948,8 @@ void THD::restore_tmp_table_share(TMP_TABLE_SHARE *share) If its a replication slave, report whether slave temporary tables exist (Relay_log_info::save_temporary_tables) or report about THD temporary table (Open_tables_state::temporary_tables) otherwise. + Note start-new-trans context is not about replication transaction + in which case the function uses the non-slave normal branch. @return false Temporary tables exist true No temporary table exist @@ -957,7 +959,14 @@ bool THD::has_temporary_tables() DBUG_ENTER("THD::has_temporary_tables"); bool result; #ifdef HAVE_REPLICATION - if (rgi_slave) + /* + Slave applier thread may execute an out-of-band "new-transaction" + and do so in the middle of a replicated transaction processing. + All functions that open the access to slave temporary table repository + including the current one have to deny it within the start-new-transaction + context. + */ + if (not_new_trans(rgi_slave)) { mysql_mutex_lock(&rgi_slave->rli->data_lock); result= rgi_slave->rli->save_temporary_tables && @@ -1062,7 +1071,8 @@ TMP_TABLE_SHARE *THD::create_temporary_table(LEX_CUSTRING *frm, during cleanup() from Relay_log_info::close_temporary_tables() */ init_tmp_table_share(this, share, saved_key_cache, key_length, - strend(saved_key_cache) + 1, tmp_path, !slave_thread); + strend(saved_key_cache) + 1, tmp_path, + !not_new_trans(rgi_slave)); /* Prefer using frm image over file. The image might not be available in @@ -1218,7 +1228,7 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, In replication, temporary tables are not confined to a single thread/THD. */ - if (slave_thread) + if (not_new_trans(rgi_slave)) flags|= HA_OPEN_GLOBAL_TMP_TABLE; if (open_table_from_share(this, share, &alias, (uint) HA_OPEN_KEYFILE, @@ -1240,7 +1250,7 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, share->all_tmp_tables.push_front(table); /* Increment Slave_open_temp_table_definitions status variable count. */ - if (rgi_slave) + if (not_new_trans(rgi_slave)) slave_open_temp_tables++; DBUG_PRINT("tmptable", ("Opened table: '%s'.'%s table: %p", @@ -1656,6 +1666,8 @@ void THD::free_temporary_table(TABLE *table) /** On replication slave, acquire the Relay_log_info's data_lock and use slave temporary tables. + Note start-new-trans context is not about replication transaction + in which case the function returns false. @return true Lock acquired false Lock wasn't acquired @@ -1671,7 +1683,7 @@ bool THD::lock_temporary_tables() } #ifdef HAVE_REPLICATION - if (rgi_slave) + if (not_new_trans(rgi_slave)) /* see has_temporary_tables comments */ { mysql_mutex_lock(&rgi_slave->rli->data_lock); temporary_tables= rgi_slave->rli->save_temporary_tables; @@ -1699,7 +1711,7 @@ void THD::unlock_temporary_tables() } #ifdef HAVE_REPLICATION - if (rgi_slave) + if (not_new_trans(rgi_slave)) /* ditto lock */ { rgi_slave->rli->save_temporary_tables= temporary_tables; temporary_tables= NULL; /* Safety */