summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJulius Goryavsky <julius.goryavsky@mariadb.com>2020-06-05 18:32:37 +0200
committerJulius Goryavsky <julius.goryavsky@mariadb.com>2020-06-05 18:32:37 +0200
commit5f55f69e4a237deb98cd4fc7d6ea9a17a8fe63bb (patch)
treed9031bb02e1807d0324b9f802dcf72eb8e3768a6 /sql
parentefc70da5fd0459ff44153529d13651741cc32bc4 (diff)
parent3f019d1771d4e6e21f941b72a83e0663f15b376f (diff)
downloadmariadb-git-5f55f69e4a237deb98cd4fc7d6ea9a17a8fe63bb.tar.gz
Merge 10.1 into 10.2
Diffstat (limited to 'sql')
-rw-r--r--sql/sp_head.cc89
-rw-r--r--sql/sql_trigger.cc15
-rw-r--r--sql/wsrep_hton.cc22
-rw-r--r--sql/wsrep_mysqld.cc9
-rw-r--r--sql/wsrep_thd.cc111
-rw-r--r--sql/wsrep_thd.h1
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();