summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-09-24 16:21:20 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-09-24 16:21:20 +0300
commitf59f5c4a10151b18d1407065ca48746384b6a25a (patch)
treee91c6e0da25434d21224159656fa6cae925245a0 /storage
parentcfe1a258e884a4e21df9c752c2c3351da96bfb1d (diff)
downloadmariadb-git-f59f5c4a10151b18d1407065ca48746384b6a25a.tar.gz
Revert MDEV-25114
Revert 88a4be75a5f3b8d59ac8f6347ff2c197813c05dc and 9d97f92febc89941784d17d59c60275e21140ce0, which had been prematurely pushed by accident.
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/handler/ha_innodb.cc310
-rw-r--r--storage/innobase/include/ha_prototypes.h3
2 files changed, 158 insertions, 155 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 921b8282e45..a42e8e3699c 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -60,6 +60,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include <my_service_manager.h>
#include <key.h>
+#include <sql_manager.h>
/* Include necessary InnoDB headers */
#include "btr0btr.h"
@@ -5233,21 +5234,17 @@ UNIV_INTERN void lock_cancel_waiting_and_release(lock_t* lock);
@sa THD::awake() @sa ha_kill_query() */
static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
{
- DBUG_ENTER("innobase_kill_query");
+ DBUG_ENTER("innobase_kill_query");
#ifdef WITH_WSREP
- if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT)
- {
- /* if victim has been signaled by BF thread and/or aborting
- is already progressing, following query aborting is not necessary
- any more. E.g. wsrep_innobase_kill_one_trx().
- Also, BF thread should own trx mutex for the victim, which would
- conflict with trx_mutex_enter() below
- */
- WSREP_DEBUG("Victim thread %ld bail out conflict_state %s query %s",
- thd_get_thread_id(thd),
- wsrep_thd_conflict_state_str(thd), wsrep_thd_query(thd));
- DBUG_VOID_RETURN;
- }
+ if (wsrep_thd_get_conflict_state(thd) != NO_CONFLICT) {
+ /* if victim has been signaled by BF thread and/or aborting
+ is already progressing, following query aborting is not necessary
+ any more.
+ Also, BF thread should own trx mutex for the victim, which would
+ conflict with trx_mutex_enter() below
+ */
+ DBUG_VOID_RETURN;
+ }
#endif /* WITH_WSREP */
if (trx_t* trx= thd_to_trx(thd))
@@ -19502,9 +19499,9 @@ static struct st_mysql_storage_engine innobase_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
#ifdef WITH_WSREP
-static
void
wsrep_abort_slave_trx(
+/*==================*/
wsrep_seqno_t bf_seqno,
wsrep_seqno_t victim_seqno)
{
@@ -19514,97 +19511,93 @@ wsrep_abort_slave_trx(
"2) a bug in the code.\n\t"
"3) a database corruption.\n Node consistency compromized, "
"need to abort. Restart the node to resync with cluster.",
- bf_seqno, victim_seqno);
+ (long long)bf_seqno, (long long)victim_seqno);
abort();
}
-/*******************************************************************//**
-This function is used to kill one transaction in BF. */
-void
-wsrep_innobase_kill_one_trx(
- MYSQL_THD const bf_thd,
- const trx_t * const bf_trx,
- trx_t *victim_trx,
- my_bool signal)
+
+struct bg_wsrep_kill_trx_arg {
+ my_thread_id thd_id;
+ trx_id_t trx_id;
+ int64_t bf_seqno;
+ ibool signal;
+};
+
+static void bg_wsrep_kill_trx(
+ void *void_arg)
{
- ut_ad(bf_thd);
- ut_ad(victim_trx);
- ut_ad(lock_mutex_own());
- ut_ad(trx_mutex_own(victim_trx));
+ bg_wsrep_kill_trx_arg *arg = (bg_wsrep_kill_trx_arg*)void_arg;
+ THD *thd = find_thread_by_id(arg->thd_id, false);
+ trx_t *victim_trx = NULL;
+ bool awake = false;
+ DBUG_ENTER("bg_wsrep_kill_trx");
- DBUG_ENTER("wsrep_innobase_kill_one_trx");
- THD *thd= (THD *) victim_trx->mysql_thd;
- int64_t bf_seqno= wsrep_thd_trx_seqno(bf_thd);
+ if (thd) {
+ victim_trx= thd_to_trx(thd);
+ /* Victim trx might not exist e.g. on MDL-conflict. */
+ if (victim_trx) {
+ lock_mutex_enter();
+ trx_mutex_enter(victim_trx);
+ if (victim_trx->id != arg->trx_id ||
+ victim_trx->state == TRX_STATE_COMMITTED_IN_MEMORY)
+ {
+ /* Victim was meanwhile rolled back or
+ committed */
+ trx_mutex_exit(victim_trx);
+ lock_mutex_exit();
+ wsrep_thd_UNLOCK(thd);
+ victim_trx= NULL;
+ }
+ } else {
+ /* find_thread_by_id locked
+ THD::LOCK_thd_data */
+ wsrep_thd_UNLOCK(thd);
+ }
+ }
- if (!thd) {
- WSREP_WARN("no THD for trx: " TRX_ID_FMT, victim_trx->id);
- DBUG_VOID_RETURN;
+ if (!victim_trx) {
+ /* Victim trx might not exist (MDL-conflict) or victim
+ was meanwhile rolled back or committed because of
+ a KILL statement or a disconnect. */
+ goto ret;
}
- /* Here we need to lock THD::LOCK_thd_data to protect from
- concurrent usage or disconnect or delete. */
- DEBUG_SYNC(bf_thd, "wsrep_before_BF_victim_lock");
- wsrep_thd_LOCK(thd);
- DEBUG_SYNC(bf_thd, "wsrep_after_BF_victim_lock");
-
- WSREP_DEBUG("Aborter %s trx_id: " TRX_ID_FMT " thread: %ld "
- "seqno: %lld query_state: %s conflict_state: %s query: %s",
- wsrep_thd_is_BF(bf_thd, false) ? "BF" : "normal",
- bf_trx ? bf_trx->id : TRX_ID_MAX,
- thd_get_thread_id(bf_thd),
- bf_seqno,
- wsrep_thd_query_state_str(bf_thd),
- wsrep_thd_conflict_state_str(bf_thd),
- wsrep_thd_query(bf_thd));
-
- WSREP_DEBUG("Victim %s trx_id: " TRX_ID_FMT " thread: %ld "
- "seqno: %lld query_state: %s conflict_state: %s query: %s",
- wsrep_thd_is_BF(thd, false) ? "BF" : "normal",
- victim_trx->id,
+ WSREP_DEBUG("BF kill (" ULINTPF ", seqno: " INT64PF
+ "), victim: (%lu) trx: " TRX_ID_FMT,
+ arg->signal, arg->bf_seqno,
thd_get_thread_id(thd),
- wsrep_thd_trx_seqno(thd),
- wsrep_thd_query_state_str(thd),
- wsrep_thd_conflict_state_str(thd),
- wsrep_thd_query(thd));
+ victim_trx->id);
- WSREP_LOG_CONFLICT(bf_thd, thd, TRUE);
+ WSREP_DEBUG("Aborting query: %s conf %d trx: %" PRId64,
+ (wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void",
+ wsrep_thd_conflict_state(thd, FALSE),
+ wsrep_thd_ws_handle(thd)->trx_id);
if (wsrep_thd_query_state(thd) == QUERY_EXITING) {
WSREP_DEBUG("kill trx EXITING for " TRX_ID_FMT,
victim_trx->id);
- wsrep_thd_UNLOCK(thd);
- DBUG_VOID_RETURN;
+ goto ret_unlock;
}
if (wsrep_thd_exec_mode(thd) != LOCAL_STATE) {
- WSREP_DEBUG("withdraw for BF trx: " TRX_ID_FMT
- ", state: %s exec %s",
+ WSREP_DEBUG("withdraw for BF trx: " TRX_ID_FMT ", state: %d",
victim_trx->id,
- wsrep_thd_conflict_state_str(thd),
- wsrep_thd_exec_mode_str(thd));
+ wsrep_thd_get_conflict_state(thd));
}
switch (wsrep_thd_get_conflict_state(thd)) {
case NO_CONFLICT:
- /* This will cause any call to innobase_kill_query()
- for this thd to bail out. */
wsrep_thd_set_conflict_state(thd, MUST_ABORT);
break;
case MUST_ABORT:
WSREP_DEBUG("victim " TRX_ID_FMT " in MUST ABORT state",
victim_trx->id);
- wsrep_thd_awake(thd, signal);
- wsrep_thd_UNLOCK(thd);
- DBUG_VOID_RETURN;
- break;
+ goto ret_awake;
case ABORTED:
case ABORTING: // fall through
default:
- WSREP_DEBUG("victim " TRX_ID_FMT " in state %s",
- victim_trx->id,
- wsrep_thd_conflict_state_str(thd));
- wsrep_thd_UNLOCK(thd);
- DBUG_VOID_RETURN;
- break;
+ WSREP_DEBUG("victim " TRX_ID_FMT " in state %d",
+ victim_trx->id, wsrep_thd_get_conflict_state(thd));
+ goto ret_unlock;
}
switch (wsrep_thd_query_state(thd)) {
@@ -19617,12 +19610,12 @@ wsrep_innobase_kill_one_trx(
victim_trx->id);
if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- wsrep_abort_slave_trx(bf_seqno,
+ wsrep_abort_slave_trx(arg->bf_seqno,
wsrep_thd_trx_seqno(thd));
} else {
wsrep_t *wsrep= get_wsrep();
rcode = wsrep->abort_pre_commit(
- wsrep, bf_seqno,
+ wsrep, arg->bf_seqno,
(wsrep_trx_id_t)wsrep_thd_ws_handle(thd)->trx_id
);
@@ -19631,10 +19624,7 @@ wsrep_innobase_kill_one_trx(
WSREP_DEBUG("cancel commit warning: "
TRX_ID_FMT,
victim_trx->id);
- wsrep_thd_awake(thd, signal);
- wsrep_thd_UNLOCK(thd);
- DBUG_VOID_RETURN;
- break;
+ goto ret_awake;
case WSREP_OK:
break;
default:
@@ -19647,12 +19637,9 @@ wsrep_innobase_kill_one_trx(
* kill the lock holder first.
*/
abort();
- break;
}
}
- wsrep_thd_awake(thd, signal);
- wsrep_thd_UNLOCK(thd);
- break;
+ goto ret_awake;
case QUERY_EXEC:
/* it is possible that victim trx is itself waiting for some
* other lock. We need to cancel this waiting
@@ -19673,65 +19660,118 @@ wsrep_innobase_kill_one_trx(
lock_cancel_waiting_and_release(wait_lock);
}
- wsrep_thd_awake(thd, signal);
- wsrep_thd_UNLOCK(thd);
} else {
/* abort currently executing query */
+ DBUG_PRINT("wsrep",("sending KILL_QUERY to: %lu",
+ thd_get_thread_id(thd)));
WSREP_DEBUG("kill query for: %ld",
thd_get_thread_id(thd));
- wsrep_thd_awake(thd, signal);
- wsrep_thd_UNLOCK(thd);
/* for BF thd, we need to prevent him from committing */
if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
- wsrep_abort_slave_trx(bf_seqno,
- wsrep_thd_trx_seqno(thd));
+ wsrep_abort_slave_trx(arg->bf_seqno,
+ wsrep_thd_trx_seqno(thd));
}
}
- break;
+ goto ret_awake;
case QUERY_IDLE:
{
WSREP_DEBUG("kill IDLE for " TRX_ID_FMT, victim_trx->id);
if (wsrep_thd_exec_mode(thd) == REPL_RECV) {
WSREP_DEBUG("kill BF IDLE, seqno: %lld",
- wsrep_thd_trx_seqno(thd));
- wsrep_thd_UNLOCK(thd);
- wsrep_abort_slave_trx(bf_seqno,
+ (long long)wsrep_thd_trx_seqno(thd));
+ wsrep_abort_slave_trx(arg->bf_seqno,
wsrep_thd_trx_seqno(thd));
- DBUG_VOID_RETURN;
+ goto ret_unlock;
}
- /* This will lock thd from proceeding after net_read()
- and innobase_kill_query to bail out for this thd. */
+ /* This will lock thd from proceeding after net_read() */
wsrep_thd_set_conflict_state(thd, ABORTING);
wsrep_lock_rollback();
if (wsrep_aborting_thd_contains(thd)) {
WSREP_WARN("duplicate thd aborter %lu",
- thd_get_thread_id(thd));
+ (ulong) thd_get_thread_id(thd));
} else {
wsrep_aborting_thd_enqueue(thd);
+ DBUG_PRINT("wsrep",("enqueuing trx abort for %lu",
+ thd_get_thread_id(thd)));
WSREP_DEBUG("enqueuing trx abort for (%lu)",
- thd_get_thread_id(thd));
+ thd_get_thread_id(thd));
}
+ DBUG_PRINT("wsrep",("signalling wsrep rollbacker"));
WSREP_DEBUG("signaling aborter");
wsrep_unlock_rollback();
- wsrep_thd_UNLOCK(thd);
-
- break;
+ goto ret_unlock;
}
default:
- ut_error;
+ WSREP_WARN("bad wsrep query state: %d",
+ wsrep_thd_query_state(thd));
+ goto ret_unlock;
}
+ret_awake:
+ awake= true;
+
+ret_unlock:
+ trx_mutex_exit(victim_trx);
+ lock_mutex_exit();
+ if (awake)
+ wsrep_thd_awake(thd, arg->signal);
+ wsrep_thd_UNLOCK(thd);
+
+ret:
+ free(arg);
+ DBUG_VOID_RETURN;
+
+}
+
+/*******************************************************************//**
+This function is used to kill one transaction in BF. */
+UNIV_INTERN
+void
+wsrep_innobase_kill_one_trx(
+/*========================*/
+ MYSQL_THD const bf_thd,
+ const trx_t * const bf_trx,
+ trx_t *victim_trx,
+ ibool signal)
+{
+ ut_ad(bf_thd);
+ ut_ad(victim_trx);
+ ut_ad(lock_mutex_own());
+ ut_ad(trx_mutex_own(victim_trx));
+
+ bg_wsrep_kill_trx_arg *arg = (bg_wsrep_kill_trx_arg*)malloc(sizeof(*arg));
+ arg->thd_id = thd_get_thread_id(victim_trx->mysql_thd);
+ arg->trx_id = victim_trx->id;
+ arg->bf_seqno = wsrep_thd_trx_seqno((THD*)bf_thd);
+ arg->signal = signal;
+
+ DBUG_ENTER("wsrep_innobase_kill_one_trx");
+
+ WSREP_LOG_CONFLICT(bf_thd, victim_trx->mysql_thd, TRUE);
+
+ DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
+ {
+ const char act[]=
+ "now "
+ "wait_for signal.wsrep_after_BF_victim_lock";
+ DBUG_ASSERT(!debug_sync_set_action(bf_thd,
+ STRING_WITH_LEN(act)));
+ };);
+
+
+ mysql_manager_submit(bg_wsrep_kill_trx, arg);
DBUG_VOID_RETURN;
}
static
void
wsrep_abort_transaction(
+/*====================*/
handlerton* hton,
THD *bf_thd,
THD *victim_thd,
@@ -19739,66 +19779,28 @@ wsrep_abort_transaction(
{
DBUG_ENTER("wsrep_abort_transaction");
- ut_ad(bf_thd);
- ut_ad(victim_thd);
- trx_t* victim_trx= thd_to_trx(victim_thd);
- trx_t* bf_trx= thd_to_trx(bf_thd);
-
- /* Here we should hold THD::LOCK_thd_data to protect
- victim from concurrent usage or disconnect or delete. */
- WSREP_DEBUG("wsrep_abort_transaction: BF:"
- " thread %ld query_state %s conflict_state %s"
- " exec %s query %s trx " TRX_ID_FMT,
- thd_get_thread_id(bf_thd),
- wsrep_thd_query_state_str(bf_thd),
- wsrep_thd_conflict_state_str(bf_thd),
- wsrep_thd_exec_mode_str(bf_thd),
- wsrep_thd_query(bf_thd),
- bf_trx ? bf_trx->id : 0);
-
- WSREP_DEBUG("wsrep_abort_transaction: victim:"
- " thread %ld query_state %s conflict_state %s"
- " exec %s query %s trx " TRX_ID_FMT,
- thd_get_thread_id(victim_thd),
- wsrep_thd_query_state_str(victim_thd),
- wsrep_thd_conflict_state_str(victim_thd),
- wsrep_thd_exec_mode_str(victim_thd),
- wsrep_thd_query(victim_thd),
- victim_trx ? victim_trx->id : 0);
+ trx_t* victim_trx = thd_to_trx(victim_thd);
+ trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
+
+ WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %d",
+ wsrep_thd_query(bf_thd),
+ wsrep_thd_query(victim_thd),
+ wsrep_thd_conflict_state(victim_thd, FALSE));
if (victim_trx) {
- WSREP_DEBUG("wsrep_abort_transaction: Victim thread %ld "
- "transaction " TRX_ID_FMT " trx_state %d",
- thd_get_thread_id(victim_thd),
- victim_trx->id,
- victim_trx->state);
- /* This is necessary as correct mutexing order is
- lock_sys -> trx -> THD::LOCK_thd_data and below
- function assumes we have lock_sys and trx locked
- and takes THD::LOCK_thd_data for THD state check. */
- wsrep_thd_UNLOCK(victim_thd);
- DEBUG_SYNC(bf_thd, "wsrep_abort_victim_unlocked");
- DBUG_EXECUTE_IF("wsrep_abort_replicated_sleep",
- WSREP_DEBUG("wsrep_abort_transaction: sleeping "
- "for thread %ld ",
- thd_get_thread_id(victim_thd));
- my_sleep(100000););
lock_mutex_enter();
trx_mutex_enter(victim_trx);
wsrep_innobase_kill_one_trx(bf_thd, bf_trx, victim_trx, signal);
lock_mutex_exit();
trx_mutex_exit(victim_trx);
wsrep_srv_conc_cancel_wait(victim_trx);
- wsrep_thd_LOCK(victim_thd);
DBUG_VOID_RETURN;
} else {
- WSREP_DEBUG("wsrep_abort_transaction: Victim thread %ld "
- "no transaction",
- thd_get_thread_id(victim_thd));
- /* This will cause any call to innobase_kill_query()
- for this thd to bail out. */
+ WSREP_DEBUG("victim does not have transaction");
+ wsrep_thd_LOCK(victim_thd);
wsrep_thd_set_conflict_state(victim_thd, MUST_ABORT);
wsrep_thd_awake(victim_thd, signal);
+ wsrep_thd_UNLOCK(victim_thd);
}
DBUG_VOID_RETURN;
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 427e57f09d2..3eab2135969 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -233,11 +233,12 @@ innobase_casedn_str(
char* a); /*!< in/out: string to put in lower case */
#ifdef WITH_WSREP
+UNIV_INTERN
void
wsrep_innobase_kill_one_trx(MYSQL_THD const thd_ptr,
const trx_t * const bf_trx,
trx_t *victim_trx,
- my_bool signal);
+ ibool signal);
int wsrep_innobase_mysql_sort(int mysql_type, uint charset_number,
unsigned char* str, unsigned int str_length,
unsigned int buf_length);