mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 20:07:13 +02:00
Many files:
Fix hang introduced by selective deadlock resolution srv0srv.c, row0mysql.c: Fix hang introduced by selective deadlock resolution + corruption caused by lock timeout or sel deadl res in ON DELETE CASCADE innobase/include/que0que.h: Fix hang introduced by selective deadlock resolution innobase/include/trx0trx.h: Fix hang introduced by selective deadlock resolution innobase/include/ut0ut.h: Fix hang introduced by selective deadlock resolution innobase/lock/lock0lock.c: Fix hang introduced by selective deadlock resolution innobase/log/log0log.c: Fix hang introduced by selective deadlock resolution innobase/que/que0que.c: Fix hang introduced by selective deadlock resolution innobase/row/row0mysql.c: Fix hang introduced by selective deadlock resolution + corruption caused by lock timeout or sel deadl res in ON DELETE CASCADE innobase/srv/srv0srv.c: Fix hang introduced by selective deadlock resolution + corruption caused by lock timeout or sel deadl res in ON DELETE CASCADE innobase/trx/trx0sys.c: Fix hang introduced by selective deadlock resolution innobase/trx/trx0trx.c: Fix hang introduced by selective deadlock resolution
This commit is contained in:
parent
8fc4319ae3
commit
4fa5e50edb
10 changed files with 81 additions and 24 deletions
|
|
@ -117,6 +117,7 @@ que_thr_stop(
|
|||
/**************************************************************************
|
||||
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
||||
the n_active_thrs counters of the query graph and transaction. */
|
||||
|
||||
void
|
||||
que_thr_move_to_run_state_for_mysql(
|
||||
/*================================*/
|
||||
|
|
@ -125,14 +126,17 @@ que_thr_move_to_run_state_for_mysql(
|
|||
/**************************************************************************
|
||||
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
|
||||
select, when there is no error or lock wait. */
|
||||
|
||||
void
|
||||
que_thr_stop_for_mysql_no_error(
|
||||
/*============================*/
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
trx_t* trx); /* in: transaction */
|
||||
/**************************************************************************
|
||||
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
|
||||
select. */
|
||||
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
|
||||
query thread is stopped and made inactive, except in the case where
|
||||
it was put to the lock wait state in lock0lock.c, but the lock has already
|
||||
been granted or the transaction chosen as a victim in deadlock resolution. */
|
||||
|
||||
void
|
||||
que_thr_stop_for_mysql(
|
||||
|
|
|
|||
|
|
@ -429,7 +429,10 @@ struct trx_struct{
|
|||
MySQL */
|
||||
/*------------------------------*/
|
||||
ulint error_state; /* 0 if no error, otherwise error
|
||||
number */
|
||||
number; NOTE That ONLY the thread
|
||||
doing the transaction is allowed to
|
||||
set this field: this is NOT protected
|
||||
by the kernel mutex */
|
||||
void* error_info; /* if the error number indicates a
|
||||
duplicate key error, a pointer to
|
||||
the problematic index is stored here */
|
||||
|
|
@ -466,6 +469,12 @@ struct trx_struct{
|
|||
TRX_QUE_LOCK_WAIT, this points to
|
||||
the lock request, otherwise this is
|
||||
NULL */
|
||||
ibool was_chosen_as_deadlock_victim;
|
||||
/* when the transaction decides to wait
|
||||
for a lock, this it sets this to FALSE;
|
||||
if another transaction chooses this
|
||||
transaction as a victim in deadlock
|
||||
resolution, it sets this to TRUE */
|
||||
time_t wait_started; /* lock wait started at this time */
|
||||
UT_LIST_BASE_NODE_T(que_thr_t)
|
||||
wait_thrs; /* query threads belonging to this
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ Created 1/20/1994 Heikki Tuuri
|
|||
#define ut0ut_h
|
||||
|
||||
#include "univ.i"
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#ifndef MYSQL_SERVER
|
||||
#include <ctype.h>
|
||||
|
|
|
|||
|
|
@ -1727,6 +1727,7 @@ index->table_name);
|
|||
}
|
||||
|
||||
trx->que_state = TRX_QUE_LOCK_WAIT;
|
||||
trx->was_chosen_as_deadlock_victim = FALSE;
|
||||
trx->wait_started = time(NULL);
|
||||
|
||||
ut_a(que_thr_stop(thr));
|
||||
|
|
@ -3173,7 +3174,8 @@ lock_deadlock_recursive(
|
|||
err_buf += sprintf(err_buf,
|
||||
"*** WE ROLL BACK TRANSACTION (1)\n");
|
||||
|
||||
wait_lock->trx->error_state = DB_DEADLOCK;
|
||||
wait_lock->trx->was_chosen_as_deadlock_victim
|
||||
= TRUE;
|
||||
|
||||
lock_cancel_waiting_and_release(wait_lock);
|
||||
|
||||
|
|
@ -3353,6 +3355,7 @@ table->name);
|
|||
}
|
||||
|
||||
trx->que_state = TRX_QUE_LOCK_WAIT;
|
||||
trx->was_chosen_as_deadlock_victim = FALSE;
|
||||
trx->wait_started = time(NULL);
|
||||
|
||||
ut_a(que_thr_stop(thr));
|
||||
|
|
|
|||
|
|
@ -1654,8 +1654,8 @@ log_reset_first_header_and_checkpoint(
|
|||
lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE);
|
||||
|
||||
/* Write the label of ibbackup --restore */
|
||||
sprintf((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup ");
|
||||
ut_sprintf_timestamp((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
|
||||
sprintf(hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup ");
|
||||
ut_sprintf_timestamp(hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
|
||||
+ strlen("ibbackup "));
|
||||
buf = hdr_buf + LOG_CHECKPOINT_1;
|
||||
|
||||
|
|
|
|||
|
|
@ -1046,14 +1046,16 @@ que_thr_stop(
|
|||
}
|
||||
|
||||
/**************************************************************************
|
||||
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. */
|
||||
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
|
||||
query thread is stopped and made inactive, except in the case where
|
||||
it was put to the lock wait state in lock0lock.c, but the lock has already
|
||||
been granted or the transaction chosen as a victim in deadlock resolution. */
|
||||
|
||||
void
|
||||
que_thr_stop_for_mysql(
|
||||
/*===================*/
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
ibool stopped = FALSE;
|
||||
trx_t* trx;
|
||||
|
||||
trx = thr_get_trx(thr);
|
||||
|
|
@ -1067,13 +1069,10 @@ que_thr_stop_for_mysql(
|
|||
|
||||
/* Error handling built for the MySQL interface */
|
||||
thr->state = QUE_THR_COMPLETED;
|
||||
|
||||
stopped = TRUE;
|
||||
}
|
||||
|
||||
if (!stopped) {
|
||||
/* It must have been a lock wait but the
|
||||
lock was already released */
|
||||
} else {
|
||||
/* It must have been a lock wait but the lock was
|
||||
already released, or this transaction was chosen
|
||||
as a victim in selective deadlock resolution */
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
|
|
@ -1081,6 +1080,10 @@ que_thr_stop_for_mysql(
|
|||
}
|
||||
}
|
||||
|
||||
ut_ad(thr->is_active == TRUE);
|
||||
ut_ad(trx->n_active_thrs == 1);
|
||||
ut_ad(thr->graph->n_active_thrs == 1);
|
||||
|
||||
thr->is_active = FALSE;
|
||||
(thr->graph)->n_active_thrs--;
|
||||
|
||||
|
|
@ -1132,6 +1135,9 @@ que_thr_stop_for_mysql_no_error(
|
|||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
ut_ad(thr->state == QUE_THR_RUNNING);
|
||||
ut_ad(thr->is_active == TRUE);
|
||||
ut_ad(trx->n_active_thrs == 1);
|
||||
ut_ad(thr->graph->n_active_thrs == 1);
|
||||
|
||||
if (thr->magic_n != QUE_THR_MAGIC_N) {
|
||||
fprintf(stderr,
|
||||
|
|
|
|||
|
|
@ -198,8 +198,9 @@ row_mysql_handle_errors(
|
|||
/* out: TRUE if it was a lock wait and
|
||||
we should continue running the query thread */
|
||||
ulint* new_err,/* out: possible new error encountered in
|
||||
rollback, or the old error which was
|
||||
during the function entry */
|
||||
lock wait, or if no new error, the value
|
||||
of trx->error_state at the entry of this
|
||||
function */
|
||||
trx_t* trx, /* in: transaction */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
trx_savept_t* savept) /* in: savepoint or NULL */
|
||||
|
|
@ -1010,10 +1011,27 @@ run_again:
|
|||
|
||||
err = trx->error_state;
|
||||
|
||||
/* Note that the cascade node is a subnode of another InnoDB
|
||||
query graph node. We do a normal lock wait in this node, but
|
||||
all errors are handled by the parent node. */
|
||||
|
||||
if (err == DB_LOCK_WAIT) {
|
||||
/* Handle lock wait here */
|
||||
|
||||
que_thr_stop_for_mysql(thr);
|
||||
|
||||
row_mysql_handle_errors(&err, trx, thr, NULL);
|
||||
srv_suspend_mysql_thread(thr);
|
||||
|
||||
/* Note that a lock wait may also end in a lock wait timeout,
|
||||
or this transaction is picked as a victim in selective
|
||||
deadlock resolution */
|
||||
|
||||
if (trx->error_state != DB_SUCCESS) {
|
||||
|
||||
return(trx->error_state);
|
||||
}
|
||||
|
||||
/* Retry operation after a normal lock wait */
|
||||
|
||||
goto run_again;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2082,13 +2082,24 @@ srv_suspend_mysql_thread(
|
|||
|
||||
if (thr->state == QUE_THR_RUNNING) {
|
||||
|
||||
/* The lock has already been released: no need to suspend */
|
||||
ut_ad(thr->is_active == TRUE);
|
||||
|
||||
/* The lock has already been released or this transaction
|
||||
was chosen as a deadlock victim: no need to suspend */
|
||||
|
||||
if (trx->was_chosen_as_deadlock_victim) {
|
||||
|
||||
trx->error_state = DB_DEADLOCK;
|
||||
trx->was_chosen_as_deadlock_victim = FALSE;
|
||||
}
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ut_ad(thr->is_active == FALSE);
|
||||
|
||||
slot = srv_table_reserve_slot_for_mysql();
|
||||
|
||||
event = slot->event;
|
||||
|
|
@ -2142,6 +2153,12 @@ srv_suspend_mysql_thread(
|
|||
|
||||
wait_time = ut_difftime(ut_time(), slot->suspend_time);
|
||||
|
||||
if (trx->was_chosen_as_deadlock_victim) {
|
||||
|
||||
trx->error_state = DB_DEADLOCK;
|
||||
trx->was_chosen_as_deadlock_victim = FALSE;
|
||||
}
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
if (srv_lock_wait_timeout < 100000000 &&
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ trx_sys_update_mysql_binlog_offset(
|
|||
|
||||
mlog_write_string(sys_header + field
|
||||
+ TRX_SYS_MYSQL_LOG_NAME,
|
||||
(byte*) file_name, 1 + ut_strlen(file_name), mtr);
|
||||
file_name, 1 + ut_strlen(file_name), mtr);
|
||||
}
|
||||
|
||||
if (mach_read_from_4(sys_header + field
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ trx_create(
|
|||
trx->graph = NULL;
|
||||
|
||||
trx->wait_lock = NULL;
|
||||
trx->was_chosen_as_deadlock_victim = FALSE;
|
||||
UT_LIST_INIT(trx->wait_thrs);
|
||||
|
||||
trx->lock_heap = mem_heap_create_in_buffer(256);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue