diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2021-03-03 12:14:23 +0200 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2021-03-16 10:15:33 +0200 |
commit | 7cec3a9e9569a7f91344e02bf68d1250047a958a (patch) | |
tree | 8f1b1953662a1c7149259d14c7ac77d98e12db3b | |
parent | 1ea6ac3c953f847da033254d5df67f57987a1884 (diff) | |
download | mariadb-git-bb-10.4-MDEV-24923.tar.gz |
MDEV-24923 : Port selected Galera conflict resolution changes from 10.6bb-10.4-MDEV-24923
Add condition on trx->state == TRX_STATE_COMMITTED_IN_MEMORY in order to
avoid unnecessary work. If a transaction has already been committed or
rolled back, it will release its locks in lock_release() and let
the waiting thread(s) continue execution.
Let BF wait on lock_rec_has_to_wait and if necessary other BF
is replayed.
bg_wsrep_kill_trx
Make sure victim_trx is found and check also its state. If
state is TRX_STATE_COMMITTED_IN_MEMORY we can return.
wsrep_assert_no_bf_bf_wait
Check both bf trx and conflicting trx state and if one of them
is TRX_STATE_COMMITTED_IN_MEMORY we can let BF wait for locks
to be released.
lock_rec_has_to_wait
We very well can let bf to wait normally as other BF will be
replayed in case of conflict. For debug builds we will do
additional sanity checks to catch unsupported bf wait if any.
wsrep_kill_victim
Check is victim already in TRX_STATE_COMMITTED_IN_MEMORY state and
if it is we can return.
lock_rec_dequeue_from_page
lock_rec_unlock
Remove unnecessary wsrep_assert_no_bf_bf_wait function call.
We can very well let BF wait here.
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 3 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 15 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 98 |
3 files changed, 62 insertions, 54 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fd0b645f067..fe26ffa1b71 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -18627,7 +18627,8 @@ static void bg_wsrep_kill_trx(void *void_arg) lock_mutex_enter(); trx_mutex_enter(victim_trx); - if (victim_trx->id != arg->trx_id) + if (victim_trx->id != arg->trx_id || + victim_trx->state == TRX_STATE_COMMITTED_IN_MEMORY) { /* apparently victim trx was meanwhile rolled back. tell bf thd not to wait, in case it already started to */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index daffbacdfe6..c9aef273163 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1135,7 +1135,20 @@ public: ut_ad(dict_operation == TRX_DICT_OP_NONE); } - +#if defined(WITH_WSREP) && defined(UNIV_DEBUG) + inline const char* trx_state_str() + { + switch(state) + { + case TRX_STATE_NOT_STARTED : return "TRX_STATE_NOT_STARTED"; break; + case TRX_STATE_ACTIVE : return "TRX_STATE_ACTIVE"; break; + case TRX_STATE_PREPARED : return "TRX_STATE_PREPARED"; break; + case TRX_STATE_PREPARED_RECOVERED : return "TRX_STATE_PREPARED"; break; + case TRX_STATE_COMMITTED_IN_MEMORY : return "TRX_STATE_COMMITTED_IN_MEMORY"; break; + default: ut_error; return " "; break; // for compiler + } + } +#endif /* WITH_WSREP && UNIV_DEBUG */ private: /** Assign a rollback segment for modifying temporary tables. @return the assigned rollback segment */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index e1d9dea0dc5..4e9de00610a 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -637,6 +637,7 @@ lock_rec_get_insert_intention( return(lock->type_mode & LOCK_INSERT_INTENTION); } +#ifdef UNIV_DEBUG #ifdef WITH_WSREP /** Check if both conflicting lock and other record lock are brute force (BF). This case is a bug so report lock information and wsrep state. @@ -647,7 +648,7 @@ lock_rec_get_insert_intention( static void wsrep_assert_no_bf_bf_wait( const lock_t* lock_rec1, const lock_t* lock_rec2, - const trx_t* trx1) + trx_t* trx1) { ut_ad(!lock_rec1 || lock_get_type_low(lock_rec1) == LOCK_REC); ut_ad(lock_get_type_low(lock_rec2) == LOCK_REC); @@ -664,6 +665,22 @@ static void wsrep_assert_no_bf_bf_wait( if (UNIV_LIKELY(!wsrep_thd_is_BF(lock_rec2->trx->mysql_thd, FALSE))) return; + ut_ad(!trx_mutex_own(trx1)); + ut_ad(!trx_mutex_own(lock_rec2->trx)); + trx_mutex_enter(trx1); + trx_mutex_enter(lock_rec2->trx); + + + /* If transaction is already committed in memory we can wait */ + if (trx_state_eq(trx1, TRX_STATE_COMMITTED_IN_MEMORY) || + trx_state_eq(lock_rec2->trx, TRX_STATE_COMMITTED_IN_MEMORY)) { + trx_mutex_exit(trx1); + trx_mutex_exit(lock_rec2->trx); + return; + } + trx_mutex_exit(trx1); + trx_mutex_exit(lock_rec2->trx); + /* if BF - BF order is honored, we can keep trx1 waiting for the lock */ if (wsrep_thd_order_before(trx1->mysql_thd, lock_rec2->trx->mysql_thd)) return; @@ -671,13 +688,14 @@ static void wsrep_assert_no_bf_bf_wait( /* avoiding BF-BF conflict assert, if victim is already aborting or rolling back for replaying */ - wsrep_thd_LOCK(lock_rec2->trx->mysql_thd); if (wsrep_thd_is_aborting(lock_rec2->trx->mysql_thd)) { - wsrep_thd_UNLOCK(lock_rec2->trx->mysql_thd); return; } - wsrep_thd_UNLOCK(lock_rec2->trx->mysql_thd); + WSREP_INFO("Trx state trx_id: " TRX_ID_FMT " state: %s" + " trx_id2: " TRX_ID_FMT " state: %s", + trx1->id, trx1->trx_state_str(), + lock_rec2->trx->id, lock_rec2->trx->trx_state_str()); mtr_t mtr; if (lock_rec1) { @@ -706,6 +724,7 @@ static void wsrep_assert_no_bf_bf_wait( ut_error; } #endif /* WITH_WSREP */ +#endif /* UNIV_DEBUG */ /*********************************************************************//** Checks if a lock request for a new lock has to wait for request lock2. @@ -828,9 +847,13 @@ lock_rec_has_to_wait( return false; } - /* There should not be two conflicting locks that are - brute force. If there is it is a bug. */ - wsrep_assert_no_bf_bf_wait(NULL, lock2, trx); +#ifdef UNIV_DEBUG + /* We very well can let bf to wait normally as other + BF will be replayed in case of conflict. For debug + builds we will do additional sanity checks to catch + unsupported bf wait if any. */ + wsrep_assert_no_bf_bf_wait(NULL, lock2, const_cast<trx_t*>(trx)); +#endif #endif /* WITH_WSREP */ return true; @@ -1108,56 +1131,35 @@ wsrep_kill_victim( { ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(lock->trx)); - - /* quit for native mysql */ - if (!trx->is_wsrep()) return; + ut_ad(trx->is_wsrep()); + ut_ad(lock->trx != trx); if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { return; } - my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, FALSE); - mtr_t mtr; + trx_t* lock_trx = lock->trx; + + if (lock_trx->state == TRX_STATE_COMMITTED_IN_MEMORY + || lock_trx->lock.was_chosen_as_deadlock_victim) { + return; + } + + my_bool bf_other = wsrep_thd_is_BF(lock_trx->mysql_thd, FALSE); if ((!bf_other) || - (wsrep_thd_order_before( - trx->mysql_thd, lock->trx->mysql_thd))) { + (wsrep_thd_order_before( + trx->mysql_thd, lock_trx->mysql_thd))) { - if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) { + if (lock_trx->lock.que_state == TRX_QUE_LOCK_WAIT) { if (UNIV_UNLIKELY(wsrep_debug)) { - ib::info() << "WSREP: BF victim waiting\n"; + WSREP_INFO("BF victim waiting"); } /* cannot release lock, until our lock is in the queue*/ - } else if (lock->trx != trx) { - if (wsrep_log_conflicts) { - ib::info() << "*** Priority TRANSACTION:"; - - trx_print_latched(stderr, trx, 3000); - - if (bf_other) { - ib::info() << "*** Priority TRANSACTION:"; - } else { - ib::info() << "*** Victim TRANSACTION:"; - } - trx_print_latched(stderr, lock->trx, 3000); - - ib::info() << "*** WAITING FOR THIS LOCK TO BE GRANTED:"; - - if (lock_get_type(lock) == LOCK_REC) { - lock_rec_print(stderr, lock, mtr); - } else { - lock_table_print(stderr, lock); - } - - ib::info() << " SQL1: " - << wsrep_thd_query(trx->mysql_thd); - ib::info() << " SQL2: " - << wsrep_thd_query(lock->trx->mysql_thd); - } - + } else { wsrep_innobase_kill_one_trx(trx->mysql_thd, - lock->trx, true); + lock_trx, true); } } } @@ -2251,10 +2253,6 @@ static void lock_rec_dequeue_from_page(lock_t* in_lock) /* Grant the lock */ ut_ad(lock->trx != in_lock->trx); lock_grant(lock); -#ifdef WITH_WSREP - } else { - wsrep_assert_no_bf_bf_wait(c, lock, c->trx); -#endif /* WITH_WSREP */ } } } else { @@ -4207,10 +4205,6 @@ released: /* Grant the lock */ ut_ad(trx != lock->trx); lock_grant(lock); -#ifdef WITH_WSREP - } else { - wsrep_assert_no_bf_bf_wait(c, lock, c->trx); -#endif /* WITH_WSREP */ } } } else { |