diff options
author | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2020-06-05 18:32:37 +0200 |
---|---|---|
committer | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2020-06-05 18:32:37 +0200 |
commit | 5f55f69e4a237deb98cd4fc7d6ea9a17a8fe63bb (patch) | |
tree | d9031bb02e1807d0324b9f802dcf72eb8e3768a6 /sql | |
parent | efc70da5fd0459ff44153529d13651741cc32bc4 (diff) | |
parent | 3f019d1771d4e6e21f941b72a83e0663f15b376f (diff) | |
download | mariadb-git-5f55f69e4a237deb98cd4fc7d6ea9a17a8fe63bb.tar.gz |
Merge 10.1 into 10.2
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sp_head.cc | 89 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 15 | ||||
-rw-r--r-- | sql/wsrep_hton.cc | 22 | ||||
-rw-r--r-- | sql/wsrep_mysqld.cc | 9 | ||||
-rw-r--r-- | sql/wsrep_thd.cc | 111 | ||||
-rw-r--r-- | sql/wsrep_thd.h | 1 |
6 files changed, 237 insertions, 10 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1f5c6e96906..464f2df1506 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -45,6 +45,9 @@ #include "transaction.h" // trans_commit_stmt #include "sql_audit.h" #include "debug_sync.h" +#ifdef WITH_WSREP +#include "wsrep_thd.h" +#endif /* WITH_WSREP */ /* Sufficient max length of printed destinations and frame offsets (all uints). @@ -1318,7 +1321,93 @@ sp_head::execute(THD *thd, bool merge_da_on_success) thd->m_digest= NULL; err_status= i->execute(thd, &ip); +#ifdef WITH_WSREP + if (m_type == TYPE_ENUM_PROCEDURE) + { + mysql_mutex_lock(&thd->LOCK_thd_data); + if (thd->wsrep_conflict_state == MUST_REPLAY) + { + wsrep_replay_sp_transaction(thd); + err_status= thd->get_stmt_da()->is_set(); + thd->wsrep_conflict_state= NO_CONFLICT; + } + else if (thd->wsrep_conflict_state == ABORTED || + thd->wsrep_conflict_state == CERT_FAILURE) + { + /* + If the statement execution was BF aborted or was aborted + due to certification failure, clean up transaction here + and reset conflict state to NO_CONFLICT and thd->killed + to THD::NOT_KILLED. Error handling is done based on err_status + below. Error must have been raised by wsrep hton code before + entering here. + */ + DBUG_ASSERT(err_status); + DBUG_ASSERT(thd->get_stmt_da()->is_error()); + thd->wsrep_conflict_state= NO_CONFLICT; + thd->killed= NOT_KILLED; + } + mysql_mutex_unlock(&thd->LOCK_thd_data); + } +#endif /* WITH_WSREP */ +#ifdef WITH_WSREP_NO + if (WSREP(thd)) + { + if (((thd->wsrep_trx().state() == wsrep::transaction::s_executing) && + (thd->is_fatal_error || thd->killed))) + { + WSREP_DEBUG("SP abort err status %d in sub %d trx state %d", + err_status, thd->in_sub_stmt, thd->wsrep_trx().state()); + err_status= 1; + thd->is_fatal_error= 1; + /* + SP was killed, and it is not due to a wsrep conflict. + We skip after_command hook at this point because + otherwise it clears the error, and cleans up the + whole transaction. For now we just return and finish + our handling once we are back to mysql_parse. + */ + WSREP_DEBUG("Skipping after_command hook for killed SP"); + } + else + { + const bool must_replay= wsrep_must_replay(thd); + if (must_replay) + { + WSREP_DEBUG("MUST_REPLAY set after SP, err_status %d trx state: %d", + err_status, thd->wsrep_trx().state()); + } + (void) wsrep_after_statement(thd); + /* + Reset the return code to zero if the transaction was + replayed succesfully. + */ + if (must_replay && !wsrep_current_error(thd)) + { + err_status= 0; + thd->get_stmt_da()->reset_diagnostics_area(); + } + /* + Final wsrep error status for statement is known only after + wsrep_after_statement() call. If the error is set, override + error in thd diagnostics area and reset wsrep client_state error + so that the error does not get propagated via client-server protocol. + */ + if (wsrep_current_error(thd)) + { + wsrep_override_error(thd, wsrep_current_error(thd), + wsrep_current_error_status(thd)); + thd->wsrep_cs().reset_error(); + /* Reset also thd->killed if it has been set during BF abort. */ + if (thd->killed == KILL_QUERY) + thd->killed= NOT_KILLED; + /* if failed transaction was not replayed, must return with error from here */ + if (!must_replay) err_status = 1; + } + } + } +#endif /* WITH_WSREP */ thd->m_digest= parent_digest; if (i->free_list) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 2d1c3e1cafb..52817ef65ae 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -34,6 +34,9 @@ #include "sql_handler.h" // mysql_ha_rm_tables #include "sp_cache.h" // sp_invalidate_cache #include <mysys_err.h> +#ifdef WITH_WSREP +#include "debug_sync.h" +#endif /* WITH_WSREP */ LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, uint length, MEM_ROOT *mem_root) @@ -517,7 +520,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) #ifdef WITH_WSREP if (thd->wsrep_exec_mode == LOCAL_STATE) - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, tables); #endif /* We should have only one table in table list. */ @@ -579,6 +582,16 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) goto end; } +#ifdef WITH_WSREP + DBUG_EXECUTE_IF("sync.mdev_20225", + { + const char act[]= + "now " + "wait_for signal.mdev_20225_continue"; + DBUG_ASSERT(!debug_sync_set_action(thd, + STRING_WITH_LEN(act))); + };); +#endif /* WITH_WSREP */ result= (create ? table->triggers->create_trigger(thd, tables, &stmt_query): table->triggers->drop_trigger(thd, tables, &stmt_query)); diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index 459cd368355..575c57c5d24 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -37,6 +37,8 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd); void wsrep_cleanup_transaction(THD *thd) { if (!WSREP(thd)) return; + DBUG_ASSERT(thd->wsrep_conflict_state != MUST_REPLAY && + thd->wsrep_conflict_state != REPLAYING); if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd); thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; @@ -137,7 +139,11 @@ void wsrep_post_commit(THD* thd, bool all) /* non-InnoDB statements may have populated events in stmt cache => cleanup */ - WSREP_DEBUG("cleanup transaction for LOCAL_STATE"); + if (thd->wsrep_conflict_state != MUST_REPLAY) + { + WSREP_DEBUG("cleanup transaction for LOCAL_STATE: %s", + WSREP_QUERY(thd)); + } /* Run post-rollback hook to clean up in the case if some keys were populated for the transaction in provider @@ -146,13 +152,18 @@ void wsrep_post_commit(THD* thd, bool all) rolls back to savepoint after first operation. */ if (all && thd->wsrep_conflict_state != MUST_REPLAY && - wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) + thd->wsrep_conflict_state != REPLAYING && + wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) { WSREP_WARN("post_rollback fail: %llu %d", (long long)thd->thread_id, thd->get_stmt_da()->status()); } - wsrep_cleanup_transaction(thd); - break; + if (thd->wsrep_conflict_state != MUST_REPLAY && + thd->wsrep_conflict_state != REPLAYING) + { + wsrep_cleanup_transaction(thd); + } + break; } default: break; } @@ -566,7 +577,8 @@ wsrep_run_wsrep_commit(THD *thd, bool all) DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); /* fall through */ case WSREP_TRX_FAIL: - WSREP_DEBUG("commit failed for reason: %d", rcode); + WSREP_DEBUG("commit failed for reason: %d conf %d", + rcode, thd->wsrep_conflict_state); DBUG_PRINT("wsrep", ("replicating commit fail")); wsrep_thd_set_query_state(thd, QUERY_EXEC); diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index af50699af59..f95ef168a23 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1612,7 +1612,6 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, case SQLCOM_CREATE_TRIGGER: - DBUG_ASSERT(!table_list); DBUG_ASSERT(first_table); if (thd->find_temporary_table(first_table)) @@ -1621,6 +1620,14 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } return true; + case SQLCOM_DROP_TRIGGER: + DBUG_ASSERT(table_list); + if (thd->find_temporary_table(table_list)) + { + return false; + } + return true; + default: if (table && !thd->find_temporary_table(db, table)) { diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index a7b6e8ff1b1..1e60088c5f1 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -93,10 +93,12 @@ void wsrep_client_rollback(THD *thd) #define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1 #define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2 -static rpl_group_info* wsrep_relay_group_init(const char* log_fname) +static rpl_group_info* wsrep_relay_group_init(THD *thd, const char* log_fname) { Relay_log_info* rli= new Relay_log_info(false); + WSREP_DEBUG("wsrep_relay_group_init %s", log_fname); + if (!rli->relay_log.description_event_for_exec) { rli->relay_log.description_event_for_exec= @@ -125,7 +127,7 @@ static rpl_group_info* wsrep_relay_group_init(const char* log_fname) rli->mi = new Master_info(&connection_name, false); struct rpl_group_info *rgi= new rpl_group_info(rli); - rgi->thd= rli->sql_driver_thd= current_thd; + rgi->thd= rli->sql_driver_thd= thd; if ((rgi->deferred_events_collecting= rli->mi->rpl_filter->is_on())) { @@ -150,7 +152,7 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) else thd->variables.option_bits&= ~(OPTION_BIN_LOG); - if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init("wsrep_relay"); + if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init(thd, "wsrep_relay"); /* thd->system_thread_info.rpl_sql_info isn't initialized. */ if (!thd->slave_thread) @@ -193,6 +195,109 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) thd->set_row_count_func(shadow->row_count_func); } +void wsrep_replay_sp_transaction(THD* thd) +{ + DBUG_ENTER("wsrep_replay_sp_transaction"); + mysql_mutex_assert_owner(&thd->LOCK_thd_data); + DBUG_ASSERT(thd->wsrep_conflict_state == MUST_REPLAY); + DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0); + + WSREP_DEBUG("replaying SP transaction %llu", thd->thread_id); + close_thread_tables(thd); + if (thd->locked_tables_mode && thd->lock) + { + WSREP_DEBUG("releasing table lock for replaying (%u)", + thd->thread_id); + thd->locked_tables_list.unlock_locked_tables(thd); + thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); + } + thd->mdl_context.release_transactional_locks(); + + mysql_mutex_unlock(&thd->LOCK_thd_data); + THD *replay_thd= new THD(true); + replay_thd->thread_stack= thd->thread_stack; + + struct wsrep_thd_shadow shadow; + wsrep_prepare_bf_thd(replay_thd, &shadow); + WSREP_DEBUG("replaying set for %p rgi %p", replay_thd, replay_thd->wsrep_rgi); replay_thd->wsrep_trx_meta= thd->wsrep_trx_meta; + replay_thd->wsrep_ws_handle= thd->wsrep_ws_handle; + replay_thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; + replay_thd->wsrep_conflict_state= REPLAYING; + + replay_thd->variables.option_bits|= OPTION_BEGIN; + replay_thd->server_status|= SERVER_STATUS_IN_TRANS; + + thd->reset_globals(); + replay_thd->store_globals(); + wsrep_status_t rcode= wsrep->replay_trx(wsrep, + &replay_thd->wsrep_ws_handle, + (void*) replay_thd); + + wsrep_return_from_bf_mode(replay_thd, &shadow); + replay_thd->reset_globals(); + delete replay_thd; + + mysql_mutex_lock(&thd->LOCK_thd_data); + + thd->store_globals(); + + switch (rcode) + { + case WSREP_OK: + { + thd->wsrep_conflict_state= NO_CONFLICT; + thd->killed= NOT_KILLED; + wsrep_status_t rcode= wsrep->post_commit(wsrep, &thd->wsrep_ws_handle); + if (rcode != WSREP_OK) + { + WSREP_WARN("Post commit failed for SP replay: thd: %u error: %d", + thd->thread_id, rcode); + } + /* As replaying the transaction was successful, an error must not + be returned to client, so we need to reset the error state of + the diagnostics area */ + thd->get_stmt_da()->reset_diagnostics_area(); + break; + } + case WSREP_TRX_FAIL: + { + thd->wsrep_conflict_state= ABORTED; + wsrep_status_t rcode= wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle); + if (rcode != WSREP_OK) + { + WSREP_WARN("Post rollback failed for SP replay: thd: %u error: %d", + thd->thread_id, rcode); + } + if (thd->get_stmt_da()->is_set()) + { + thd->get_stmt_da()->reset_diagnostics_area(); + } + my_error(ER_LOCK_DEADLOCK, MYF(0)); + break; + } + default: + WSREP_ERROR("trx_replay failed for: %d, schema: %s, query: %s", + rcode, + (thd->db ? thd->db : "(null)"), + WSREP_QUERY(thd)); + /* we're now in inconsistent state, must abort */ + mysql_mutex_unlock(&thd->LOCK_thd_data); + unireg_abort(1); + break; + } + + wsrep_cleanup_transaction(thd); + + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + WSREP_DEBUG("replaying decreased: %d, thd: %u", + wsrep_replaying, thd->thread_id); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + DBUG_VOID_RETURN; +} + void wsrep_replay_transaction(THD *thd) { DBUG_ENTER("wsrep_replay_transaction"); diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index 8d928014518..10efcbefbf6 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -25,6 +25,7 @@ int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff, enum enum_var_type scope); void wsrep_client_rollback(THD *thd); +void wsrep_replay_sp_transaction(THD* thd); void wsrep_replay_transaction(THD *thd); bool wsrep_create_appliers(long threads, bool thread_count_lock=false); void wsrep_create_rollbacker(); |