MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel replication causing replication to fail.
After-review changes. Fix InnoDB coding style issues.
This commit is contained in:
parent
ba4e56d8d7
commit
45f6262f54
@ -4218,21 +4218,23 @@ innobase_kill_query(
|
|||||||
|
|
||||||
trx = thd_to_trx(thd);
|
trx = thd_to_trx(thd);
|
||||||
|
|
||||||
if (trx)
|
if (trx) {
|
||||||
{
|
|
||||||
THD *cur = current_thd;
|
THD *cur = current_thd;
|
||||||
THD *owner = trx->current_lock_mutex_owner;
|
THD *owner = trx->current_lock_mutex_owner;
|
||||||
|
|
||||||
/* Cancel a pending lock request. */
|
/* Cancel a pending lock request. */
|
||||||
if (owner != cur)
|
if (owner != cur) {
|
||||||
lock_mutex_enter();
|
lock_mutex_enter();
|
||||||
|
}
|
||||||
trx_mutex_enter(trx);
|
trx_mutex_enter(trx);
|
||||||
if (trx->lock.wait_lock)
|
if (trx->lock.wait_lock) {
|
||||||
lock_cancel_waiting_and_release(trx->lock.wait_lock);
|
lock_cancel_waiting_and_release(trx->lock.wait_lock);
|
||||||
|
}
|
||||||
trx_mutex_exit(trx);
|
trx_mutex_exit(trx);
|
||||||
if (owner != cur)
|
if (owner != cur) {
|
||||||
lock_mutex_exit();
|
lock_mutex_exit();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -399,9 +399,9 @@ UNIV_INTERN ibool lock_print_waits = FALSE;
|
|||||||
|
|
||||||
/* Buffer to collect THDs to report waits for. */
|
/* Buffer to collect THDs to report waits for. */
|
||||||
struct thd_wait_reports {
|
struct thd_wait_reports {
|
||||||
struct thd_wait_reports *next;
|
struct thd_wait_reports *next; /*!< List link */
|
||||||
ulint used;
|
ulint used; /*!< How many elements in waitees[] */
|
||||||
trx_t *waitees[64];
|
trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3916,11 +3916,14 @@ lock_deadlock_search(
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* We do not need to report autoinc locks to the upper
|
/* We do not need to report autoinc locks to the upper
|
||||||
layer. These locks are released before commit, so they can
|
layer. These locks are released before commit, so they
|
||||||
not cause deadlocks with binlog-fixed commit order. */
|
can not cause deadlocks with binlog-fixed commit
|
||||||
if (waitee_ptr && (lock_get_type_low(lock) != LOCK_TABLE ||
|
order. */
|
||||||
|
if (waitee_ptr &&
|
||||||
|
(lock_get_type_low(lock) != LOCK_TABLE ||
|
||||||
lock_get_mode(lock) != LOCK_AUTO_INC)) {
|
lock_get_mode(lock) != LOCK_AUTO_INC)) {
|
||||||
if (waitee_ptr->used == sizeof(waitee_ptr->waitees)/
|
if (waitee_ptr->used ==
|
||||||
|
sizeof(waitee_ptr->waitees) /
|
||||||
sizeof(waitee_ptr->waitees[0])) {
|
sizeof(waitee_ptr->waitees[0])) {
|
||||||
waitee_ptr->next =
|
waitee_ptr->next =
|
||||||
(struct thd_wait_reports *)
|
(struct thd_wait_reports *)
|
||||||
@ -4028,22 +4031,28 @@ lock_deadlock_trx_rollback(
|
|||||||
trx_mutex_exit(trx);
|
trx_mutex_exit(trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static
|
||||||
mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr,
|
void
|
||||||
THD *mysql_thd,
|
lock_report_waiters_to_mysql(
|
||||||
trx_id_t victim_trx_id)
|
/*=======================*/
|
||||||
|
struct thd_wait_reports* waitee_buf_ptr, /*!< in: set of trxs */
|
||||||
|
THD* mysql_thd, /*!< in: THD */
|
||||||
|
trx_id_t victim_trx_id) /*!< in: Trx selected
|
||||||
|
as deadlock victim, if
|
||||||
|
any */
|
||||||
{
|
{
|
||||||
struct thd_wait_reports *p = waitee_buf_ptr;
|
struct thd_wait_reports* p;
|
||||||
while (p) {
|
|
||||||
struct thd_wait_reports* q;
|
struct thd_wait_reports* q;
|
||||||
ulint i = 0;
|
ulint i;
|
||||||
|
|
||||||
|
p = waitee_buf_ptr;
|
||||||
|
while (p) {
|
||||||
|
i = 0;
|
||||||
while (i < p->used) {
|
while (i < p->used) {
|
||||||
trx_t *w_trx = p->waitees[i];
|
trx_t *w_trx = p->waitees[i];
|
||||||
/* There is no need to report waits to a trx already
|
/* There is no need to report waits to a trx already
|
||||||
selected as a victim. */
|
selected as a victim. */
|
||||||
if (w_trx->id != victim_trx_id)
|
if (w_trx->id != victim_trx_id) {
|
||||||
{
|
|
||||||
/* If thd_report_wait_for() decides to kill the
|
/* If thd_report_wait_for() decides to kill the
|
||||||
transaction, then we will get a call back into
|
transaction, then we will get a call back into
|
||||||
innobase_kill_query. We mark this by setting
|
innobase_kill_query. We mark this by setting
|
||||||
@ -4056,8 +4065,9 @@ mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr,
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
q = p->next;
|
q = p->next;
|
||||||
if (p != waitee_buf_ptr)
|
if (p != waitee_buf_ptr) {
|
||||||
mem_free(p);
|
mem_free(p);
|
||||||
|
}
|
||||||
p = q;
|
p = q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4079,7 +4089,8 @@ lock_deadlock_check_and_resolve(
|
|||||||
const trx_t* trx) /*!< in: transaction */
|
const trx_t* trx) /*!< in: transaction */
|
||||||
{
|
{
|
||||||
trx_id_t victim_trx_id;
|
trx_id_t victim_trx_id;
|
||||||
struct thd_wait_reports waitee_buf, *waitee_buf_ptr;
|
struct thd_wait_reports waitee_buf;
|
||||||
|
struct thd_wait_reports*waitee_buf_ptr;
|
||||||
THD* start_mysql_thd;
|
THD* start_mysql_thd;
|
||||||
|
|
||||||
ut_ad(trx != NULL);
|
ut_ad(trx != NULL);
|
||||||
@ -4088,10 +4099,11 @@ lock_deadlock_check_and_resolve(
|
|||||||
assert_trx_in_list(trx);
|
assert_trx_in_list(trx);
|
||||||
|
|
||||||
start_mysql_thd = trx->mysql_thd;
|
start_mysql_thd = trx->mysql_thd;
|
||||||
if (start_mysql_thd && thd_need_wait_for(start_mysql_thd))
|
if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) {
|
||||||
waitee_buf_ptr = &waitee_buf;
|
waitee_buf_ptr = &waitee_buf;
|
||||||
else
|
} else {
|
||||||
waitee_buf_ptr = NULL;
|
waitee_buf_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try and resolve as many deadlocks as possible. */
|
/* Try and resolve as many deadlocks as possible. */
|
||||||
do {
|
do {
|
||||||
@ -4113,9 +4125,11 @@ lock_deadlock_check_and_resolve(
|
|||||||
victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr);
|
victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr);
|
||||||
|
|
||||||
/* Report waits to upper layer, as needed. */
|
/* Report waits to upper layer, as needed. */
|
||||||
if (waitee_buf_ptr)
|
if (waitee_buf_ptr) {
|
||||||
mysql_report_waiters(waitee_buf_ptr, start_mysql_thd,
|
lock_report_waiters_to_mysql(waitee_buf_ptr,
|
||||||
|
start_mysql_thd,
|
||||||
victim_trx_id);
|
victim_trx_id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Search too deep, we rollback the joining transaction. */
|
/* Search too deep, we rollback the joining transaction. */
|
||||||
if (ctx.too_deep) {
|
if (ctx.too_deep) {
|
||||||
|
@ -1921,10 +1921,11 @@ trx_weight_ge(
|
|||||||
/* First ask the upper server layer if it has any preference for which
|
/* First ask the upper server layer if it has any preference for which
|
||||||
to prefer as a deadlock victim. */
|
to prefer as a deadlock victim. */
|
||||||
pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd);
|
pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd);
|
||||||
if (pref < 0)
|
if (pref < 0) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (pref > 0)
|
} else if (pref > 0) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Upper server layer had no preference, we fall back to comparing the
|
/* Upper server layer had no preference, we fall back to comparing the
|
||||||
number of altered/locked rows. */
|
number of altered/locked rows. */
|
||||||
|
@ -4704,13 +4704,13 @@ innobase_kill_connection(
|
|||||||
|
|
||||||
trx = thd_to_trx(thd);
|
trx = thd_to_trx(thd);
|
||||||
|
|
||||||
if (trx)
|
if (trx) {
|
||||||
{
|
|
||||||
THD *cur = current_thd;
|
THD *cur = current_thd;
|
||||||
THD *owner = trx->current_lock_mutex_owner;
|
THD *owner = trx->current_lock_mutex_owner;
|
||||||
|
|
||||||
if (owner != cur)
|
if (owner != cur) {
|
||||||
lock_mutex_enter();
|
lock_mutex_enter();
|
||||||
|
}
|
||||||
trx_mutex_enter(trx);
|
trx_mutex_enter(trx);
|
||||||
|
|
||||||
/* Cancel a pending lock request. */
|
/* Cancel a pending lock request. */
|
||||||
@ -4718,9 +4718,10 @@ innobase_kill_connection(
|
|||||||
lock_cancel_waiting_and_release(trx->lock.wait_lock);
|
lock_cancel_waiting_and_release(trx->lock.wait_lock);
|
||||||
|
|
||||||
trx_mutex_exit(trx);
|
trx_mutex_exit(trx);
|
||||||
if (owner != cur)
|
if (owner != cur) {
|
||||||
lock_mutex_exit();
|
lock_mutex_exit();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
@ -399,9 +399,9 @@ UNIV_INTERN ibool lock_print_waits = FALSE;
|
|||||||
|
|
||||||
/* Buffer to collect THDs to report waits for. */
|
/* Buffer to collect THDs to report waits for. */
|
||||||
struct thd_wait_reports {
|
struct thd_wait_reports {
|
||||||
struct thd_wait_reports *next;
|
struct thd_wait_reports *next; /*!< List link */
|
||||||
ulint used;
|
ulint used; /*!< How many elements in waitees[] */
|
||||||
trx_t *waitees[64];
|
trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -3939,11 +3939,14 @@ lock_deadlock_search(
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* We do not need to report autoinc locks to the upper
|
/* We do not need to report autoinc locks to the upper
|
||||||
layer. These locks are released before commit, so they can
|
layer. These locks are released before commit, so they
|
||||||
not cause deadlocks with binlog-fixed commit order. */
|
can not cause deadlocks with binlog-fixed commit
|
||||||
if (waitee_ptr && (lock_get_type_low(lock) != LOCK_TABLE ||
|
order. */
|
||||||
|
if (waitee_ptr &&
|
||||||
|
(lock_get_type_low(lock) != LOCK_TABLE ||
|
||||||
lock_get_mode(lock) != LOCK_AUTO_INC)) {
|
lock_get_mode(lock) != LOCK_AUTO_INC)) {
|
||||||
if (waitee_ptr->used == sizeof(waitee_ptr->waitees)/
|
if (waitee_ptr->used ==
|
||||||
|
sizeof(waitee_ptr->waitees) /
|
||||||
sizeof(waitee_ptr->waitees[0])) {
|
sizeof(waitee_ptr->waitees[0])) {
|
||||||
waitee_ptr->next =
|
waitee_ptr->next =
|
||||||
(struct thd_wait_reports *)
|
(struct thd_wait_reports *)
|
||||||
@ -4051,22 +4054,28 @@ lock_deadlock_trx_rollback(
|
|||||||
trx_mutex_exit(trx);
|
trx_mutex_exit(trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static
|
||||||
mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr,
|
void
|
||||||
THD *mysql_thd,
|
lock_report_waiters_to_mysql(
|
||||||
trx_id_t victim_trx_id)
|
/*=======================*/
|
||||||
|
struct thd_wait_reports* waitee_buf_ptr, /*!< in: set of trxs */
|
||||||
|
THD* mysql_thd, /*!< in: THD */
|
||||||
|
trx_id_t victim_trx_id) /*!< in: Trx selected
|
||||||
|
as deadlock victim, if
|
||||||
|
any */
|
||||||
{
|
{
|
||||||
struct thd_wait_reports *p = waitee_buf_ptr;
|
struct thd_wait_reports* p;
|
||||||
while (p) {
|
|
||||||
struct thd_wait_reports* q;
|
struct thd_wait_reports* q;
|
||||||
ulint i = 0;
|
ulint i;
|
||||||
|
|
||||||
|
p = waitee_buf_ptr;
|
||||||
|
while (p) {
|
||||||
|
i = 0;
|
||||||
while (i < p->used) {
|
while (i < p->used) {
|
||||||
trx_t *w_trx = p->waitees[i];
|
trx_t *w_trx = p->waitees[i];
|
||||||
/* There is no need to report waits to a trx already
|
/* There is no need to report waits to a trx already
|
||||||
selected as a victim. */
|
selected as a victim. */
|
||||||
if (w_trx->id != victim_trx_id)
|
if (w_trx->id != victim_trx_id) {
|
||||||
{
|
|
||||||
/* If thd_report_wait_for() decides to kill the
|
/* If thd_report_wait_for() decides to kill the
|
||||||
transaction, then we will get a call back into
|
transaction, then we will get a call back into
|
||||||
innobase_kill_query. We mark this by setting
|
innobase_kill_query. We mark this by setting
|
||||||
@ -4079,8 +4088,9 @@ mysql_report_waiters(struct thd_wait_reports *waitee_buf_ptr,
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
q = p->next;
|
q = p->next;
|
||||||
if (p != waitee_buf_ptr)
|
if (p != waitee_buf_ptr) {
|
||||||
mem_free(p);
|
mem_free(p);
|
||||||
|
}
|
||||||
p = q;
|
p = q;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4102,7 +4112,8 @@ lock_deadlock_check_and_resolve(
|
|||||||
const trx_t* trx) /*!< in: transaction */
|
const trx_t* trx) /*!< in: transaction */
|
||||||
{
|
{
|
||||||
trx_id_t victim_trx_id;
|
trx_id_t victim_trx_id;
|
||||||
struct thd_wait_reports waitee_buf, *waitee_buf_ptr;
|
struct thd_wait_reports waitee_buf;
|
||||||
|
struct thd_wait_reports*waitee_buf_ptr;
|
||||||
THD* start_mysql_thd;
|
THD* start_mysql_thd;
|
||||||
|
|
||||||
ut_ad(trx != NULL);
|
ut_ad(trx != NULL);
|
||||||
@ -4111,10 +4122,11 @@ lock_deadlock_check_and_resolve(
|
|||||||
assert_trx_in_list(trx);
|
assert_trx_in_list(trx);
|
||||||
|
|
||||||
start_mysql_thd = trx->mysql_thd;
|
start_mysql_thd = trx->mysql_thd;
|
||||||
if (start_mysql_thd && thd_need_wait_for(start_mysql_thd))
|
if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) {
|
||||||
waitee_buf_ptr = &waitee_buf;
|
waitee_buf_ptr = &waitee_buf;
|
||||||
else
|
} else {
|
||||||
waitee_buf_ptr = NULL;
|
waitee_buf_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try and resolve as many deadlocks as possible. */
|
/* Try and resolve as many deadlocks as possible. */
|
||||||
do {
|
do {
|
||||||
@ -4136,9 +4148,11 @@ lock_deadlock_check_and_resolve(
|
|||||||
victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr);
|
victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr);
|
||||||
|
|
||||||
/* Report waits to upper layer, as needed. */
|
/* Report waits to upper layer, as needed. */
|
||||||
if (waitee_buf_ptr)
|
if (waitee_buf_ptr) {
|
||||||
mysql_report_waiters(waitee_buf_ptr, start_mysql_thd,
|
lock_report_waiters_to_mysql(waitee_buf_ptr,
|
||||||
|
start_mysql_thd,
|
||||||
victim_trx_id);
|
victim_trx_id);
|
||||||
|
}
|
||||||
|
|
||||||
/* Search too deep, we rollback the joining transaction. */
|
/* Search too deep, we rollback the joining transaction. */
|
||||||
if (ctx.too_deep) {
|
if (ctx.too_deep) {
|
||||||
|
@ -2142,9 +2142,8 @@ trx_assert_started(
|
|||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
/*******************************************************************//**
|
/*******************************************************************//**
|
||||||
Compares the "weight" (or size) of two transactions. Transactions that
|
Compares the "weight" (or size) of two transactions. The heavier the weight,
|
||||||
have edited non-transactional tables are considered heavier than ones
|
the more reluctant we will be to choose the transaction as a deadlock victim.
|
||||||
that have not.
|
|
||||||
@return TRUE if weight(a) >= weight(b) */
|
@return TRUE if weight(a) >= weight(b) */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
ibool
|
ibool
|
||||||
@ -2158,10 +2157,11 @@ trx_weight_ge(
|
|||||||
/* First ask the upper server layer if it has any preference for which
|
/* First ask the upper server layer if it has any preference for which
|
||||||
to prefer as a deadlock victim. */
|
to prefer as a deadlock victim. */
|
||||||
pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd);
|
pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd);
|
||||||
if (pref < 0)
|
if (pref < 0) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
else if (pref > 0)
|
} else if (pref > 0) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Upper server layer had no preference, we fall back to comparing the
|
/* Upper server layer had no preference, we fall back to comparing the
|
||||||
number of altered/locked rows. */
|
number of altered/locked rows. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user