diff options
author | heikki@hundin.mysql.fi <> | 2002-11-07 14:47:25 +0200 |
---|---|---|
committer | heikki@hundin.mysql.fi <> | 2002-11-07 14:47:25 +0200 |
commit | b31f909d7b756813993cc0f8f0d4d707aa2c2d20 (patch) | |
tree | 55c72cdc1d8c91f0b56057c2e2c01f7ce3c93883 /innobase | |
parent | aa4e1658080ef50072f796773d2723e723d01ff0 (diff) | |
download | mariadb-git-b31f909d7b756813993cc0f8f0d4d707aa2c2d20.tar.gz |
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
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/include/que0que.h | 8 | ||||
-rw-r--r-- | innobase/include/trx0trx.h | 11 | ||||
-rw-r--r-- | innobase/include/ut0ut.h | 1 | ||||
-rw-r--r-- | innobase/lock/lock0lock.c | 5 | ||||
-rw-r--r-- | innobase/log/log0log.c | 4 | ||||
-rw-r--r-- | innobase/que/que0que.c | 24 | ||||
-rw-r--r-- | innobase/row/row0mysql.c | 30 | ||||
-rw-r--r-- | innobase/srv/srv0srv.c | 19 | ||||
-rw-r--r-- | innobase/trx/trx0sys.c | 2 | ||||
-rw-r--r-- | innobase/trx/trx0trx.c | 1 |
10 files changed, 81 insertions, 24 deletions
diff --git a/innobase/include/que0que.h b/innobase/include/que0que.h index cdaeeae1fde..a3ed18e2b14 100644 --- a/innobase/include/que0que.h +++ b/innobase/include/que0que.h @@ -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( diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 1468ef449e7..34f820f03e7 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -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 diff --git a/innobase/include/ut0ut.h b/innobase/include/ut0ut.h index d4697c47266..8ec23b23dcd 100644 --- a/innobase/include/ut0ut.h +++ b/innobase/include/ut0ut.h @@ -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> diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 92ee5ee6cbe..7b08d6b89b8 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -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)); diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index f9b785ccbd5..c798a08e2de 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -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; diff --git a/innobase/que/que0que.c b/innobase/que/que0que.c index 7fa444f6741..a96c8840a03 100644 --- a/innobase/que/que0que.c +++ b/innobase/que/que0que.c @@ -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, diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index b109b785a45..f228a75ad3a 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -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 */ @@ -998,8 +999,8 @@ row_update_cascade_for_mysql( or set null operation */ dict_table_t* table) /* in: table where we do the operation */ { - ulint err; - trx_t* trx; + ulint err; + trx_t* trx; trx = thr_get_trx(thr); run_again: @@ -1010,11 +1011,28 @@ 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) { - que_thr_stop_for_mysql(thr); + /* Handle lock wait here */ - row_mysql_handle_errors(&err, trx, thr, NULL); + que_thr_stop_for_mysql(thr); + 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; } diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 51d7878fd29..f9eba721cbc 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -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 && diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 19cf52c8676..33c962772e8 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -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 diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 9f711890f60..f0077f941de 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -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); |