diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2015-12-21 16:36:26 +0200 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2015-12-21 16:36:26 +0200 |
commit | 080da551ea171f8a43633ab27b56875938643dd0 (patch) | |
tree | 7f9a26b8bb0bc05407527e9bc68a1ab29ef48bf3 | |
parent | 8dfd157bb2c560f0ee7496216cc3f0895788bdf0 (diff) | |
download | mariadb-git-080da551ea171f8a43633ab27b56875938643dd0.tar.gz |
MDEV-8869: Potential lock_sys->mutex deadlockbb-10.0-galera-jan
In wsrep BF we have already took lock_sys and trx
mutex either on wsrep_abort_transaction() or
before wsrep_kill_victim(). In replication we
could own lock_sys mutex taken in
lock_deadlock_check_and_resolve().
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 37 | ||||
-rw-r--r-- | storage/innobase/include/lock0lock.h | 8 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 10 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 39 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.cc | 39 | ||||
-rw-r--r-- | storage/xtradb/include/lock0lock.h | 9 | ||||
-rw-r--r-- | storage/xtradb/include/trx0trx.h | 10 | ||||
-rw-r--r-- | storage/xtradb/lock/lock0lock.cc | 39 |
8 files changed, 164 insertions, 27 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0466635d058..8e9fb083f56 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4358,29 +4358,46 @@ innobase_kill_query( #endif /* WITH_WSREP */ trx = thd_to_trx(thd); - if (trx) { + if (trx && trx->lock.wait_lock) { /* In wsrep BF we have already took lock_sys and trx mutex either on wsrep_abort_transaction() or - before wsrep_kill_victim() */ - - if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + before wsrep_kill_victim(). In replication we + could own lock_sys mutex taken in + lock_deadlock_check_and_resolve(). */ + + WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " TRX_ID_FMT " ABORT %d thd %p" + " current_thd %p BF %d wait_lock_modes: %s\n", + trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE), + wsrep_thd_is_BF(thd, FALSE), + trx->id, trx->abort_type, + trx->mysql_thd, + current_thd, + wsrep_thd_is_BF(current_thd, FALSE), + lock_get_info(trx->lock.wait_lock).c_str()); + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { ut_ad(!lock_mutex_own()); - ut_ad(!trx_mutex_own(trx)); lock_mutex_enter(); + } + + if (trx->abort_type != TRX_WSREP_ABORT) { trx_mutex_enter(trx); } ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(trx)); - /* We did dirty read above in case when abort is not - from wsrep. */ if (trx->lock.wait_lock) { lock_cancel_waiting_and_release(trx->lock.wait_lock); } - if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (trx->abort_type != TRX_WSREP_ABORT) { trx_mutex_exit(trx); + } + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { lock_mutex_exit(); } } @@ -17537,12 +17554,12 @@ wsrep_abort_transaction( if (victim_trx) { lock_mutex_enter(); trx_mutex_enter(victim_trx); - victim_trx->wsrep_abort = TRUE; + 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->wsrep_abort = FALSE; + victim_trx->abort_type = TRX_SERVER_ABORT; wsrep_srv_conc_cancel_wait(victim_trx); DBUG_RETURN(rcode); } else { diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index eb7ab5dce9d..f3bf4cfd0d9 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -991,6 +991,14 @@ void lock_cancel_waiting_and_release( /*============================*/ lock_t* lock); /*!< in/out: waiting lock request */ + +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t*); + #endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "lock0lock.ic" diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 6a58dcd25da..f434381543a 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -673,6 +673,12 @@ 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. */ +typedef enum { + TRX_SERVER_ABORT = 0, + TRX_WSREP_ABORT = 1, + TRX_REPLICATION_ABORT = 2 +} trx_abort_t; + struct trx_t{ ulint magic_n; @@ -848,8 +854,8 @@ struct trx_t{ /*------------------------------*/ THD* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ - ibool wsrep_abort; /*!< Transaction is aborted from - wsrep functions. */ + trx_abort_t abort_type; /*!< Transaction abort type*/ + const char* mysql_log_file_name; /*!< if MySQL binlog is used, this field contains a pointer to the latest file diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index b072aea2432..5543bbddd54 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -57,6 +57,10 @@ extern my_bool wsrep_debug; extern my_bool wsrep_log_conflicts; #include "ha_prototypes.h" #endif + +#include <string> +#include <sstream> + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -1729,10 +1733,10 @@ wsrep_kill_victim( } } - lock->trx->wsrep_abort = TRUE; + lock->trx->abort_type = TRX_WSREP_ABORT; wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); - lock->trx->wsrep_abort = FALSE; + lock->trx->abort_type = TRX_SERVER_ABORT; } } } @@ -4401,7 +4405,9 @@ lock_report_waiters_to_mysql( 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; thd_report_wait_for(mysql_thd, w_trx->mysql_thd); + w_trx->abort_type = TRX_SERVER_ABORT; } ++i; } @@ -7741,3 +7747,32 @@ lock_trx_has_rec_x_lock( return(true); } #endif /* UNIV_DEBUG */ + +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t* lock) +{ + std::string info; + std::string mode("mode "); + std::string index("index "); + std::string table("table "); + std::string n_uniq(" n_uniq"); + std::string n_user(" n_user"); + std::string lock_mode((lock_get_mode_str(lock))); + std::string iname(lock->index->name); + std::string tname(lock->index->table_name); + +#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() + + info = mode + lock_mode + + index + iname + + table + tname + + n_uniq + SSTR(lock->index->n_uniq) + + n_user + SSTR(lock->index->n_user_defined_cols); + + return info; +} diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 2f088f106fc..cea5286a1ab 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -5039,25 +5039,46 @@ innobase_kill_connection( trx = thd_to_trx(thd); - if (trx) { + if (trx && trx->lock.wait_lock) { /* In wsrep BF we have already took lock_sys and trx mutex either on wsrep_abort_transaction() or - before wsrep_kill_victim() */ - - if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + before wsrep_kill_victim(). In replication we + could own lock_sys mutex taken in + lock_deadlock_check_and_resolve().*/ + + WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " TRX_ID_FMT " ABORT %d thd %p" + " current_thd %p BF %d wait_lock_modes: %s\n", + trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE), + wsrep_thd_is_BF(thd, FALSE), + trx->id, trx->abort_type, + trx->mysql_thd, + current_thd, + wsrep_thd_is_BF(current_thd, FALSE), + lock_get_info(trx->lock.wait_lock).c_str()); + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { ut_ad(!lock_mutex_own()); - ut_ad(!trx_mutex_own(trx)); lock_mutex_enter(); + } + + if (trx->abort_type != TRX_WSREP_ABORT) { trx_mutex_enter(trx); } ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(trx)); - lock_cancel_waiting_and_release(trx->lock.wait_lock); + if (trx->lock.wait_lock) { + lock_cancel_waiting_and_release(trx->lock.wait_lock); + } - if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { + if (trx->abort_type != TRX_WSREP_ABORT) { trx_mutex_exit(trx); + } + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { lock_mutex_exit(); } } @@ -18699,12 +18720,12 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, if (victim_trx) { lock_mutex_enter(); trx_mutex_enter(victim_trx); - victim_trx->wsrep_abort = TRUE; + 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->wsrep_abort = FALSE; + victim_trx->abort_type = TRX_SERVER_ABORT; wsrep_srv_conc_cancel_wait(victim_trx); DBUG_RETURN(rcode); } else { diff --git a/storage/xtradb/include/lock0lock.h b/storage/xtradb/include/lock0lock.h index 1c07c055c23..ff22a27de27 100644 --- a/storage/xtradb/include/lock0lock.h +++ b/storage/xtradb/include/lock0lock.h @@ -39,6 +39,8 @@ Created 5/7/1996 Heikki Tuuri #include "srv0srv.h" #include "ut0vec.h" +#include <string> + #ifdef UNIV_DEBUG extern ibool lock_print_waits; #endif /* UNIV_DEBUG */ @@ -995,6 +997,13 @@ extern lock_sys_t* lock_sys; mutex_exit(&lock_sys->wait_mutex); \ } while (0) +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t*); + #ifndef UNIV_NONINL #include "lock0lock.ic" #endif diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index 76af1a938aa..d3b1b89e706 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -705,6 +705,12 @@ 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. */ +typedef enum { + TRX_SERVER_ABORT = 0, + TRX_WSREP_ABORT = 1, + TRX_REPLICATION_ABORT = 2 +} trx_abort_t; + struct trx_t{ ulint magic_n; @@ -881,8 +887,8 @@ struct trx_t{ /*------------------------------*/ THD* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ - ibool wsrep_abort; /*!< Transaction is aborted from - wsrep functions. */ + trx_abort_t abort_type; /*!< Transaction abort type */ + const char* mysql_log_file_name; /*!< if MySQL binlog is used, this field contains a pointer to the latest file diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index f73c6b504dd..93955331204 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -57,6 +57,10 @@ extern my_bool wsrep_debug; extern my_bool wsrep_log_conflicts; #include "ha_prototypes.h" #endif + +#include <string> +#include <sstream> + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -1728,10 +1732,10 @@ wsrep_kill_victim( } } - lock->trx->wsrep_abort = TRUE; + lock->trx->abort_type = TRX_WSREP_ABORT; wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); - lock->trx->wsrep_abort = FALSE; + lock->trx->abort_type = TRX_SERVER_ABORT; } } } @@ -4426,7 +4430,9 @@ lock_report_waiters_to_mysql( 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; thd_report_wait_for(mysql_thd, w_trx->mysql_thd); + w_trx->abort_type = TRX_SERVER_ABORT; } ++i; } @@ -7852,3 +7858,32 @@ lock_trx_has_rec_x_lock( return(true); } #endif /* UNIV_DEBUG */ + +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t* lock) +{ + std::string info; + std::string mode("mode "); + std::string index("index "); + std::string table("table "); + std::string n_uniq(" n_uniq"); + std::string n_user(" n_user"); + std::string lock_mode((lock_get_mode_str(lock))); + std::string iname(lock->index->name); + std::string tname(lock->index->table_name); + +#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() + + info = mode + lock_mode + + index + iname + + table + tname + + n_uniq + SSTR(lock->index->n_uniq) + + n_user + SSTR(lock->index->n_user_defined_cols); + + return info; +} |