MDEV-18464: Port kill_one_trx fixes from 10.4 to 10.1

Pushed the decision for innodb transaction and system
locking down to lock0lock.cc level. With this,
we can avoid releasing these mutexes for executions
where these mutexes were acquired upfront.

This patch will also fix BF aborting of native threads, e.g.
threads which have declared wsrep_on=OFF. Earlier, we have
used, for innodb trx locks, was_chosen_as_deadlock_victim
flag, for marking inodb transactions, which are victims for
wsrep BF abort. With native threads (wsrep_on==OFF), re-using
was_chosen_as_deadlock_victim flag may lead to inteference
with real deadlock, and to deal with this, the patch has added new
flag for marking wsrep BF aborts only: victim=true

Similar way if replication decides to abort one of the threads
we mark victim by: victim=true

innobase_kill_query
	Remove lock sys and trx mutex handling.

wsrep_innobase_kill_one_trx
	Mark victim trx with victim=true

trx0trx.h
	Remove trx_abort_t type and abort type variable from
	trx struct. Add victim variable to trx.

wsrep_kill_victim
	Remove abort_type

lock_report_waiters_to_mysql
	Take also trx mutex and mark trx as a victim for
	replication abort.

lock_trx_handle_wait_low
	New low level function to check whether the transaction
	has already been rolled back because it was selected as
	a deadlock victim, or if it has to wait then cancel
	the wait lock.

lock_trx_handle_wait
	If transaction is not marked as victim take lock sys
	and trx mutex before calling lock_trx_handle_wait_low
	and release them after that.

row_search_for_mysql
	Remove lock sys and trx mutex taking and releasing.

trx_rollback_to_savepoint_for_mysql_low
trx_commit_in_memory
	Clean up victim variable.
This commit is contained in:
Jan Lindström 2019-03-27 09:28:49 +02:00
parent deff3f7572
commit 21b2fada7a
12 changed files with 99 additions and 170 deletions

View File

