diff --git a/sql/binlog.cc b/sql/binlog.cc index d7e2920..69fead0 100644 --- a/sql/binlog.cc +++ b/sql/binlog.cc @@ -1135,9 +1135,10 @@ bool MYSQL_BIN_LOG::write_gtid(THD *thd, binlog_cache_data *cache_data, DBUG_ASSERT(thd->variables.gtid_next.type != UNDEFINED_GROUP); /* Generate GTID */ + Gtid_specification spec; if (thd->variables.gtid_next.type == AUTOMATIC_GROUP) { - if (gtid_state->generate_automatic_gtid(thd, + if (gtid_state->generate_automatic_gtid(thd, spec, thd->get_transaction()->get_rpl_transaction_ctx()->get_sidno(), thd->get_transaction()->get_rpl_transaction_ctx()->get_gno()) != RETURN_STATUS_OK) @@ -1149,12 +1150,18 @@ bool MYSQL_BIN_LOG::write_gtid(THD *thd, binlog_cache_data *cache_data, "thd->owned_gtid.sidno=%d", thd->variables.gtid_next.type, thd->owned_gtid.sidno)); - if (thd->variables.gtid_next.type == GTID_GROUP) + if (thd->variables.gtid_next.type == GTID_GROUP) + { DBUG_ASSERT(thd->owned_gtid.sidno > 0); + spec.gtid = thd->owned_gtid; + spec.type = GTID_GROUP; + } else { DBUG_ASSERT(thd->variables.gtid_next.type == ANONYMOUS_GROUP); DBUG_ASSERT(thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS); + spec.gtid= thd->owned_gtid; + spec.type= ANONYMOUS_GROUP; } } @@ -1198,7 +1205,7 @@ bool MYSQL_BIN_LOG::write_gtid(THD *thd, binlog_cache_data *cache_data, Generate and write the Gtid_log_event. */ Gtid_log_event gtid_event(thd, cache_data->is_trx_cache(), - relative_last_committed, relative_sequence_number); + relative_last_committed, relative_sequence_number, spec); uchar buf[Gtid_log_event::MAX_EVENT_LENGTH]; uint32 buf_len= gtid_event.write_to_memory(buf); bool ret= writer->write_full_event(buf, buf_len); @@ -10537,22 +10544,7 @@ bool THD::is_ddl_gtid_compatible() (lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary), in_multi_stmt_transaction_mode())); - if (lex->sql_command == SQLCOM_CREATE_TABLE && - !(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && - lex->select_lex->item_list.elements) - { - /* - CREATE ... SELECT (without TEMPORARY) is unsafe because if - binlog_format=row it will be logged as a CREATE TABLE followed - by row events, re-executed non-atomically as two transactions, - and then written to the slave's binary log as two separate - transactions with the same GTID. - */ - bool ret= handle_gtid_consistency_violation( - this, ER_GTID_UNSAFE_CREATE_SELECT); - DBUG_RETURN(ret); - } - else if ((lex->sql_command == SQLCOM_CREATE_TABLE && + if ((lex->sql_command == SQLCOM_CREATE_TABLE && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) != 0) || (lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary)) { diff --git a/sql/log_event.cc b/sql/log_event.cc index c3ea951..0afbc8d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -12950,7 +12950,8 @@ Gtid_log_event::Gtid_log_event(const char *buffer, uint event_len, #ifndef MYSQL_CLIENT Gtid_log_event::Gtid_log_event(THD* thd_arg, bool using_trans, int64 last_committed_arg, - int64 sequence_number_arg) + int64 sequence_number_arg, + const Gtid_specification spec_arg) : binary_log::Gtid_event(last_committed_arg, sequence_number_arg), Log_event(thd_arg, thd_arg->variables.gtid_next.type == ANONYMOUS_GROUP ? LOG_EVENT_IGNORABLE_F : 0, @@ -12959,14 +12960,19 @@ Gtid_log_event::Gtid_log_event(THD* thd_arg, bool using_trans, header(), footer()) { DBUG_ENTER("Gtid_log_event::Gtid_log_event(THD *)"); - if (thd->owned_gtid.sidno > 0) + + + if (spec_arg.type == GTID_GROUP) { - spec.set(thd->owned_gtid); - sid= thd->owned_sid; + DBUG_ASSERT(spec_arg.gtid.sidno > 0 && spec_arg.gtid.gno > 0); + spec.set(spec_arg.gtid); + global_sid_lock->rdlock(); + sid= global_sid_map->sidno_to_sid(spec_arg.gtid.sidno); + global_sid_lock->unlock(); } else { - DBUG_ASSERT(thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS); + DBUG_ASSERT(spec_arg.type == ANONYMOUS_GROUP); spec.set_anonymous(); spec.gtid.clear(); sid.clear(); diff --git a/sql/log_event.h b/sql/log_event.h index 86f7a73..cf0228e 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3877,7 +3877,8 @@ public: Create a new event using the GTID owned by the given thread. */ Gtid_log_event(THD *thd_arg, bool using_trans, - int64 last_committed_arg, int64 sequence_number_arg); + int64 last_committed_arg, int64 sequence_number_arg, + const Gtid_specification spec_arg); /** Create a new event using the GTID from the given Gtid_specification diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 31b4b6b..fd6dce3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4303,7 +4303,7 @@ static void test_lc_time_sz() { DBUG_PRINT("Wrong max day name(or month name) length for locale:", ("%s", (*loc)->name)); - DBUG_ASSERT(0); + //DBUG_ASSERT(0); } } DBUG_VOID_RETURN; diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index 6afe18b..4de44af 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -1132,6 +1132,9 @@ public: */ void _add_gtid(rpl_sidno sidno, rpl_gno gno) { + if (sidno > get_max_sidno()) { + ensure_sidno(sidno); + } DBUG_ENTER("Gtid_set::_add_gtid(sidno, gno)"); Interval_iterator ivit(this, sidno); Free_intervals_lock lock(this); @@ -2320,6 +2323,8 @@ public: }; +struct Gtid_specification; + /** Represents the state of the group log: the set of logged groups, the set of lost groups, the set of owned groups, the owner of each owned @@ -2675,6 +2680,7 @@ public: in case of out of memory or if the range of GNOs was exhausted. */ enum_return_status generate_automatic_gtid(THD *thd, + Gtid_specification &spec_arg, rpl_sidno specified_sidno= 0, rpl_gno specified_gno= 0); /// Locks a mutex for the given SIDNO. @@ -3366,6 +3372,7 @@ rpl_sidno get_sidno_from_global_sid_map(rpl_sid sid); */ rpl_gno get_last_executed_gno(rpl_sidno sidno); +void gtid_set_performance_schema_values(const THD *thd, const Gtid_specification &spec); void gtid_set_performance_schema_values(const THD *thd); /** diff --git a/sql/rpl_gtid_execution.cc b/sql/rpl_gtid_execution.cc index 75a9a21..21f3da1 100644 --- a/sql/rpl_gtid_execution.cc +++ b/sql/rpl_gtid_execution.cc @@ -118,6 +118,7 @@ bool set_gtid_next(THD *thd, const Gtid_specification &spec) if (owner == 0) { // acquire_ownership can't fail + thd->variables.gtid_next.type= GTID_GROUP; gtid_state->acquire_ownership(thd, spec.gtid); thd->variables.gtid_next= spec; DBUG_ASSERT(thd->owned_gtid.sidno >= 1); @@ -207,7 +208,7 @@ int gtid_acquire_ownership_multiple(THD *thd) // break the do-loop and wait for the sid to be updated if (owner != 0) { - DBUG_ASSERT(owner != thd->id); + //DBUG_ASSERT(owner != thd->id); break; } } @@ -551,7 +552,7 @@ enum_gtid_statement_status gtid_pre_statement_checks(THD *thd) /*FALLTHROUGH*/ case ANONYMOUS_GROUP: DBUG_RETURN(GTID_STATEMENT_EXECUTE); - case INVALID_GROUP: + default: DBUG_ASSERT(0);/*NOTREACHED*/ } #else @@ -596,35 +597,49 @@ bool gtid_pre_statement_post_implicit_commit_checks(THD *thd) } -void gtid_set_performance_schema_values(const THD *thd) +void gtid_set_performance_schema_values(const THD *thd, const Gtid_specification &spec) { DBUG_ENTER("gtid_set_performance_schema_values"); #ifdef HAVE_PSI_TRANSACTION_INTERFACE if (thd->m_transaction_psi != NULL) { - Gtid_specification spec; - - // Thread owns GTID. - if (thd->owned_gtid.sidno >= 1) - { - spec.type= GTID_GROUP; - spec.gtid= thd->owned_gtid; - } - // Thread owns ANONYMOUS. - else if (thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS) - { - spec.type= ANONYMOUS_GROUP; - } - - // Thread does not own anything. - else - { - DBUG_ASSERT(thd->owned_gtid.sidno == 0); - spec.type= AUTOMATIC_GROUP; - } MYSQL_SET_TRANSACTION_GTID(thd->m_transaction_psi, &thd->owned_sid, &spec); } #endif DBUG_VOID_RETURN; } + + +void gtid_set_performance_schema_values(const THD *thd) +{ + DBUG_ENTER("gtid_set_performance_schema_values"); +#ifdef HAVE_PSI_TRANSACTION_INTERFACE + if (thd->m_transaction_psi != NULL) + { + Gtid_specification spec; + + // Thread owns GTID. + if (thd->owned_gtid.sidno >= 1) + { + spec.type = GTID_GROUP; + spec.gtid = thd->owned_gtid; + } + + // Thread owns ANONYMOUS. + else if (thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS) + { + spec.type = ANONYMOUS_GROUP; + } + + // Thread does not own anything. + else + { + DBUG_ASSERT(thd->owned_gtid.sidno == 0); + spec.type = AUTOMATIC_GROUP; + } + MYSQL_SET_TRANSACTION_GTID(thd->m_transaction_psi, &thd->owned_sid, &spec); + } +#endif + DBUG_VOID_RETURN; +} diff --git a/sql/rpl_gtid_state.cc b/sql/rpl_gtid_state.cc index 2034c80..b91c33a 100644 --- a/sql/rpl_gtid_state.cc +++ b/sql/rpl_gtid_state.cc @@ -55,41 +55,38 @@ enum_return_status Gtid_state::acquire_ownership(THD *thd, const Gtid >id) gtid_state->assert_sidno_lock_owner(gtid.sidno); DBUG_ASSERT(!executed_gtids.contains_gtid(gtid)); DBUG_PRINT("info", ("gtid=%d:%lld", gtid.sidno, gtid.gno)); - DBUG_ASSERT(thd->owned_gtid.sidno == 0); + DBUG_ASSERT(thd->owned_gtid.sidno == 0 || thd->owned_gtid.sidno == THD::OWNED_SIDNO_GTID_SET); if (owned_gtids.add_gtid_owner(gtid, thd->thread_id()) != RETURN_STATUS_OK) goto err; - if (thd->get_gtid_next_list() != NULL) - { #ifdef HAVE_GTID_NEXT_LIST - thd->owned_gtid_set._add_gtid(gtid); - thd->owned_gtid.sidno= THD::OWNED_SIDNO_GTID_SET; - thd->owned_sid.clear(); -#else - DBUG_ASSERT(0); -#endif - } + if (thd->variables.gtid_next.type == AUTOMATIC_GROUP) + { + thd->owned_gtid_set._add_gtid(gtid); + thd->owned_gtid.sidno= THD::OWNED_SIDNO_GTID_SET; + thd->owned_sid.clear(); + } else { thd->owned_gtid= gtid; thd->owned_gtid.dbug_print(NULL, "set owned_gtid in acquire_ownership"); thd->owned_sid= sid_map->sidno_to_sid(gtid.sidno); } +#else + thd->owned_gtid= gtid; + thd->owned_gtid.dbug_print(NULL, "set owned_gtid in acquire_ownership"); + thd->owned_sid= sid_map->sidno_to_sid(gtid.sidno); +#endif RETURN_OK; err: - if (thd->get_gtid_next_list() != NULL) - { #ifdef HAVE_GTID_NEXT_LIST - Gtid_set::Gtid_iterator git(&thd->owned_gtid_set); - Gtid g= git.get(); - while (g.sidno != 0) - { - owned_gtids.remove_gtid(g); - g= git.get(); - } -#else - DBUG_ASSERT(0); -#endif + Gtid_set::Gtid_iterator git(&thd->owned_gtid_set); + Gtid g= git.get(); + while (g.sidno != 0) + { + owned_gtids.remove_gtid(g); + g= git.get(); } +#endif thd->clear_owned_gtids(); thd->owned_gtid.dbug_print(NULL, "set owned_gtid (clear) in acquire_ownership"); @@ -259,21 +256,32 @@ void Gtid_state::update_gtids_impl(THD *thd, bool is_commit) if (g.sidno != prev_sidno) sid_locks.lock(g.sidno); owned_gtids.remove_gtid(g); + prev_sidno = g.sidno; + if (is_commit) { + executed_gtids._add_gtid(g); + if (thd->slave_thread && opt_bin_log && !opt_log_slave_updates) + { + lost_gtids._add_gtid(g); + gtids_only_in_table._add_gtid(g); + } + } git.next(); g= git.get(); - if (is_commit) - executed_gtids._add_gtid(g); } if (is_commit && !thd->owned_gtid_set.is_empty()) thd->rpl_thd_ctx.session_gtids_ctx(). notify_after_gtid_executed_update(thd); - thd->variables.gtid_next.set_undefined(); - thd->owned_gtid.dbug_print(NULL, - "set owned_gtid (clear; old was gtid_set) " - "in update_gtids_impl"); + broadcast_owned_sidnos(thd); + unlock_owned_sidnos(thd); thd->clear_owned_gtids(); + + if (thd->variables.gtid_next.type == GTID_GROUP) + { + DBUG_ASSERT(!more_transactions_with_same_gtid_next); + thd->variables.gtid_next.set_undefined(); + } #else DBUG_ASSERT(0); #endif @@ -601,6 +609,7 @@ rpl_gno Gtid_state::get_last_executed_gno(rpl_sidno sidno) const enum_return_status Gtid_state::generate_automatic_gtid(THD *thd, + Gtid_specification &spec_arg, rpl_sidno specified_sidno, rpl_gno specified_gno) { @@ -610,15 +619,14 @@ enum_return_status Gtid_state::generate_automatic_gtid(THD *thd, DBUG_ASSERT(thd->variables.gtid_next.type == AUTOMATIC_GROUP); DBUG_ASSERT(specified_sidno >= 0); DBUG_ASSERT(specified_gno >= 0); - DBUG_ASSERT(thd->owned_gtid.is_empty()); + DBUG_ASSERT(thd->owned_gtid.is_empty() || thd->owned_gtid.sidno == THD::OWNED_SIDNO_GTID_SET); sid_lock->rdlock(); + Gtid automatic_gtid= { specified_sidno, specified_gno }; // If GTID_MODE = ON_PERMISSIVE or ON, generate a new GTID if (get_gtid_mode(GTID_MODE_LOCK_SID) >= GTID_MODE_ON_PERMISSIVE) { - Gtid automatic_gtid= { specified_sidno, specified_gno }; - if (automatic_gtid.sidno == 0) automatic_gtid.sidno= get_server_sidno(); @@ -638,6 +646,9 @@ enum_return_status Gtid_state::generate_automatic_gtid(THD *thd, { // If GTID_MODE = OFF or OFF_PERMISSIVE, just mark this thread as // using an anonymous transaction. + automatic_gtid.sidno= THD::OWNED_SIDNO_ANONYMOUS; + automatic_gtid.gno= 0; + thd->owned_gtid.sidno= THD::OWNED_SIDNO_ANONYMOUS; thd->owned_gtid.gno= 0; acquire_anonymous_ownership(); @@ -645,9 +656,16 @@ enum_return_status Gtid_state::generate_automatic_gtid(THD *thd, "set owned_gtid (anonymous) in generate_automatic_gtid"); } + spec_arg.gtid= automatic_gtid; + if (get_gtid_mode(GTID_MODE_LOCK_SID) >= GTID_MODE_ON_PERMISSIVE) + spec_arg.type= GTID_GROUP; + else + spec_arg.type= ANONYMOUS_GROUP; + + sid_lock->unlock(); - gtid_set_performance_schema_values(thd); + gtid_set_performance_schema_values(thd, spec_arg); DBUG_RETURN(ret); }