@ -4929,8 +4929,6 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
/* 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;
}
@ -4939,34 +4937,8 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
if (trx_t* trx = thd_to_trx(thd)) {
ut_ad(trx->mysql_thd == thd);
switch (trx->abort_type) {
#ifdef WITH_WSREP
case TRX_WSREP_ABORT:
break;
#endif
case TRX_SERVER_ABORT:
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
lock_mutex_enter();
}
/* fall through */
case TRX_REPLICATION_ABORT:
trx_mutex_enter(trx);
}
/* Cancel a pending lock request if there are any */
lock_trx_handle_wait(trx);
switch (trx->abort_type) {
#ifdef WITH_WSREP
case TRX_WSREP_ABORT:
break;
#endif
case TRX_SERVER_ABORT:
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
lock_mutex_exit();
}
/* fall through */
case TRX_REPLICATION_ABORT:
trx_mutex_exit(trx);
}
}
DBUG_VOID_RETURN;
@ -18683,6 +18655,12 @@ wsrep_innobase_kill_one_trx(
wsrep_thd_ws_handle(thd)->trx_id);
wsrep_thd_LOCK(thd);
/* We mark this as victim transaction, which is already marked
as BF victim. Both trx mutex and lock_sys mutex is held until
this victim has aborted. */
victim_trx->victim = true;
DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
{
const char act[]=
@ -18866,7 +18844,7 @@ wsrep_abort_transaction(
my_bool signal)
{
DBUG_ENTER("wsrep_innobase_abort_thd");
trx_t* victim_trx = thd_to_trx(victim_thd);
trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL;
@ -18878,12 +18856,10 @@ wsrep_abort_transaction(
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
victim_trx->abort_type = TRX_WSREP_ABORT;
int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
victim_trx, signal);
trx_mutex_exit(victim_trx);
lock_mutex_exit();
victim_trx->abort_type = TRX_SERVER_ABORT;
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2018, MariaDB Corporation.
Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -623,7 +623,6 @@ struct trx_lock_t {
lock_sys->mutex. Otherwise, this may
only be modified by the thread that is
serving the running transaction. */
mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */
@ -695,14 +694,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
enum trx_abort_t {
TRX_SERVER_ABORT = 0,
#ifdef WITH_WSREP
TRX_WSREP_ABORT,
#endif
TRX_REPLICATION_ABORT
};
struct trx_t{
ulint magic_n;
@ -880,8 +871,12 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
trx_abort_t abort_type; /*!< Transaction abort type*/
bool victim; /*!< This transaction is
selected as victim for abort
either by replication or
high priority wsrep thread. This
field is protected by trx and
lock sys mutex. */
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2018, MariaDB Corporation.
Copyright (c) 2014, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1793,10 +1793,8 @@ wsrep_kill_victim(
}
}
lock->trx->abort_type = TRX_WSREP_ABORT;
wsrep_innobase_kill_one_trx(trx->mysql_thd,
(const trx_t*) trx, lock->trx, TRUE);
lock->trx->abort_type = TRX_SERVER_ABORT;
}
}
}
@ -4782,12 +4780,11 @@ lock_report_waiters_to_mysql(
if (w_trx->id != victim_trx_id) {
/* If thd_report_wait_for() decides to kill the
transaction, then we will get a call back into
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
w_trx->abort_type = TRX_REPLICATION_ABORT;
innobase_kill_query.*/
trx_mutex_enter(w_trx);
w_trx->victim = true;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
w_trx->abort_type = TRX_SERVER_ABORT;
trx_mutex_exit(w_trx);
}
++i;
}
@ -7967,16 +7964,7 @@ lock_trx_release_locks(
lock_mutex_exit();
}
/*********************************************************************//**
Check whether the transaction has already been rolled back because it
was selected as a deadlock victim, or if it has to wait then cancel
the wait lock.
@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
UNIV_INTERN
dberr_t
lock_trx_handle_wait(
/*=================*/
trx_t* trx) /*!< in/out: trx lock state */
inline dberr_t lock_trx_handle_wait_low(trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
@ -7993,6 +7981,32 @@ lock_trx_handle_wait(
return DB_LOCK_WAIT;
}
/*********************************************************************//**
Check whether the transaction has already been rolled back because it
was selected as a deadlock victim, or if it has to wait then cancel
the wait lock.
@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
UNIV_INTERN
dberr_t
lock_trx_handle_wait(
/*=================*/
trx_t* trx) /*!< in/out: trx lock state */
{
if (!trx->victim) {
lock_mutex_enter();
trx_mutex_enter(trx);
}
dberr_t err = lock_trx_handle_wait_low(trx);
if (!trx->victim) {
lock_mutex_exit();
trx_mutex_exit(trx);
}
return err;
}
/*********************************************************************//**
Get the number of locks on a table.
@return number of locks */

View File

@ -4746,11 +4746,7 @@ no_gap_lock:
a deadlock and the transaction had to wait then
release the lock it is waiting on. */
lock_mutex_enter();
trx_mutex_enter(trx);
err = lock_trx_handle_wait(trx);
lock_mutex_exit();
trx_mutex_exit(trx);
switch (err) {
case DB_SUCCESS:

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2018, MariaDB Corporation.
Copyright (c) 2016, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -370,6 +370,7 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
trx->victim = false;
return(err);
}

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2018, MariaDB Corporation.
Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1339,11 +1339,7 @@ trx_commit_in_memory(
ut_ad(!trx->in_ro_trx_list);
ut_ad(!trx->in_rw_trx_list);
#ifdef WITH_WSREP
if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
trx->lock.was_chosen_as_deadlock_victim = FALSE;
}
#endif
trx->victim = false;
trx->dict_operation = TRX_DICT_OP_NONE;
trx->error_state = DB_SUCCESS;

View File

@ -5534,8 +5534,6 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
/* 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;
}
@ -5543,34 +5541,8 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
if (trx_t* trx = thd_to_trx(thd)) {
ut_ad(trx->mysql_thd == thd);
switch (trx->abort_type) {
#ifdef WITH_WSREP
case TRX_WSREP_ABORT:
break;
#endif
case TRX_SERVER_ABORT:
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
lock_mutex_enter();
}
/* fall through */
case TRX_REPLICATION_ABORT:
trx_mutex_enter(trx);
}
/* Cancel a pending lock request if there are any */
lock_trx_handle_wait(trx);
switch (trx->abort_type) {
#ifdef WITH_WSREP
case TRX_WSREP_ABORT:
break;
#endif
case TRX_SERVER_ABORT:
if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
lock_mutex_exit();
}
/* fall through */
case TRX_REPLICATION_ABORT:
trx_mutex_exit(trx);
}
}
DBUG_VOID_RETURN;
@ -19723,6 +19695,12 @@ wsrep_innobase_kill_one_trx(
(thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void");
wsrep_thd_LOCK(thd);
/* We mark this as victim transaction, which is already marked
as BF victim. Both trx mutex and lock_sys mutex is held until
this victim has aborted. */
victim_trx->victim = true;
DBUG_EXECUTE_IF("sync.wsrep_after_BF_victim_lock",
{
const char act[]=
@ -19911,12 +19889,10 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
if (victim_trx) {
lock_mutex_enter();
trx_mutex_enter(victim_trx);
victim_trx->abort_type = TRX_WSREP_ABORT;
int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx,
victim_trx, signal);
trx_mutex_exit(victim_trx);
lock_mutex_exit();
victim_trx->abort_type = TRX_SERVER_ABORT;
wsrep_srv_conc_cancel_wait(victim_trx);
DBUG_RETURN(rcode);
} else {

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2018, MariaDB Corporation.
Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -672,7 +672,6 @@ struct trx_lock_t {
lock_sys->mutex. Otherwise, this may
only be modified by the thread that is
serving the running transaction. */
mem_heap_t* lock_heap; /*!< memory heap for trx_locks;
protected by lock_sys->mutex */
@ -744,14 +743,6 @@ lock_rec_convert_impl_to_expl()) will access transactions associated
to other connections. The locks of transactions are protected by
lock_sys->mutex and sometimes by trx->mutex. */
enum trx_abort_t {
TRX_SERVER_ABORT = 0,
#ifdef WITH_WSREP
TRX_WSREP_ABORT,
#endif
TRX_REPLICATION_ABORT
};
struct trx_t{
ulint magic_n;
@ -930,8 +921,12 @@ struct trx_t{
/*------------------------------*/
THD* mysql_thd; /*!< MySQL thread handle corresponding
to this trx, or NULL */
trx_abort_t abort_type; /*!< Transaction abort type */
bool victim; /*!< This transaction is
selected as victim for abort
either by replication or
high priority wsrep thread. This
field is protected by trx and
lock sys mutex. */
const char* mysql_log_file_name;
/*!< if MySQL binlog is used, this field
contains a pointer to the latest file

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2018, MariaDB Corporation.
Copyright (c) 2014, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1804,10 +1804,8 @@ wsrep_kill_victim(
}
}
lock->trx->abort_type = TRX_WSREP_ABORT;
wsrep_innobase_kill_one_trx(trx->mysql_thd,
(const trx_t*) trx, lock->trx, TRUE);
lock->trx->abort_type = TRX_SERVER_ABORT;
}
}
}
@ -4821,12 +4819,11 @@ lock_report_waiters_to_mysql(
if (w_trx->id != victim_trx_id) {
/* If thd_report_wait_for() decides to kill the
transaction, then we will get a call back into
innobase_kill_query. We mark this by setting
current_lock_mutex_owner, so we can avoid trying
to recursively take lock_sys->mutex. */
w_trx->abort_type = TRX_REPLICATION_ABORT;
innobase_kill_query.*/
trx_mutex_enter(w_trx);
w_trx->victim = true;
thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
w_trx->abort_type = TRX_SERVER_ABORT;
trx_mutex_exit(w_trx);
}
++i;
}
@ -8077,16 +8074,7 @@ lock_trx_release_locks(
lock_mutex_exit();
}
/*********************************************************************//**
Check whether the transaction has already been rolled back because it
was selected as a deadlock victim, or if it has to wait then cancel
the wait lock.
@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
UNIV_INTERN
dberr_t
lock_trx_handle_wait(
/*=================*/
trx_t* trx) /*!< in/out: trx lock state */
inline dberr_t lock_trx_handle_wait_low(trx_t* trx)
{
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
@ -8103,6 +8091,32 @@ lock_trx_handle_wait(
return DB_LOCK_WAIT;
}
/*********************************************************************//**
Check whether the transaction has already been rolled back because it
was selected as a deadlock victim, or if it has to wait then cancel
the wait lock.
@return DB_DEADLOCK, DB_LOCK_WAIT or DB_SUCCESS */
UNIV_INTERN
dberr_t
lock_trx_handle_wait(
/*=================*/
trx_t* trx) /*!< in/out: trx lock state */
{
if (!trx->victim) {
lock_mutex_enter();
trx_mutex_enter(trx);
}
dberr_t err = lock_trx_handle_wait_low(trx);
if (!trx->victim) {
lock_mutex_exit();
trx_mutex_exit(trx);
}
return err;
}
/*********************************************************************//**
Get the number of locks on a table.
@return number of locks */

View File

@ -4755,11 +4755,7 @@ no_gap_lock:
a deadlock and the transaction had to wait then
release the lock it is waiting on. */
lock_mutex_enter();
trx_mutex_enter(trx);
err = lock_trx_handle_wait(trx);
lock_mutex_exit();
trx_mutex_exit(trx);
switch (err) {
case DB_SUCCESS:

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2018, MariaDB Corporation.
Copyright (c) 2016, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -33,8 +33,6 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0roll.ic"
#endif
#include <mysql/service_wsrep.h>
#include "fsp0fsp.h"
#include "mach0data.h"
#include "trx0rseg.h"
@ -51,9 +49,6 @@ Created 3/26/1996 Heikki Tuuri
#include "pars0pars.h"
#include "srv0mon.h"
#include "trx0sys.h"
#ifdef WITH_WSREP
#include "ha_prototypes.h"
#endif /* WITH_WSREP */
/** This many pages must be undone before a truncate is tried within
rollback */
@ -375,13 +370,7 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
#ifdef WITH_WSREP
if (wsrep_on(trx->mysql_thd) &&
trx->lock.was_chosen_as_deadlock_victim) {
trx->lock.was_chosen_as_deadlock_victim = FALSE;
}
#endif
trx->victim = false;
return(err);
}
@ -1079,12 +1068,6 @@ trx_roll_try_truncate(
if (trx->update_undo) {
trx_undo_truncate_end(trx, trx->update_undo, limit);
}
#ifdef WITH_WSREP_OUT
if (wsrep_on(trx->mysql_thd)) {
trx->lock.was_chosen_as_deadlock_victim = FALSE;
}
#endif /* WITH_WSREP */
}
/***********************************************************************//**

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2018, MariaDB Corporation.
Copyright (c) 2015, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1563,11 +1563,7 @@ trx_commit_in_memory(
ut_ad(!trx->in_ro_trx_list);
ut_ad(!trx->in_rw_trx_list);
#ifdef WITH_WSREP
if (trx->mysql_thd && wsrep_on(trx->mysql_thd)) {
trx->lock.was_chosen_as_deadlock_victim = FALSE;
}
#endif
trx->victim = false;
trx->dict_operation = TRX_DICT_OP_NONE;
trx->error_state = DB_SUCCESS;
@ -2668,10 +2664,6 @@ trx_start_if_not_started_low(
{
switch (trx->state) {
case TRX_STATE_NOT_STARTED:
#ifdef WITH_WSREP
ut_d(trx->start_file = __FILE__);
ut_d(trx->start_line = __LINE__);
#endif /* WITH_WSREP */
trx_start_low(trx);
/* fall through */
case TRX_STATE_ACTIVE:
@ -2705,11 +2697,6 @@ trx_start_for_ddl_low(
trx->will_lock = 1;
trx->ddl = true;
#ifdef WITH_WSREP
ut_d(trx->start_file = __FILE__);
ut_d(trx->start_line = __LINE__);
#endif /* WITH_WSREP */
trx_start_low(trx);
return;